Skip to content

Commit

Permalink
test(http): assert JSON response for all endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
yoshinorin committed Nov 27, 2023
1 parent 3f73935 commit b9db55d
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 58 deletions.
6 changes: 6 additions & 0 deletions src/test/scala/net/yoshinorin/qualtet/fixture/Fixture.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package net.yoshinorin.qualtet.fixture
import cats.Monad
import cats.effect.IO
import org.http4s.Uri
import org.http4s.Response
import org.typelevel.log4cats.{LoggerFactory => Log4CatsLoggerFactory}
import org.typelevel.log4cats.slf4j.{Slf4jFactory => Log4CatsSlf4jFactory}
import com.github.benmanes.caffeine.cache.Caffeine
import com.github.benmanes.caffeine.cache.{Cache => CaffeineCache}
import com.github.plokhotnyuk.jsoniter_scala.core.JsonValueCodec
import net.yoshinorin.qualtet.http.AuthProvider
import net.yoshinorin.qualtet.http.CorsProvider
import net.yoshinorin.qualtet.cache.CacheModule
Expand Down Expand Up @@ -206,4 +208,8 @@ object Fixture {
Modules.seriesService.create(rs).unsafeRunSync()
}
}

def unsafeDecode[T](response: Response[IO])(implicit j: JsonValueCodec[T]) = {
response.as[String].unsafeRunSync().decode
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import org.http4s.*
import org.http4s.dsl.io.*
import org.http4s.headers.`Content-Type`
import org.http4s.implicits.*
import net.yoshinorin.qualtet.domains.articles.ResponseArticleWithCount
import net.yoshinorin.qualtet.domains.authors.AuthorName
import net.yoshinorin.qualtet.domains.contents.{Path, RequestContent}
import net.yoshinorin.qualtet.domains.robots.Attributes
import net.yoshinorin.qualtet.message.Message
import net.yoshinorin.qualtet.Modules.*
import net.yoshinorin.qualtet.fixture.Fixture
import net.yoshinorin.qualtet.fixture.Fixture.{author, router, unsafeDecode}
import org.scalatest.wordspec.AnyWordSpec

import cats.effect.unsafe.implicits.global
Expand All @@ -36,9 +38,9 @@ class ArticleRouteSpec extends AnyWordSpec {
}

// NOTE: create content and related data for test
requestContents.foreach { rc => contentService.createContentFromRequest(AuthorName(Fixture.author.name.value), rc).unsafeRunSync() }
requestContents.foreach { rc => contentService.createContentFromRequest(AuthorName(author.name.value), rc).unsafeRunSync() }

val client: Client[IO] = Client.fromHttpApp(Fixture.router.routes.orNotFound)
val client: Client[IO] = Client.fromHttpApp(router.routes.orNotFound)

"ArticleRoute" should {
"be return articles with default query params" in {
Expand All @@ -48,8 +50,10 @@ class ArticleRouteSpec extends AnyWordSpec {
IO {
assert(response.status === Ok)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
// TODO: assert json
assert(response.as[String].unsafeRunSync().replaceAll("\n", "").replaceAll(" ", "").contains("count"))

val maybeArticles = unsafeDecode[ResponseArticleWithCount](response)
assert(maybeArticles.count >= 20) // FIXME: get number of all articles and assert it.
assert(maybeArticles.articles.size === 10)
}
}
.unsafeRunSync()
Expand All @@ -62,8 +66,10 @@ class ArticleRouteSpec extends AnyWordSpec {
IO {
assert(response.status === Ok)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
// TODO: assert json
assert(response.as[String].unsafeRunSync().replaceAll("\n", "").replaceAll(" ", "").contains("count"))

val maybeArticles = unsafeDecode[ResponseArticleWithCount](response)
assert(maybeArticles.count >= 20) // FIXME: get number of all articles and assert it.
assert(maybeArticles.articles.size === 5)
}
}
.unsafeRunSync()
Expand All @@ -76,8 +82,10 @@ class ArticleRouteSpec extends AnyWordSpec {
IO {
assert(response.status === Ok)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
// TODO: assert json & it's count
assert(response.as[String].unsafeRunSync().replaceAll("\n", "").replaceAll(" ", "").contains("count"))

val maybeArticles = unsafeDecode[ResponseArticleWithCount](response)
assert(maybeArticles.count >= 20) // FIXME: get number of all articles and assert it.
assert(maybeArticles.articles.size === 10)
}
}
.unsafeRunSync()
Expand All @@ -90,7 +98,9 @@ class ArticleRouteSpec extends AnyWordSpec {
IO {
assert(response.status === NotFound)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
assert(response.as[String].unsafeRunSync().replaceAll("\n", "").replaceAll(" ", "").contains("articlesnotfound"))

val maybeError = unsafeDecode[Message](response)
assert(maybeError.message === "articles not found")
}
}
.unsafeRunSync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import org.http4s.dsl.io.*
import org.http4s.headers.`Content-Type`
import org.http4s.implicits.*
import net.yoshinorin.qualtet.domains.authors.ResponseAuthor
import net.yoshinorin.qualtet.auth.ResponseToken
import net.yoshinorin.qualtet.message.Message
import net.yoshinorin.qualtet.Modules.*
import net.yoshinorin.qualtet.fixture.Fixture.{author, router}
import net.yoshinorin.qualtet.fixture.Fixture.{author, router, unsafeDecode}
import org.scalatest.wordspec.AnyWordSpec
import cats.effect.unsafe.implicits.global

Expand Down Expand Up @@ -36,8 +38,9 @@ class AuthRouteSpec extends AnyWordSpec {
IO {
assert(response.status === Ok)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
// TODO: assert json
assert(response.as[String].unsafeRunSync().contains("."))

val maybeToken = unsafeDecode[ResponseToken](response)
assert(maybeToken.token.count(_ === '.') === 2)
}
}
.unsafeRunSync()
Expand Down Expand Up @@ -142,7 +145,8 @@ class AuthRouteSpec extends AnyWordSpec {
assert(response.status === NotFound)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
// TODO: avoid to return user not found message
assert(response.as[String].unsafeRunSync().replaceAll("\n", "").replaceAll(" ", "").contains("not-exists-userisnotfound."))
val maybeError = unsafeDecode[Message](response)
assert(maybeError.message === "not-exists-user is not found.")
}
}
.unsafeRunSync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import org.http4s.dsl.io.*
import org.http4s.headers.`Content-Type`
import org.http4s.implicits.*
import net.yoshinorin.qualtet.domains.authors.{AuthorName, ResponseAuthor}
import net.yoshinorin.qualtet.fixture.Fixture.{author, author2, router}
import net.yoshinorin.qualtet.message.Message
import net.yoshinorin.qualtet.fixture.Fixture.{author, author2, router, unsafeDecode}
import net.yoshinorin.qualtet.Modules.*
import org.scalatest.wordspec.AnyWordSpec
import cats.effect.unsafe.implicits.global
Expand Down Expand Up @@ -46,7 +47,6 @@ class AuthorRouteSpec extends AnyWordSpec {
IO {
assert(response.status === Ok)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
// TODO: assert json & it's count
assert(response.as[String].unsafeRunSync().replaceAll("\n", "").replaceAll(" ", "").contains(expectJson))
}
}
Expand All @@ -70,7 +70,6 @@ class AuthorRouteSpec extends AnyWordSpec {
IO {
assert(response.status === Ok)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
// TODO: assert json & it's count
assert(response.as[String].unsafeRunSync().replaceAll("\n", "").replaceAll(" ", "").contains(expectJson))
}
}
Expand All @@ -84,7 +83,9 @@ class AuthorRouteSpec extends AnyWordSpec {
IO {
assert(response.status === NotFound)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
assert(response.as[String].unsafeRunSync().replaceAll("\n", "").replaceAll(" ", "").contains("NotFound"))

val maybeError = unsafeDecode[Message](response)
assert(maybeError.message === "Not Found")
}
}
.unsafeRunSync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ import org.http4s.implicits.*
import org.typelevel.ci.*
import net.yoshinorin.qualtet.auth.RequestToken
import net.yoshinorin.qualtet.domains.authors.ResponseAuthor
import net.yoshinorin.qualtet.domains.contents.{ContentId, Path, RequestContent}
import net.yoshinorin.qualtet.domains.contents.{Content, ContentId, Path, RequestContent, ResponseContent}
import net.yoshinorin.qualtet.domains.robots.Attributes
import net.yoshinorin.qualtet.message.Message
import net.yoshinorin.qualtet.fixture.Fixture.*
import net.yoshinorin.qualtet.Modules.*
import org.scalatest.wordspec.AnyWordSpec

import java.time.Instant

import cats.effect.unsafe.implicits.global

// testOnly net.yoshinorin.qualtet.http.routes.ContentRouteSpec
Expand Down Expand Up @@ -45,7 +49,17 @@ class ContentRouteSpec extends AnyWordSpec {
IO {
assert(response.status === Created)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
// TODO: assert response

val maybeContent = unsafeDecode[Content](response)
assert(maybeContent.authorId === validAuthor.id)
// assert(maybeContent.contentTypeId === 'TODO') TODO: assert contentTypeId
assert(maybeContent.htmlContent === "<p>this is a html ContentRouteSpec1<p>")
// assert(maybeContent.id) TODO: asset id is ULID
assert(maybeContent.path === "/test/ContentRouteSpec1")
assert(maybeContent.publishedAt === 1644075206)
assert(maybeContent.rawContent === "this is a raw ContentRouteSpec1")
assert(maybeContent.title === "this is a ContentRouteSpec1 title")
assert(maybeContent.updatedAt === 1644075206)
}
}
.unsafeRunSync()
Expand All @@ -72,7 +86,7 @@ class ContentRouteSpec extends AnyWordSpec {
IO {
assert(response.status === Created)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
// TODO: assert response
// NOTE: no-need to assert response. Because, this test case for `HTTP Header bearer is LowerCase`.
}
}
.unsafeRunSync()
Expand Down Expand Up @@ -111,7 +125,9 @@ class ContentRouteSpec extends AnyWordSpec {
IO {
assert(response.status === NotFound)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
assert(response.as[String].unsafeRunSync().replaceAll("\n", "").replaceAll(" ", "").contains("contentnotfound"))

val maybeError = unsafeDecode[Message](response)
assert(maybeError.message.startsWith("content not found: "))
}
}
.unsafeRunSync()
Expand Down Expand Up @@ -363,6 +379,8 @@ class ContentRouteSpec extends AnyWordSpec {
}

"be return specific content" in {
val now = Instant.now.getEpochSecond

// NOTE: create content and related data for test
contentService
.createContentFromRequest(
Expand All @@ -375,7 +393,8 @@ class ContentRouteSpec extends AnyWordSpec {
htmlContent = "<p>this is a html ContentRouteSpec2<p>",
robotsAttributes = Attributes("noarchive, noimageindex"),
tags = List("ContentRoute"),
externalResources = List()
externalResources = List(),
publishedAt = 1644075206
)
)
.unsafeRunSync()
Expand All @@ -391,7 +410,19 @@ class ContentRouteSpec extends AnyWordSpec {
IO {
assert(response.status === Ok)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
// TODO: assert json

val maybeContent = unsafeDecode[ResponseContent](response)
assert(maybeContent.authorName === validAuthor.displayName.toString().toLowerCase())
assert(maybeContent.content === "<p>this is a html ContentRouteSpec2<p>")
assert(maybeContent.description === "this is a html ContentRouteSpec2")
assert(maybeContent.externalResources.isEmpty)
assert(maybeContent.length === "this is a html ContentRouteSpec2".size)
assert(maybeContent.publishedAt === 1644075206)
assert(maybeContent.robotsAttributes === "noarchive, noimageindex")
assert(maybeContent.tags.size === 1)
assert(maybeContent.tags.head.name === "ContentRoute")
assert(maybeContent.title === "this is a ContentRouteSpec2 title")
assert(maybeContent.updatedAt >= now)
}
}
.unsafeRunSync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import org.http4s.*
import org.http4s.dsl.io.*
import org.http4s.headers.`Content-Type`
import org.http4s.implicits.*
import net.yoshinorin.qualtet.fixture.Fixture.router
import net.yoshinorin.qualtet.domains.contentTypes.ContentType
import net.yoshinorin.qualtet.message.Message
import net.yoshinorin.qualtet.fixture.Fixture.{router, unsafeDecode}
import org.scalatest.wordspec.AnyWordSpec

import cats.effect.unsafe.implicits.global
Expand All @@ -25,6 +27,9 @@ class ContentTypeRouteSpec extends AnyWordSpec {
IO {
assert(response.status === Ok)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))

val maybeContentTypes = unsafeDecode[Seq[ContentType]](response)
assert(maybeContentTypes.size === 2)
}
}
.unsafeRunSync()
Expand All @@ -37,7 +42,10 @@ class ContentTypeRouteSpec extends AnyWordSpec {
IO {
assert(response.status === Ok)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
assert(response.as[String].unsafeRunSync().replaceAll("\n", "").replaceAll(" ", "").contains("article"))

val maybeContentType = unsafeDecode[ContentType](response)
// assert(maybeContentType.id === "TODO") // TODO: assert id is ULID
assert(maybeContentType.name === "article")
}
}
.unsafeRunSync()
Expand All @@ -50,7 +58,10 @@ class ContentTypeRouteSpec extends AnyWordSpec {
IO {
assert(response.status === Ok)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
assert(response.as[String].unsafeRunSync().replaceAll("\n", "").replaceAll(" ", "").contains("page"))

val maybeContentType = unsafeDecode[ContentType](response)
// assert(maybeContentType.id === "TODO") // TODO: assert id is ULID
assert(maybeContentType.name === "page")
}
}
.unsafeRunSync()
Expand All @@ -63,7 +74,9 @@ class ContentTypeRouteSpec extends AnyWordSpec {
IO {
assert(response.status === NotFound)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
assert(response.as[String].unsafeRunSync().replaceAll("\n", "").replaceAll(" ", "").contains("NotFound"))

val maybeError = unsafeDecode[Message](response)
assert(maybeError.message === "Not Found")
}
}
.unsafeRunSync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.http4s.*
import org.http4s.dsl.io.*
import org.http4s.headers.`Content-Type`
import org.http4s.implicits.*
import net.yoshinorin.qualtet.domains.feeds.ResponseFeed
import net.yoshinorin.qualtet.fixture.Fixture.*
import org.scalatest.wordspec.AnyWordSpec
import org.scalatest.BeforeAndAfterAll
Expand Down Expand Up @@ -33,6 +34,9 @@ class FeedRouteSpec extends AnyWordSpec with BeforeAndAfterAll {
assert(response.status === Ok)
assert(response.contentType.get === `Content-Type`(MediaType.application.json))
// TODO: assert response contents count

val maybeFeeds = unsafeDecode[Seq[ResponseFeed]](response)
assert(maybeFeeds.size === 5)
}
}
.unsafeRunSync()
Expand Down
Loading

0 comments on commit b9db55d

Please sign in to comment.