package org.tbasket.test.pages import io.getquill.jdbczio.Quill import io.getquill.{SnakeCase, SqliteZioJdbcContext} import org.tbasket.auth.Authenticator import org.tbasket.data.{Database, DatabaseContext} import org.tbasket.error.RegularException.InvalidRequest import org.tbasket.handler.HandlerUtils.parseAttribute import org.tbasket.handler.LoginPageHandler import org.tbasket.handler.LoginPageHandler.post import org.tbasket.test.TestLayers import org.tbasket.test.pages.LoginPageHandlerTests.test import zio.* import zio.http.netty.client.ConnectionPool import zio.http.* import zio.http.model.{HeaderNames, Headers, Status} import zio.http.model.Headers.{Header, empty} import zio.json.* import zio.json.ast.{Json, JsonCursor} import zio.test.* import zio.test.Assertion.* object LoginPageHandlerTests extends ZIOSpecDefault { import LoginPageHandler.post import TestLayers.* private def getJsonBody(r: Response): Task[Json] = { for body <- r.body.asString json <- ZIO.fromEither(body.fromJson[Json]).mapError(new Exception(_)) yield json } private def requestsSpec = suite("erroned request body tests")( ZIO.attempt(Map( "empty packet" -> Body.empty, "with no mail attribute" -> Body.fromString("""{"password":"1234"}"""), "with no password attribute" -> Body.fromString("""{"email":"valid.mail@x.y"}"""), "with invalid json" -> Body.fromString("""this is a corrupted json""") )).map(_.map((name, body) => test(name) { for response <- post(Request.post(body, URL.empty)) json <- getJsonBody(response) errorType <- parseAttribute(json, "error", JsonCursor.field("error").isString) yield assert(response)(hasField("status", _.status, equalTo(Status.Unauthorized))) && assertTrue(errorType == "invalid request") } )) ) private def loginSpec = { suite("login situation tests")( test("login with unknown account") { for response <- post(Request.post(Body.fromString("""{"password":"123456","email":"unknownaccount@gmail.com"}"""), URL.empty)) json <- getJsonBody(response) errorType <- parseAttribute(json, "error", JsonCursor.field("error").isString) errorMsg <- parseAttribute(json, "msg", JsonCursor.field("msg").isString) yield //assert that the response error is of type unauthorized and headers are Location: /register assert(response)(hasField("status", _.status, equalTo(Status.Unauthorized))) && assert(errorType)(equalTo("unauthorized")) && assert(errorMsg)(equalTo("unknown user email")) && assert(response)(hasField("headers", _.headers, hasSameElements(Headers.location("/register")))) }, test("login with known account") { for response <- post(Request.post(Body.fromString("""{"password":"123456","email":"maximebatista18@gmail.com"}"""), URL.empty)) yield assert(response)(hasField("status", _.status, equalTo(Status.Found))) && assert(response)(hasField("body", _.body, equalTo(Body.empty))) //TODO assert that the cookie name is JWT && assert(response)(hasField("headers", _.headers, exists(hasField("key", _.key, equalTo(HeaderNames.setCookie))))) }, test("login with known account wrong password") { val requestJson = """{"password":"this is a wrong password","email":"maximebatista18@gmail.com"}""" for fiber <- post(Request.post(Body.fromString(requestJson), URL.empty)).fork _ <- TestClock.adjust(1.seconds) response <- ZIO.fromFiber(fiber) json <- getJsonBody(response) errorType <- parseAttribute(json, "error", JsonCursor.field("error").isString) errorMsg <- parseAttribute(json, "msg", JsonCursor.field("msg").isString) yield assert(errorType)(equalTo("unauthorized")) && assert(errorMsg)(equalTo("invalid password")) } ) } override def spec = suite("/login page handler")( requestsSpec, loginSpec ).provide( db.datasourceLayer, db.contextLayer, auth, ConnectionPool.fixed(1), Scope.default, ClientConfig.default, Client.live) }