module Yesod.Test.Json (
testApp,
APIFunction,
assertBool,
assertString,
assertOK,
assertJSON,
Session(..),
H.Assertion,
module Test.Hspec,
module Data.Aeson,
SResponse(..)
) where
import qualified Test.HUnit as H
import qualified Data.ByteString.Lazy.Char8 as L8
import qualified Data.ByteString.Lazy as L
import Data.ByteString (ByteString)
import Data.Text (Text)
import Data.Aeson
import Network.HTTP.Types
import Test.Hspec
import Network.Wai
import Network.Wai.Test
import Control.Monad.IO.Class
import Yesod.Default.Config
import Data.Conduit.List
type APIFunction = ByteString
-> [Text]
-> Maybe Value
-> Session SResponse
assertBool :: String -> Bool -> Session ()
assertBool s b = liftIO $ H.assertBool s b
assertString :: String -> Session ()
assertString = liftIO . H.assertString
assertOK :: SResponse -> Session ()
assertOK SResponse{simpleStatus = s, simpleBody = b} = assertBool (concat
[ "Expected status code 200, but received "
, show sc
, ". Response body: "
, show (L8.unpack b)
]) $ sc == 200
where
sc = statusCode s
assertJSON :: (ToJSON a, FromJSON a) => (a -> (String, Bool)) -> SResponse -> Session ()
assertJSON f SResponse{simpleBody = lbs} = do
case decode lbs of
Nothing -> assertString $ "Invalid JSON: " ++ show (L8.unpack lbs)
Just a ->
case fromJSON a of
Error s -> assertString (concat [s, "\nInput JSON: ", show a])
Success x -> uncurry assertBool (f x)
apiRequest :: AppConfig env extra -> APIFunction
apiRequest conf m p x = srequest $ SRequest r (maybe L.empty encode x) where
r = defaultRequest {
serverPort = appPort conf,
requestBody = sourceList . L.toChunks $ encode x,
requestMethod = m,
pathInfo = p
}
testApp :: Application -> AppConfig env extra ->
(((APIFunction -> Session ()) -> H.Assertion) -> Spec) -> IO ()
testApp app conf specfun = do
let apiTest f = runSession (f (apiRequest conf)) app
hspec $ (specfun apiTest)