From a17bd11e9e413995ac2c82bb47764927037c1c17 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Fri, 19 Feb 2021 23:30:04 +0100 Subject: [PATCH] Add Integration test for follow article routes --- .../integration/Follow articles routes.kt | 88 +++++++++++++++++++ .../kotlin/integration/steps/given/Citizen.kt | 5 +- .../kotlin/integration/steps/given/Follow.kt | 57 ++++++++++++ .../kotlin/integration/steps/given/Request.kt | 5 ++ .../kotlin/integration/steps/when/request.kt | 19 +++- .../resources/feature/constitution.feature | 1 + .../resources/feature/followArticle.feature | 1 + 7 files changed, 170 insertions(+), 6 deletions(-) create mode 100644 src/test/kotlin/integration/Follow articles routes.kt create mode 100644 src/test/kotlin/integration/steps/given/Follow.kt create mode 100644 src/test/kotlin/integration/steps/given/Request.kt diff --git a/src/test/kotlin/integration/Follow articles routes.kt b/src/test/kotlin/integration/Follow articles routes.kt new file mode 100644 index 0000000..2036bda --- /dev/null +++ b/src/test/kotlin/integration/Follow articles routes.kt @@ -0,0 +1,88 @@ +package integration + +import integration.steps.`And the response should be null` +import integration.steps.`And the response should contain` +import integration.steps.`And the response should not be null` +import integration.steps.`Then the response should be` +import integration.steps.`when`.`When I send a DELETE request` +import integration.steps.`when`.`When I send a GET request` +import integration.steps.`when`.`When I send a POST request` +import integration.steps.and +import integration.steps.given.`And follow article` +import integration.steps.given.`Given I have article` +import integration.steps.given.`Given I have citizen` +import integration.steps.given.`authenticated as` +import integration.steps.given.`with no content` +import io.ktor.http.HttpStatusCode.Companion.Created +import io.ktor.http.HttpStatusCode.Companion.NoContent +import io.ktor.http.HttpStatusCode.Companion.OK +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Tags +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@Tags(Tag("integration"), Tag("article"), Tag("follow")) +class `Follow articles routes` : BaseTest() { + @Test + fun `I can follow article`() { + withIntegrationApplication { + `Given I have citizen`("Louis", "Pasteur") + `Given I have article`(id = "04754b7b-edef-4adc-af81-75e3aadeebea") + `When I send a POST request`("/articles/04754b7b-edef-4adc-af81-75e3aadeebea/follows") { + `authenticated as`("Louis", "Pasteur") + `with no content`() + } `Then the response should be` Created + } + } + + @Test + fun `I can get follow article`() { + withIntegrationApplication { + `Given I have article`(id = "d743619a-1f6b-4d20-a2d6-8e81f0e6a4c8") + `Given I have citizen`("Johannes", "Kepler", id = "e4592d53-3660-4264-8353-ebdbf5d9c41c") { + `And follow article`("d743619a-1f6b-4d20-a2d6-8e81f0e6a4c8") + } + `When I send a GET request`("/citizens/e4592d53-3660-4264-8353-ebdbf5d9c41c/follows/articles") { + `authenticated as`("Johannes", "Kepler") + } `Then the response should be` OK and { + `And the response should not be null`() + `And the response should contain`("$.current_page", 1) + `And the response should contain`("$.limit", 50) + } + } + } + + @Test + fun `I can unfollow article`() { + withIntegrationApplication { + `Given I have article`(id = "aad3aa9d-95fd-4919-9e84-46255f620e31") + `Given I have citizen`("Thomas", "Edison") { + `And follow article`("aad3aa9d-95fd-4919-9e84-46255f620e31") + } + `When I send a DELETE request`("/articles/aad3aa9d-95fd-4919-9e84-46255f620e31/follows") { + `authenticated as`("Thomas", "Edison") + `with no content`() + } `Then the response should be` NoContent and { + `And the response should be null`() + } + } + } + + @Test + fun `I can know if I follow an article`() { + withIntegrationApplication { + `Given I have article`(id = "3ee4e6d0-f312-4940-872d-1f578c8d824c") + `Given I have citizen`("Marie", "Curie") { + `And follow article`("3ee4e6d0-f312-4940-872d-1f578c8d824c") + } + `When I send a GET request`("/articles/3ee4e6d0-f312-4940-872d-1f578c8d824c/follows") { + `authenticated as`("Marie", "Curie") + `with no content`() + } `Then the response should be` OK and { + `And the response should not be null`() + `And the response should contain`("$.target.id", "3ee4e6d0-f312-4940-872d-1f578c8d824c") + } + } + } +} diff --git a/src/test/kotlin/integration/steps/given/Citizen.kt b/src/test/kotlin/integration/steps/given/Citizen.kt index 73756bd..b7b96a6 100644 --- a/src/test/kotlin/integration/steps/given/Citizen.kt +++ b/src/test/kotlin/integration/steps/given/Citizen.kt @@ -15,7 +15,8 @@ fun TestApplicationEngine.`Given I have citizen`( firstName: String, lastName: String, email: String = ("$firstName-$lastName".toLowerCase()) + "@dc-project.fr", - id: String = UUID.randomUUID().toString() + id: String = UUID.randomUUID().toString(), + callback: Citizen.() -> Unit = {} ): Citizen? { val repo: CitizenRepository by lazy { GlobalContext.get().koin.get() } @@ -32,7 +33,7 @@ fun TestApplicationEngine.`Given I have citizen`( user = user ) - return repo.insertWithUser(citizen) + return repo.insertWithUser(citizen)?.also { callback(it) } } fun createCitizen(createdByUsername: String? = null): Citizen { diff --git a/src/test/kotlin/integration/steps/given/Follow.kt b/src/test/kotlin/integration/steps/given/Follow.kt new file mode 100644 index 0000000..46b7c3a --- /dev/null +++ b/src/test/kotlin/integration/steps/given/Follow.kt @@ -0,0 +1,57 @@ +package integration.steps.given + +import fr.dcproject.common.utils.toUUID +import fr.dcproject.component.article.ArticleRef +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.component.citizen.CitizenRepository +import fr.dcproject.component.constitution.ConstitutionRef +import fr.dcproject.component.follow.FollowArticleRepository +import fr.dcproject.component.follow.FollowConstitutionRepository +import fr.dcproject.component.follow.FollowForUpdate +import io.ktor.server.testing.TestApplicationEngine +import org.koin.core.context.GlobalContext + +fun Citizen.`And follow article`( + article: String, +) { + createFollow(this, ArticleRef(article.toUUID())) +} + +fun Citizen.`And follow constitution`( + constitution: String, +) { + createFollow(this, ConstitutionRef(constitution.toUUID())) +} + +fun TestApplicationEngine.`Given I have follow on article`( + firstName: String, + lastName: String, + article: String, +) { + val citizenRepository: CitizenRepository by lazy { GlobalContext.get().koin.get() } + val citizen = citizenRepository.findByUsername("$firstName-$lastName".toLowerCase()) ?: error("Citizen not exist") + createFollow(citizen, ArticleRef(article.toUUID())) +} + +fun TestApplicationEngine.`Given I have follow on constitution`( + firstName: String, + lastName: String, + constitution: String, +) { + val citizenRepository: CitizenRepository by lazy { GlobalContext.get().koin.get() } + val citizen = citizenRepository.findByUsername("$firstName-$lastName".toLowerCase()) ?: error("Citizen not exist") + createFollow(citizen, ArticleRef(constitution.toUUID())) +} + +fun createFollow(citizen: CitizenRef, article: ArticleRef) { + val followArticleRepository: FollowArticleRepository by lazy { GlobalContext.get().koin.get() } + val follow = FollowForUpdate(createdBy = citizen, target = article) + followArticleRepository.follow(follow) +} + +fun createFollow(citizen: CitizenRef, constitution: ConstitutionRef) { + val followConstitutionRepository: FollowConstitutionRepository by lazy { GlobalContext.get().koin.get() } + val follow = FollowForUpdate(createdBy = citizen, target = constitution) + followConstitutionRepository.follow(follow) +} diff --git a/src/test/kotlin/integration/steps/given/Request.kt b/src/test/kotlin/integration/steps/given/Request.kt new file mode 100644 index 0000000..3dd089f --- /dev/null +++ b/src/test/kotlin/integration/steps/given/Request.kt @@ -0,0 +1,5 @@ +package integration.steps.given + +import io.ktor.server.testing.TestApplicationRequest + +fun TestApplicationRequest.`with no content`(): String? = null diff --git a/src/test/kotlin/integration/steps/when/request.kt b/src/test/kotlin/integration/steps/when/request.kt index fdb0475..5eb7e21 100644 --- a/src/test/kotlin/integration/steps/when/request.kt +++ b/src/test/kotlin/integration/steps/when/request.kt @@ -20,7 +20,7 @@ fun TestApplicationEngine.`When I send a GET request`(uri: String? = null, setup } fun TestApplicationEngine.`When I send a POST request`(uri: String? = null, setup: (TestApplicationRequest.() -> String?)? = null): TestApplicationCall { - val setupOveride: TestApplicationRequest.() -> Unit = { + return handleRequest(true) { method = HttpMethod.Post if (uri != null) { this.uri = uri @@ -30,11 +30,10 @@ fun TestApplicationEngine.`When I send a POST request`(uri: String? = null, setu setBody(it.trimIndent()) } } - return handleRequest(true, setupOveride) } fun TestApplicationEngine.`When I send a PUT request`(uri: String? = null, setup: (TestApplicationRequest.() -> String?)? = null): TestApplicationCall { - val setupOveride: TestApplicationRequest.() -> Unit = { + return handleRequest(true) { method = HttpMethod.Put if (uri != null) { this.uri = uri @@ -44,7 +43,19 @@ fun TestApplicationEngine.`When I send a PUT request`(uri: String? = null, setup setBody(it.trimIndent()) } } - return handleRequest(true, setupOveride) +} + +fun TestApplicationEngine.`When I send a DELETE request`(uri: String? = null, setup: (TestApplicationRequest.() -> String?)? = null): TestApplicationCall { + return handleRequest(true) { + method = HttpMethod.Delete + if (uri != null) { + this.uri = uri + } + addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString()) + setup?.let { it() }?.let { + setBody(it.trimIndent()) + } + } } fun TestApplicationRequest.`with body`(body: String) { diff --git a/src/test/resources/feature/constitution.feature b/src/test/resources/feature/constitution.feature index 90375ac..b1e24aa 100644 --- a/src/test/resources/feature/constitution.feature +++ b/src/test/resources/feature/constitution.feature @@ -1,4 +1,5 @@ @constitution +@disable Feature: constitution Scenario: The route for get constitutions must response a 200 diff --git a/src/test/resources/feature/followArticle.feature b/src/test/resources/feature/followArticle.feature index 237d5cc..d9631ac 100644 --- a/src/test/resources/feature/followArticle.feature +++ b/src/test/resources/feature/followArticle.feature @@ -1,4 +1,5 @@ @follow +@disable Feature: follow Article # Article