packages feed

serv-wai-0.2.0.0: test/Examples/Ex1.hs

{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators     #-}

module Examples.Ex1 where

import           Data.String
import           Data.Text        (Text)
import           Serv.Api.Prelude
import           Serv.Wai.Prelude

import qualified Network.Wai      as Wai
import qualified Network.Wai.Test as T
import           Test.Tasty
import qualified Test.Tasty.HUnit as Hu

type RawBody = HasBody '[TextPlain] Text
type JSONBody = HasBody '[JSON] [Int]

type TheApi
  = Endpoint ()
    '[
      Method GET
       '[ Ok :::
          Respond '[ CacheControl ::: Raw Text ] RawBody
        ]
     , Method PUT
       '[ Ok :::
          Respond '[ CacheControl ::: Raw Text ] JSONBody
        ]
     , Method DELETE
       '[ InternalServerError :::
          Respond '[] RawBody
        ]
     ]

apiSing :: Sing TheApi
apiSing = sing

impl :: Impl IO TheApi
impl =
  SGET =:
    (return . respond
       $ emptyResponse SOk
       & withHeader SCacheControl "foo"
       & withBody "Hello")
  <+>
  SPUT =:
    (return . respond
       $ emptyResponse SOk
       & withHeader SCacheControl "foo"
       & withBody [1, 2, 3])
  <+>
  SDELETE =:
    (return . respond
       $ emptyResponse SInternalServerError
       & withBody "Server error")
  <+>
  RNil

theServer :: Server IO
theServer = server apiSing impl

runTest :: T.Session a -> IO a
runTest = flip T.runSession (serverApplication theServer)

test1 :: TestTree
test1 = testGroup "Simple responses"
  [ Hu.testCase "Constant GET response (RawText)" $ runTest $ do
      let req = Wai.defaultRequest
      resp <- T.request req
      T.assertStatus 200 resp
      T.assertContentType "text/plain" resp
      T.assertBody "Hello" resp
      T.assertHeader "Cache-Control" "foo" resp

  , Hu.testCase "404 response (RawText) at ////" $ runTest $ do
      let req = Wai.defaultRequest
                & flip T.setPath "////"
      resp <- T.request req
      T.assertStatus 404 resp

  , Hu.testCase "Constant PUT response (JSON)" $ runTest $ do
      let req = Wai.defaultRequest { Wai.requestMethod = "PUT" }
      resp <- T.request req
      T.assertStatus 200 resp
      T.assertContentType "application/json" resp
      T.assertBody "[1,2,3]" resp
      T.assertHeader "Cache-Control" "foo" resp

  , Hu.testCase "Proper OPTIONS response" $ runTest $ do
      let req = Wai.defaultRequest
                { Wai.requestMethod = "OPTIONS" }
      resp <- T.request req
      T.assertStatus 200 resp
      T.assertBody "" resp
      T.assertHeader "Allow" "DELETE,GET,HEAD,OPTIONS,PUT" resp

  , Hu.testCase "Proper HEAD response" $ runTest $ do
      let req = Wai.defaultRequest
                { Wai.requestMethod = "HEAD" }
      resp <- T.request req
      T.assertStatus 200 resp
      T.assertBody "" resp
      T.assertHeader "Cache-Control" "foo" resp

  , Hu.testCase "Error on DELETE response" $ runTest $ do
      let req = Wai.defaultRequest
                { Wai.requestMethod = "DELETE" }
      resp <- T.request req
      T.assertStatus 500 resp
      T.assertBody "Server error" resp

  , Hu.testCase "Missing response at bad path" $ runTest $ do
      let req =
            Wai.defaultRequest
            & flip T.setPath "/hello"
      resp <- T.request req
      T.assertStatus 404 resp
      T.assertBody "" resp
      T.assertNoHeader "Cache-Control" resp

  , testGroup "Missing responses at wrong methods"
    $ flip map ["POST", "NOTAMETHOD"] $ \method ->
      Hu.testCase ("Missing response at method " ++ method) $ runTest $ do
        let req =
              Wai.defaultRequest
              { Wai.requestMethod = fromString method }
        resp <- T.request req
        T.assertStatus 405 resp
        T.assertBody "" resp
        T.assertNoHeader "Cache-Control" resp
  ]

tests :: TestTree
tests = testGroup "Example 1" [ test1 ]