tasty-wai-0.1.0.0: src/Test/Tasty/Wai.hs
-- | Types and functions for testing 'wai' endpoints using the 'tasty' testing framework.
--
module Test.Tasty.Wai
(
-- * Types
Sess (..)
-- * Creation
, testWai
-- * Helpers
, get
, post
, put
, assertStatus'
-- * Request Builders
, buildRequest
, buildRequestWithBody
, module Network.Wai.Test
) where
import qualified Control.Exception as E
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import Data.Monoid ((<>))
import Network.HTTP.Types (StdMethod)
import qualified Network.HTTP.Types as HTTP
import Test.Tasty.Providers (IsTest (..), Progress (..), TestName,
TestTree, singleTest, testFailed,
testPassed)
import Test.Tasty.Runners (formatMessage)
import Network.Wai (Application, Request, requestMethod)
import Network.Wai.Test
-- | Data structure for carrying around the info needed to build and run a test.
data Sess = S Application TestName (Session ())
instance IsTest Sess where
-- No options yet
testOptions = mempty
run _ (S app tName sess) yieldProgress = do
-- We don't really have progress to report, so state that we're running a
-- test but do nothing else.
yieldProgress $ Progress ("Running " <> tName) 0
-- The wai-extra testing uses `throwIO` to indicate a test failure and
-- converts that error into a 'String'. The result of the individual
-- 'Session a' isn't important for the test?
E.try (runSession sess app) >>= either toFailure toPass
where
toFailure (WaiTestFailure s) = testFailed <$> (formatMessage s)
toPass _ = pure (testPassed mempty)
-- | Create an empty 'Request' using the given HTTP Method and route.
buildRequest
:: StdMethod
-> BS.ByteString
-> Request
buildRequest mth rpath = flip setPath rpath $ defaultRequest
{ requestMethod = HTTP.renderStdMethod mth
}
-- | As per 'buildRequest' but requires body content.
buildRequestWithBody
:: StdMethod
-> BS.ByteString
-> LBS.ByteString
-> SRequest
buildRequestWithBody mth rpath =
SRequest (buildRequest mth rpath)
-- | Run a test case against a 'Application'.
--
-- This module re-exports the functions from 'wai-extra' for constructing the
-- 'Session' that is executed against a given endpoint.
--
-- A small test case may look like:
--
-- @
-- import MyApp (app)
--
-- testWai app "List Topics" $ do
-- res <- get "fudge/view"
-- assertStatus' HTTP.status200 res
-- @
--
testWai :: Application -> TestName -> Session () -> TestTree
testWai a tn = singleTest tn . S a tn
-- | Submit a 'HTTP.GET' request to the provided endpoint.
get :: BS.ByteString -> Session SResponse
get = request . buildRequest HTTP.GET
-- | Submit a 'HTTP.POST' request to the given endpoint with the provided
-- 'LBS.ByteString' as the body content.
post :: BS.ByteString -> LBS.ByteString -> Session SResponse
post r = srequest . buildRequestWithBody HTTP.POST r
-- | Submit a 'HTTP.PUT' request to the given endpoint with the provided
-- 'LBS.ByteString' as the body content.
put :: BS.ByteString -> LBS.ByteString -> Session SResponse
put r = srequest . buildRequestWithBody HTTP.PUT r
-- | An alternative helper function for checking the status code on a response
-- that lets you use the functions from 'Network.HTTP.Types' as opposed to bare
-- numbers.
assertStatus' :: HTTP.Status -> SResponse -> Session ()
assertStatus' c = assertStatus (HTTP.statusCode c)