packages feed

hairy-0.1.0: test-suite/Main.hs

{-# LANGUAGE OverloadedStrings #-}

module Main
  ( main
  ) where

import Control.Monad.Reader (runReaderT)
import Hairy (Config (Config), Environment (Test), application, pool,
  environment, getPool, runConfigM)
import Hairy.Models (Task (Task), taskContent, taskCreated)
import Data.Time.Calendar (fromGregorian)
import Data.Time.Clock (UTCTime (UTCTime), utctDay, utctDayTime)
import Database.Persist.Sql (ConnectionPool, insert_, rawExecute, runSqlPool)
import Network.HTTP.Types.Status (created201, notFound404, ok200)
import Network.Wai.Internal (requestMethod)
import Network.Wai.Test (SRequest (SRequest), defaultRequest, request,
  runSession, setPath, simpleBody, simpleHeaders, simpleRequest,
  simpleRequestBody, simpleStatus, srequest)
import Test.Hspec (before, describe, hspec, it, shouldBe)
import Web.Scotty.Trans (scottyAppT)

main :: IO ()
main = do
  let e = Test
  p <- getPool e
  let c = Config
        { environment = e
        , pool = p
        }
      t m = runReaderT (runConfigM m) c
  a <- scottyAppT t t application

  hspec $ before (resetDB p) $ do
    describe "/" $ do
      describe "GET" $ do
        it "404s" $ do
          r <- runSession (request defaultRequest) a
          simpleStatus r `shouldBe` notFound404
          lookup "Content-Type" (simpleHeaders r) `shouldBe`
            Just "application/json; charset=utf-8"
          simpleBody r `shouldBe` "null"

    describe "/tasks" $ do
      describe "GET" $ do
        it "lists the tasks" $ do
          r <- runSession (request (defaultRequest `setPath` "/tasks")) a
          simpleStatus r `shouldBe` ok200
          lookup "Content-Type" (simpleHeaders r) `shouldBe`
            Just "application/json; charset=utf-8"
          simpleBody r `shouldBe` "[]"

      describe "POST" $ do
        it "creates a task" $ do
          let req = srequest SRequest
                { simpleRequest = defaultRequest
                  { requestMethod = "POST"
                  } `setPath` "/tasks"
                , simpleRequestBody = "{\"content\":\"\",\"created\":\"2001-02-03T04:05:06Z\"}"
                }
          r <- runSession req a
          simpleStatus r `shouldBe` created201
          lookup "Content-Type" (simpleHeaders r) `shouldBe`
            Just "application/json; charset=utf-8"
          simpleBody r `shouldBe`
            "{\"created\":\"2001-02-03T04:05:06.000Z\",\"content\":\"\"}"

    describe "/tasks/:id" $ before (createTask p) $ do
      describe "GET" $ do
        it "shows the task" $ do
          r <- runSession (request (setPath defaultRequest "/tasks/1")) a
          simpleStatus r `shouldBe` ok200
          lookup "Content-Type" (simpleHeaders r) `shouldBe`
            Just "application/json; charset=utf-8"
          simpleBody r `shouldBe`
            "{\"created\":\"2001-02-03T04:05:06.000Z\",\"content\":\"\"}"

      describe "PUT" $ do
        it "replaces the task" $ do
          let req = srequest SRequest
                { simpleRequest = defaultRequest
                  { requestMethod = "PUT"
                  } `setPath` "/tasks/1"
                , simpleRequestBody = "{\"content\":\"!\",\"created\":\"2001-02-03T04:05:06Z\"}"
                }
          r <- runSession req a
          simpleStatus r `shouldBe` ok200
          lookup "Content-Type" (simpleHeaders r) `shouldBe`
            Just "application/json; charset=utf-8"
          simpleBody r `shouldBe`
            "{\"created\":\"2001-02-03T04:05:06.000Z\",\"content\":\"!\"}"

      describe "DELETE" $ do
        it "deletes the task" $ do
          r <- runSession (request (defaultRequest { requestMethod = "DELETE" }`setPath` "/tasks/1")) a
          simpleStatus r `shouldBe` ok200
          lookup "Content-Type" (simpleHeaders r) `shouldBe`
            Just "application/json; charset=utf-8"
          simpleBody r `shouldBe` "null"

resetDB :: ConnectionPool -> IO ()
resetDB = runSqlPool (rawExecute "TRUNCATE TABLE task RESTART IDENTITY" [])

createTask :: ConnectionPool -> IO ()
createTask = runSqlPool (insert_ task) where
  task = Task
    { taskContent = ""
    , taskCreated = UTCTime
      { utctDay = fromGregorian 2001 2 3
      , utctDayTime = 14706
      }
    }