Implement comment constitution
fix bugs
This commit is contained in:
@@ -12,11 +12,7 @@ import fr.dcproject.entity.Citizen
|
||||
import fr.dcproject.entity.Constitution
|
||||
import fr.dcproject.entity.User
|
||||
import fr.dcproject.routes.*
|
||||
import fr.dcproject.security.voter.ArticleVoter
|
||||
import fr.dcproject.security.voter.AuthorizationVoter
|
||||
import fr.dcproject.security.voter.CitizenVoter
|
||||
import fr.dcproject.security.voter.CommentVoter
|
||||
import fr.postgresjson.migration.Migrations
|
||||
import fr.dcproject.security.voter.*
|
||||
import io.ktor.application.Application
|
||||
import io.ktor.application.ApplicationCall
|
||||
import io.ktor.application.call
|
||||
@@ -40,7 +36,6 @@ import java.util.*
|
||||
import java.util.concurrent.CompletionException
|
||||
import fr.dcproject.repository.Article as RepositoryArticle
|
||||
import fr.dcproject.repository.Citizen as RepositoryCitizen
|
||||
import fr.dcproject.repository.CommentGeneric as CommentGenericRepository
|
||||
import fr.dcproject.repository.Constitution as RepositoryConstitution
|
||||
import fr.dcproject.repository.User as UserRepository
|
||||
|
||||
@@ -92,14 +87,6 @@ fun Application.module() {
|
||||
}
|
||||
}
|
||||
|
||||
convert<CommentEntityGeneric> {
|
||||
decode { values, _ ->
|
||||
val id = values.singleOrNull()?.let { UUID.fromString(it) }
|
||||
?: throw InternalError("Cannot convert $values to UUID")
|
||||
get<CommentGenericRepository>().findById(id) ?: throw InternalError("Comment $values not found")
|
||||
}
|
||||
}
|
||||
|
||||
convert<Citizen> {
|
||||
decode { values, _ ->
|
||||
val id = values.singleOrNull()?.let { UUID.fromString(it) }
|
||||
@@ -115,6 +102,7 @@ fun Application.module() {
|
||||
install(AuthorizationVoter) {
|
||||
voters = mutableListOf(
|
||||
ArticleVoter(),
|
||||
ConstitutionVoter(),
|
||||
CitizenVoter(),
|
||||
CommentVoter()
|
||||
)
|
||||
@@ -166,6 +154,7 @@ fun Application.module() {
|
||||
followConstitution(get())
|
||||
comment(get())
|
||||
commentArticle(get())
|
||||
commentConstitution(get())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.koin.dsl.module
|
||||
import fr.dcproject.repository.Article as ArticleRepository
|
||||
import fr.dcproject.repository.Citizen as CitizenRepository
|
||||
import fr.dcproject.repository.CommentArticle as CommentArticleRepository
|
||||
import fr.dcproject.repository.CommentConstitution as CommentConstitutionRepository
|
||||
import fr.dcproject.repository.CommentGeneric as CommentGenericRepository
|
||||
import fr.dcproject.repository.Constitution as ConstitutionRepository
|
||||
import fr.dcproject.repository.FollowArticle as FollowArticleRepository
|
||||
@@ -37,8 +38,7 @@ val Module = module {
|
||||
single { FollowConstitutionRepository(get()) }
|
||||
single { CommentGenericRepository(get()) }
|
||||
single { CommentArticleRepository(get()) }
|
||||
// TODO implment constitution
|
||||
// single { CommentConstitutionRepository(get()) }
|
||||
single { CommentConstitutionRepository(get()) }
|
||||
|
||||
single { Migrations(connection = get(), directory = config.sqlFiles) }
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ class Constitution(
|
||||
id: UUID = UUID.randomUUID(),
|
||||
var title: String?,
|
||||
var annonymous: Boolean?,
|
||||
var titles: List<Title>,
|
||||
var titles: List<Title> = listOf(),
|
||||
createdBy: Citizen?
|
||||
): UuidEntity(id),
|
||||
EntityVersioning<UUID, Int> by UuidEntityVersioning(),
|
||||
|
||||
@@ -14,11 +14,7 @@ import fr.dcproject.entity.Constitution as ConstitutionEntity
|
||||
abstract class Comment <T: UuidEntity>(override var requester: Requester): RepositoryI<CommentEntity<T>> {
|
||||
override val entityName = CommentEntity::class as KClass<CommentEntity<T>>
|
||||
|
||||
open fun findById(id: UUID): CommentEntity<ArticleEntity>? {
|
||||
return requester
|
||||
.getFunction("find_comment_by_id")
|
||||
.selectOne(mapOf("id" to id))
|
||||
}
|
||||
abstract fun findById(id: UUID): CommentEntity<T>?
|
||||
|
||||
abstract fun findByCitizen(
|
||||
citizen: CitizenEntity,
|
||||
@@ -81,23 +77,29 @@ abstract class Comment <T: UuidEntity>(override var requester: Requester): Repos
|
||||
}
|
||||
|
||||
fun edit(comment: CommentEntity<T>) {
|
||||
val reference = comment.target::class.simpleName!!.toLowerCase()
|
||||
requester
|
||||
.getFunction("edit_comment")
|
||||
.sendQuery(
|
||||
"reference" to reference,
|
||||
"id" to comment.id,
|
||||
"content" to comment.content
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class CommentGeneric (requester: Requester): Comment<UuidEntity>(requester) {
|
||||
class GenericTargetEntity(id: UUID = UUID.randomUUID()): UuidEntity(id)
|
||||
|
||||
class CommentGeneric (requester: Requester): Comment<GenericTargetEntity>(requester) {
|
||||
override fun findById(id: UUID): CommentEntity<GenericTargetEntity>? {
|
||||
return requester
|
||||
.getFunction("find_comment_by_id")
|
||||
.selectOne(mapOf("id" to id))
|
||||
}
|
||||
|
||||
override fun findByCitizen(
|
||||
citizen: CitizenEntity,
|
||||
page: Int,
|
||||
limit: Int
|
||||
): Paginated<CommentEntity<UuidEntity>> {
|
||||
): Paginated<CommentEntity<GenericTargetEntity>> {
|
||||
return requester.run {
|
||||
getFunction("find_comments_by_citizen")
|
||||
.select(page, limit,
|
||||
@@ -108,6 +110,12 @@ class CommentGeneric (requester: Requester): Comment<UuidEntity>(requester) {
|
||||
}
|
||||
|
||||
class CommentArticle (requester: Requester): Comment<ArticleEntity>(requester) {
|
||||
override fun findById(id: UUID): CommentEntity<ArticleEntity>? {
|
||||
return requester
|
||||
.getFunction("find_comment_by_id")
|
||||
.selectOne(mapOf("id" to id))
|
||||
}
|
||||
|
||||
override fun findByCitizen(
|
||||
citizen: CitizenEntity,
|
||||
page: Int,
|
||||
@@ -125,6 +133,12 @@ class CommentArticle (requester: Requester): Comment<ArticleEntity>(requester) {
|
||||
}
|
||||
|
||||
class CommentConstitution (requester: Requester): Comment<ConstitutionEntity>(requester) {
|
||||
override fun findById(id: UUID): CommentEntity<ConstitutionEntity>? {
|
||||
return requester
|
||||
.getFunction("find_comment_by_id")
|
||||
.selectOne(mapOf("id" to id))
|
||||
}
|
||||
|
||||
override fun findByCitizen(
|
||||
citizen: CitizenEntity,
|
||||
page: Int,
|
||||
|
||||
@@ -33,9 +33,9 @@ class Constitution(override var requester: Requester) : RepositoryI<Constitution
|
||||
)
|
||||
}
|
||||
|
||||
fun upsert(article: ConstitutionEntity): ConstitutionEntity? {
|
||||
fun upsert(constitution: ConstitutionEntity): ConstitutionEntity? {
|
||||
return requester
|
||||
.getFunction("upsert_constitution")
|
||||
.selectOne("resource" to article)
|
||||
.selectOne("resource" to constitution)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package fr.dcproject.routes
|
||||
import fr.dcproject.security.voter.CommentVoter.Action.UPDATE
|
||||
import fr.dcproject.security.voter.CommentVoter.Action.VIEW
|
||||
import fr.dcproject.security.voter.assertCan
|
||||
import fr.postgresjson.entity.UuidEntity
|
||||
import io.ktor.application.call
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||
@@ -14,10 +13,8 @@ import io.ktor.request.receiveText
|
||||
import io.ktor.response.respond
|
||||
import io.ktor.routing.Route
|
||||
import java.util.*
|
||||
import fr.dcproject.entity.Comment as CommentEntity
|
||||
import fr.dcproject.repository.CommentGeneric as CommentRepository
|
||||
|
||||
typealias CommentEntityGeneric = CommentEntity<UuidEntity>
|
||||
@KtorExperimentalLocationsAPI
|
||||
object CommentPaths {
|
||||
// TODO: change UUID by entity converter
|
||||
@@ -38,7 +35,7 @@ fun Route.comment(repo: CommentRepository) {
|
||||
assertCan(UPDATE,comment)
|
||||
|
||||
comment.content = call.receiveText()
|
||||
repo.edit(comment as CommentEntity<UuidEntity>)
|
||||
repo.edit(comment)
|
||||
|
||||
call.respond(HttpStatusCode.OK, comment)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||
import io.ktor.locations.Location
|
||||
import io.ktor.locations.get
|
||||
import io.ktor.locations.post
|
||||
import io.ktor.request.receive
|
||||
import io.ktor.request.receiveText
|
||||
import io.ktor.response.respond
|
||||
import io.ktor.routing.Route
|
||||
import fr.dcproject.entity.Article as ArticleEntity
|
||||
@@ -37,7 +37,7 @@ fun Route.commentArticle(repo: CommentArticleRepository) {
|
||||
post<CommentArticlePaths.ArticleCommentRequest> {
|
||||
assertCan(CREATE, it.article)
|
||||
|
||||
val content = call.receive<String>()
|
||||
val content = call.receiveText()
|
||||
val comment = CommentEntity(
|
||||
target = it.article,
|
||||
createdBy = citizen,
|
||||
|
||||
55
src/main/kotlin/fr/dcproject/routes/CommentConstitution.kt
Normal file
55
src/main/kotlin/fr/dcproject/routes/CommentConstitution.kt
Normal file
@@ -0,0 +1,55 @@
|
||||
package fr.dcproject.routes
|
||||
|
||||
import fr.dcproject.citizen
|
||||
import fr.dcproject.entity.Citizen
|
||||
import fr.dcproject.security.voter.CommentVoter.Action.CREATE
|
||||
import fr.dcproject.security.voter.CommentVoter.Action.VIEW
|
||||
import fr.dcproject.security.voter.assertCan
|
||||
import io.ktor.application.call
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||
import io.ktor.locations.Location
|
||||
import io.ktor.locations.get
|
||||
import io.ktor.locations.post
|
||||
import io.ktor.request.receiveText
|
||||
import io.ktor.response.respond
|
||||
import io.ktor.routing.Route
|
||||
import fr.dcproject.entity.Comment as CommentEntity
|
||||
import fr.dcproject.entity.Constitution as ConstitutionEntity
|
||||
import fr.dcproject.repository.CommentConstitution as CommentConstitutionRepository
|
||||
|
||||
@KtorExperimentalLocationsAPI
|
||||
object CommentConstitutionPaths {
|
||||
@Location("/constitutions/{constitution}/comments") class ConstitutionCommentRequest(val constitution: ConstitutionEntity)
|
||||
@Location("/citizens/{citizen}/comments/constitutions") class CitizenCommentConstitutionRequest(val citizen: Citizen)
|
||||
}
|
||||
|
||||
@KtorExperimentalLocationsAPI
|
||||
fun Route.commentConstitution(repo: CommentConstitutionRepository) {
|
||||
get<CommentConstitutionPaths.ConstitutionCommentRequest> {
|
||||
assertCan(VIEW, it.constitution)
|
||||
|
||||
val comment = repo.findByTarget(it.constitution)
|
||||
|
||||
call.respond(HttpStatusCode.OK, comment)
|
||||
}
|
||||
|
||||
post<CommentConstitutionPaths.ConstitutionCommentRequest> {
|
||||
assertCan(CREATE, it.constitution)
|
||||
|
||||
val content = call.receiveText()
|
||||
val comment = CommentEntity(
|
||||
target = it.constitution,
|
||||
createdBy = citizen,
|
||||
content = content
|
||||
)
|
||||
repo.comment(comment)
|
||||
|
||||
call.respond(HttpStatusCode.Created, comment)
|
||||
}
|
||||
|
||||
get<CommentConstitutionPaths.CitizenCommentConstitutionRequest> {
|
||||
val comments = repo.findByCitizen(it.citizen)
|
||||
call.respond(comments)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package fr.dcproject.security.voter
|
||||
|
||||
import fr.dcproject.entity.Constitution
|
||||
import fr.dcproject.entity.User
|
||||
import io.ktor.application.ApplicationCall
|
||||
|
||||
class ConstitutionVoter: Voter {
|
||||
enum class Action: ActionI {
|
||||
CREATE,
|
||||
UPDATE,
|
||||
VIEW,
|
||||
DELETE
|
||||
}
|
||||
|
||||
override fun supports(action: ActionI, call: ApplicationCall, subject: Any?): Boolean {
|
||||
return (action is Action || action is CommentVoter.Action) && subject is Constitution?
|
||||
}
|
||||
|
||||
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
||||
val user = call.user
|
||||
if (action == Action.CREATE && user != null) {
|
||||
return Vote.GRANTED
|
||||
}
|
||||
|
||||
if (action == Action.VIEW) {
|
||||
return Vote.GRANTED
|
||||
}
|
||||
|
||||
if (action == CommentVoter.Action.CREATE) {
|
||||
return Vote.GRANTED
|
||||
}
|
||||
|
||||
if (action == CommentVoter.Action.VIEW) {
|
||||
return Vote.GRANTED
|
||||
}
|
||||
|
||||
if (action == Action.DELETE && user is User && subject is Constitution && subject.createdBy?.userId == user.id) {
|
||||
return Vote.GRANTED
|
||||
}
|
||||
|
||||
if (action == Action.UPDATE && user is User && subject is Constitution && subject.createdBy?.userId == user.id) {
|
||||
return Vote.GRANTED
|
||||
}
|
||||
|
||||
return Vote.ABSTAIN
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,21 @@ create or replace function upsert_article(inout resource json)
|
||||
$$
|
||||
declare
|
||||
new_id uuid;
|
||||
_id_exist boolean;
|
||||
begin
|
||||
insert into article (version_id, created_by_id, title, annonymous, content, description, tags)
|
||||
-- check if version id already exist
|
||||
select count(*) >= 1
|
||||
into _id_exist
|
||||
from article
|
||||
where (resource->>'id')::uuid is not null
|
||||
and id = (resource->>'id')::uuid
|
||||
-- and draft = false
|
||||
;
|
||||
|
||||
insert into article (id, version_id, created_by_id, title, annonymous, content, description, tags)
|
||||
select
|
||||
case when _id_exist then uuid_generate_v4()
|
||||
else coalesce(id, uuid_generate_v4()) end,
|
||||
coalesce(version_id, uuid_generate_v4()),
|
||||
(resource#>>'{created_by, id}')::uuid,
|
||||
title,
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
create or replace function edit_comment(reference regclass, _id uuid, _content text) returns void
|
||||
create or replace function edit_comment(_id uuid, _content text) returns void
|
||||
language plpgsql as
|
||||
$$
|
||||
begin
|
||||
if reference = 'article'::regclass then
|
||||
update comment_on_article c set
|
||||
update comment c set
|
||||
"content" = _content
|
||||
where c.id = _id;
|
||||
elseif reference = 'constitution'::regclass then
|
||||
update comment_on_constitution c set
|
||||
"content" = _content
|
||||
where c.id = _id;
|
||||
end if;
|
||||
end;
|
||||
$$;
|
||||
|
||||
-- drop function if exists edit_comment(regclass, uuid, text);
|
||||
|
||||
-- select edit_comment('b0422e48-687f-bea7-b45f-b6b301246e97', 'plop4')
|
||||
@@ -1,27 +0,0 @@
|
||||
create or replace function find_comments_article_by_citizen(
|
||||
_created_by_id uuid,
|
||||
"limit" int default 50,
|
||||
"offset" int default 0,
|
||||
out resource json,
|
||||
out total int
|
||||
) language plpgsql as
|
||||
$$
|
||||
begin
|
||||
select json_agg(t), (select count(id) from comment where target_reference = 'article'::regclass)
|
||||
into resource, total
|
||||
from (
|
||||
select
|
||||
com.*,
|
||||
find_article_by_id(com.target_id) as target,
|
||||
find_citizen_by_id(com.created_by_id) as created_by
|
||||
from comment as com
|
||||
where created_by_id = _created_by_id
|
||||
and target_reference = 'article'::regclass
|
||||
order by created_at desc,
|
||||
com.created_at desc
|
||||
limit "limit" offset "offset"
|
||||
) as t;
|
||||
end;
|
||||
$$;
|
||||
|
||||
-- drop function if exists find_comments_article_by_citizen(uuid, int, int);
|
||||
@@ -6,9 +6,23 @@ declare
|
||||
_title json;
|
||||
_citizen_id uuid = (resource#>>'{created_by, id}')::uuid;
|
||||
new_id uuid;
|
||||
_id_exist boolean;
|
||||
begin
|
||||
insert into constitution (version_id, created_by_id, title, annonymous)
|
||||
-- check if version id already exist
|
||||
select count(*) >= 1
|
||||
into _id_exist
|
||||
from constitution
|
||||
where (resource->>'id')::uuid is not null
|
||||
and id = (resource->>'id')::uuid
|
||||
-- and draft = false
|
||||
;
|
||||
|
||||
raise notice '%', _id_exist;
|
||||
|
||||
insert into constitution (id, version_id, created_by_id, title, annonymous)
|
||||
select
|
||||
case when _id_exist then uuid_generate_v4()
|
||||
else coalesce(id, uuid_generate_v4()) end,
|
||||
version_id,
|
||||
_citizen_id,
|
||||
title,
|
||||
|
||||
@@ -10,7 +10,7 @@ begin
|
||||
when 'article'::regclass then
|
||||
find_article_by_id(_id)
|
||||
when 'constitution'::regclass then
|
||||
find_article_by_id(_id)
|
||||
find_constitution_by_id(_id)
|
||||
else
|
||||
json_build_object('id', _id)
|
||||
end
|
||||
@@ -19,3 +19,5 @@ end;
|
||||
$$;
|
||||
|
||||
-- drop function if exists find_reference_by_id(uuid, regclass, out json);
|
||||
|
||||
-- select find_reference_by_id('8944221c-3766-f952-7064-9f229c288049'::uuid, 'constitution'::regclass)
|
||||
62
src/test/kotlin/feature/ConstitutionSteps.kt
Normal file
62
src/test/kotlin/feature/ConstitutionSteps.kt
Normal file
@@ -0,0 +1,62 @@
|
||||
package feature
|
||||
|
||||
import fr.dcproject.entity.Citizen
|
||||
import io.cucumber.java8.En
|
||||
import org.joda.time.DateTime
|
||||
import org.koin.test.KoinTest
|
||||
import org.koin.test.get
|
||||
import java.util.*
|
||||
import java.util.concurrent.CompletionException
|
||||
import fr.dcproject.entity.Constitution as ConstitutionEntity
|
||||
import fr.dcproject.entity.Constitution.Title as TitleEntity
|
||||
import fr.dcproject.entity.User as UserEntity
|
||||
import fr.dcproject.repository.Citizen as CitizenRepository
|
||||
import fr.dcproject.repository.Constitution as ConstitutionRepository
|
||||
|
||||
class ConstitutionSteps: En, KoinTest {
|
||||
init {
|
||||
Given("I have constitution with id {string}") { id: String ->
|
||||
var citizen = Citizen(
|
||||
name = Citizen.Name("John", "Doe"),
|
||||
birthday = DateTime.now(),
|
||||
user = UserEntity(username = "john-doe", plainPassword = "azerty")
|
||||
)
|
||||
|
||||
try {
|
||||
get<CitizenRepository>().insertWithUser(citizen)
|
||||
} catch (e: CompletionException) {
|
||||
citizen = get<CitizenRepository>().findByUsername("john-doe")!!
|
||||
}
|
||||
|
||||
val title1 = TitleEntity(
|
||||
name = "My Title"
|
||||
)
|
||||
|
||||
val constitution = ConstitutionEntity(
|
||||
id = UUID.fromString(id),
|
||||
title = "hello",
|
||||
titles = listOf(title1),
|
||||
createdBy = citizen,
|
||||
annonymous = false
|
||||
)
|
||||
get<ConstitutionRepository>().upsert(constitution)
|
||||
}
|
||||
|
||||
Given("I have constitution with id {string} created by {string}") { id: String, username: String ->
|
||||
val citizen = get<CitizenRepository>().findByUsername(username)!!
|
||||
|
||||
val title1 = TitleEntity(
|
||||
name = "My Title"
|
||||
)
|
||||
|
||||
val constitution = ConstitutionEntity(
|
||||
id = UUID.fromString(id),
|
||||
title = "hello",
|
||||
titles = listOf(title1),
|
||||
createdBy = citizen,
|
||||
annonymous = false
|
||||
)
|
||||
get<ConstitutionRepository>().upsert(constitution)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
Feature: comment Article and Constitution
|
||||
Feature: comment Article
|
||||
|
||||
# Article
|
||||
Scenario: The route for comment article must response a 201 and return object
|
||||
Given I am authenticated as John Doe with id "64b7b379-2298-43ec-b428-ba134930cabd"
|
||||
And I have article with id "9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b"
|
||||
@@ -34,7 +33,3 @@ Feature: comment Article and Constitution
|
||||
Then the response status code should be 200
|
||||
And the JSON should contain:
|
||||
| content | Hello boy |
|
||||
|
||||
|
||||
# Constitution
|
||||
# TODO
|
||||
35
src/test/resources/feature/commentConstitution.feature
Normal file
35
src/test/resources/feature/commentConstitution.feature
Normal file
@@ -0,0 +1,35 @@
|
||||
Feature: comment Constitution
|
||||
|
||||
Scenario: The route for comment constitution must response a 201 and return object
|
||||
Given I am authenticated as John Doe with id "64b7b379-2298-43ec-b428-ba134930cabd"
|
||||
And I have constitution with id "9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b"
|
||||
When I send a POST request to "/constitutions/9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b/comments" with body:
|
||||
"""
|
||||
Hello mister
|
||||
"""
|
||||
Then the response status code should be 201
|
||||
|
||||
Scenario: The route for get comments of constitutions for the current citizen must response a 200 and return objects
|
||||
Given I have citizen John Doe with id "64b7b379-2298-43ec-b428-ba134930cabd"
|
||||
And I have constitution with id "9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b"
|
||||
When I send a GET request to "/citizens/64b7b379-2298-43ec-b428-ba134930cabd/comments/constitutions"
|
||||
Then the response status code should be 200
|
||||
And the response should contain object:
|
||||
| current_page | 1 |
|
||||
| limit | 50 |
|
||||
|
||||
Scenario: The route for edit comment must response a 200 and return object
|
||||
Given I am authenticated as username 3 with id "92877af7-0a45-fd6a-2ed7-fe81e1236b78"
|
||||
When I send a PUT request to "/comments/b0422e48-687f-bea7-b45f-b6b301246e97" with body:
|
||||
"""
|
||||
Hello boy
|
||||
"""
|
||||
Then the response status code should be 200
|
||||
And the JSON should contain:
|
||||
| content | Hello boy |
|
||||
|
||||
Scenario: The route for get comment must response a 200 and return object
|
||||
When I send a GET request to "/comments/b0422e48-687f-bea7-b45f-b6b301246e97"
|
||||
Then the response status code should be 200
|
||||
And the JSON should contain:
|
||||
| content | Hello boy |
|
||||
Reference in New Issue
Block a user