{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE UndecidableInstances #-}

-- | Similar to "Yesod.Test" from the yesod-test package
--
-- Actions in the 'YesodExample' monad are generalized to a
-- 'MonadYesodExample' constraint, allowing tests to be written
-- in custom monads more easily.
module Freckle.App.Test.Yesod
  ( -- * Monad class
    MonadYesodExample (..)

    -- * Making requests

    -- ** Via RequestBuilder
  , request
  , RequestBuilder
  , setMethod
  , setUrl
  , setRequestBody
  , addGetParam
  , addPostParam
  , addRequestHeader
  , addJsonHeaders
  , setLanguage
  , addAcceptLanguage
  , addFile

    -- ** Other ways
  , get
  , post
  , followRedirect

    -- * Inspecting the response

    -- ** Getting the body
  , getRawBody
  , getCsvBody
  , getJsonBody

    -- ** Dealing with the response
  , getResponse
  , withResponse
  , SResponse (..)

    -- * Assertions

    -- ** Status
  , statusIs

    -- ** Header fields
  , assertHeader
  , assertHeaderContains
  , assertHeaderSatisfies

    -- ** Body
  , bodyContains

    -- * Cookies
  , getRequestCookies
  , testSetCookie
  , testDeleteCookie
  , testClearCookies

    -- * Foundational details
  , SIO
  , TestApp
  , YesodExample
  , YesodExampleData (..)
  , getTestYesod
  )
where

import Freckle.App.Prelude

import Blammo.Logging (LoggingT)
import Control.Monad.Except (ExceptT)
import Control.Monad.State (StateT)
import Control.Monad.Trans.Maybe (MaybeT)
import Control.Monad.Trans.Resource (ResourceT)
import Control.Monad.Validate (ValidateT)
import Data.Aeson (FromJSON, eitherDecode)
import Data.BCP47 (BCP47)
import qualified Data.BCP47 as BCP47
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import Data.CaseInsensitive (CI)
import Data.Csv (FromNamedRecord, decodeByName)
import qualified Data.Text as T
import qualified Data.Vector as V
import Network.HTTP.Types.Header (hAccept, hAcceptLanguage, hContentType)
import Network.Wai.Test (SResponse (..))
import Test.Hspec.Expectations.Lifted (expectationFailure)
import Web.Cookie (SetCookie)
import Yesod.Core (RedirectUrl, Yesod)
import Yesod.Test
  ( RequestBuilder
  , SIO
  , TestApp
  , YesodExample
  , YesodExampleData (..)
  , addFile
  , addGetParam
  , addPostParam
  , addRequestHeader
  , getRequestCookies
  , setMethod
  , setRequestBody
  , setUrl
  , withResponse
  )
import qualified Yesod.Test

class (MonadIO m, Yesod site) => MonadYesodExample site m | m -> site where
  liftYesodExample :: YesodExample site a -> m a

instance Yesod site => MonadYesodExample site (YesodExample site) where
  liftYesodExample :: forall a. YesodExample site a -> YesodExample site a
liftYesodExample = YesodExample site a -> YesodExample site a
forall a. a -> a
id

instance MonadYesodExample site m => MonadYesodExample site (StateT s m) where
  liftYesodExample :: forall a. YesodExample site a -> StateT s m a
liftYesodExample = m a -> StateT s m a
forall (m :: * -> *) a. Monad m => m a -> StateT s m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> StateT s m a)
-> (YesodExample site a -> m a)
-> YesodExample site a
-> StateT s m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YesodExample site a -> m a
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample

instance MonadYesodExample site m => MonadYesodExample site (ReaderT r m) where
  liftYesodExample :: forall a. YesodExample site a -> ReaderT r m a
liftYesodExample = m a -> ReaderT r m a
forall (m :: * -> *) a. Monad m => m a -> ReaderT r m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> ReaderT r m a)
-> (YesodExample site a -> m a)
-> YesodExample site a
-> ReaderT r m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YesodExample site a -> m a
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample

instance MonadYesodExample site m => MonadYesodExample site (ValidateT e m) where
  liftYesodExample :: forall a. YesodExample site a -> ValidateT e m a
liftYesodExample = m a -> ValidateT e m a
forall (m :: * -> *) a. Monad m => m a -> ValidateT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> ValidateT e m a)
-> (YesodExample site a -> m a)
-> YesodExample site a
-> ValidateT e m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YesodExample site a -> m a
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample

instance MonadYesodExample site m => MonadYesodExample site (MaybeT m) where
  liftYesodExample :: forall a. YesodExample site a -> MaybeT m a
liftYesodExample = m a -> MaybeT m a
forall (m :: * -> *) a. Monad m => m a -> MaybeT m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> MaybeT m a)
-> (YesodExample site a -> m a)
-> YesodExample site a
-> MaybeT m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YesodExample site a -> m a
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample

instance MonadYesodExample site m => MonadYesodExample site (ExceptT e m) where
  liftYesodExample :: forall a. YesodExample site a -> ExceptT e m a
liftYesodExample = m a -> ExceptT e m a
forall (m :: * -> *) a. Monad m => m a -> ExceptT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> ExceptT e m a)
-> (YesodExample site a -> m a)
-> YesodExample site a
-> ExceptT e m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YesodExample site a -> m a
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample

instance MonadYesodExample site m => MonadYesodExample site (ResourceT m) where
  liftYesodExample :: forall a. YesodExample site a -> ResourceT m a
liftYesodExample = m a -> ResourceT m a
forall (m :: * -> *) a. Monad m => m a -> ResourceT m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> ResourceT m a)
-> (YesodExample site a -> m a)
-> YesodExample site a
-> ResourceT m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YesodExample site a -> m a
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample

instance MonadYesodExample site m => MonadYesodExample site (LoggingT m) where
  liftYesodExample :: forall a. YesodExample site a -> LoggingT m a
liftYesodExample = m a -> LoggingT m a
forall (m :: * -> *) a. Monad m => m a -> LoggingT m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> LoggingT m a)
-> (YesodExample site a -> m a)
-> YesodExample site a
-> LoggingT m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YesodExample site a -> m a
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample

-- | Assert the last response has the given text
--
-- The check is performed using the response body in full text form.
bodyContains :: forall m site. MonadYesodExample site m => String -> m ()
bodyContains :: forall (m :: * -> *) site.
MonadYesodExample site m =>
String -> m ()
bodyContains = YesodExample site () -> m ()
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample (YesodExample site () -> m ())
-> (String -> YesodExample site ()) -> String -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> YesodExample site ()
forall site. HasCallStack => String -> YesodExample site ()
Yesod.Test.bodyContains

-- | Clears the current cookies
testClearCookies :: forall m site. MonadYesodExample site m => m ()
testClearCookies :: forall (m :: * -> *) site. MonadYesodExample site m => m ()
testClearCookies = YesodExample site () -> m ()
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample YesodExample site ()
forall site. YesodExample site ()
Yesod.Test.testClearCookies

-- | Deletes the cookie of the given name
testDeleteCookie
  :: forall m site. MonadYesodExample site m => ByteString -> m ()
testDeleteCookie :: forall (m :: * -> *) site.
MonadYesodExample site m =>
ByteString -> m ()
testDeleteCookie = YesodExample site () -> m ()
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample (YesodExample site () -> m ())
-> (ByteString -> YesodExample site ()) -> ByteString -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> YesodExample site ()
forall site. ByteString -> YesodExample site ()
Yesod.Test.testDeleteCookie

-- | Sets a cookie
testSetCookie :: forall m site. MonadYesodExample site m => SetCookie -> m ()
testSetCookie :: forall (m :: * -> *) site.
MonadYesodExample site m =>
SetCookie -> m ()
testSetCookie = YesodExample site () -> m ()
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample (YesodExample site () -> m ())
-> (SetCookie -> YesodExample site ()) -> SetCookie -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SetCookie -> YesodExample site ()
forall site. SetCookie -> YesodExample site ()
Yesod.Test.testSetCookie

-- | Get the body of the most recent response and decode it as JSON
getJsonBody :: forall a m site. (MonadYesodExample site m, FromJSON a) => m a
getJsonBody :: forall a (m :: * -> *) site.
(MonadYesodExample site m, FromJSON a) =>
m a
getJsonBody = (String -> m a) -> (a -> m a) -> Either String a -> m a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> m a
forall {m :: * -> *} {a}. MonadIO m => String -> m a
err a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either String a -> m a)
-> (ByteString -> Either String a) -> ByteString -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String a
forall a. FromJSON a => ByteString -> Either String a
eitherDecode (ByteString -> m a) -> m ByteString -> m a
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m ByteString
forall (m :: * -> *) site. MonadYesodExample site m => m ByteString
getRawBody
 where
  err :: String -> m a
err String
e = String -> m a
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> m a) -> String -> m a
forall a b. (a -> b) -> a -> b
$ String
"Error decoding JSON response body: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
e

-- | Get the body of the most recent response and decode it as CSV
getCsvBody
  :: forall a m site. (MonadYesodExample site m, FromNamedRecord a) => m [a]
getCsvBody :: forall a (m :: * -> *) site.
(MonadYesodExample site m, FromNamedRecord a) =>
m [a]
getCsvBody = (String -> m [a])
-> ((Header, Vector a) -> m [a])
-> Either String (Header, Vector a)
-> m [a]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> m [a]
forall {m :: * -> *} {a}. MonadIO m => String -> m a
err ([a] -> m [a]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([a] -> m [a])
-> ((Header, Vector a) -> [a]) -> (Header, Vector a) -> m [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Vector a -> [a]
forall a. Vector a -> [a]
V.toList (Vector a -> [a])
-> ((Header, Vector a) -> Vector a) -> (Header, Vector a) -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Header, Vector a) -> Vector a
forall a b. (a, b) -> b
snd) (Either String (Header, Vector a) -> m [a])
-> (ByteString -> Either String (Header, Vector a))
-> ByteString
-> m [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String (Header, Vector a)
forall a.
FromNamedRecord a =>
ByteString -> Either String (Header, Vector a)
decodeByName (ByteString -> m [a]) -> m ByteString -> m [a]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m ByteString
forall (m :: * -> *) site. MonadYesodExample site m => m ByteString
getRawBody
 where
  err :: String -> m a
err String
e = String -> m a
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString (String -> m a) -> String -> m a
forall a b. (a -> b) -> a -> b
$ String
"Error decoding CSV response body: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
e

-- | Get the body of the most recent response as a byte string
getRawBody :: forall m site. MonadYesodExample site m => m BSL.ByteString
getRawBody :: forall (m :: * -> *) site. MonadYesodExample site m => m ByteString
getRawBody =
  (SResponse -> ByteString) -> m SResponse -> m ByteString
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap SResponse -> ByteString
simpleBody (m SResponse -> m ByteString)
-> (Maybe SResponse -> m SResponse)
-> Maybe SResponse
-> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m SResponse
-> (SResponse -> m SResponse) -> Maybe SResponse -> m SResponse
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> m SResponse
forall (m :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
throwString String
"Test response had no body") SResponse -> m SResponse
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    (Maybe SResponse -> m ByteString)
-> m (Maybe SResponse) -> m ByteString
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m (Maybe SResponse)
forall (m :: * -> *) site.
MonadYesodExample site m =>
m (Maybe SResponse)
getResponse

-- | Get the most recently provided response value, if available
getResponse :: forall m site. MonadYesodExample site m => m (Maybe SResponse)
getResponse :: forall (m :: * -> *) site.
MonadYesodExample site m =>
m (Maybe SResponse)
getResponse = YesodExample site (Maybe SResponse) -> m (Maybe SResponse)
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample YesodExample site (Maybe SResponse)
forall site. YesodExample site (Maybe SResponse)
Yesod.Test.getResponse

-- | The general interface for performing requests
--
-- 'request' takes a 'RequestBuilder', constructs a request, and executes it.
--
-- The 'RequestBuilder' allows you to build up attributes of the request,
-- like the headers, parameters, and URL of the request.
request
  :: forall m site. MonadYesodExample site m => RequestBuilder site () -> m ()
request :: forall (m :: * -> *) site.
MonadYesodExample site m =>
RequestBuilder site () -> m ()
request = YesodExample site () -> m ()
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample (YesodExample site () -> m ())
-> (RequestBuilder site () -> YesodExample site ())
-> RequestBuilder site ()
-> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RequestBuilder site () -> YesodExample site ()
forall site. RequestBuilder site () -> YesodExample site ()
Yesod.Test.request

-- | Set a language for the test Request
--
-- This uses a @_LANG@ query parameter since it's a singleton case, just to
-- exercise that machinery.
setLanguage :: BCP47 -> RequestBuilder site ()
setLanguage :: forall site. BCP47 -> RequestBuilder site ()
setLanguage = Text -> Text -> RequestBuilder site ()
forall site. Text -> Text -> RequestBuilder site ()
addGetParam Text
"_LANG" (Text -> RequestBuilder site ())
-> (BCP47 -> Text) -> BCP47 -> RequestBuilder site ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BCP47 -> Text
BCP47.toText

-- | Set the @Accept-Language@ header to a list of raw values
--
-- This allows testing with actual quality-factors, etc.
addAcceptLanguage :: [Text] -> RequestBuilder site ()
addAcceptLanguage :: forall site. [Text] -> RequestBuilder site ()
addAcceptLanguage [Text]
values =
  Header -> RequestBuilder site ()
forall site. Header -> RequestBuilder site ()
addRequestHeader (HeaderName
hAcceptLanguage, Text -> ByteString
encodeUtf8 (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> [Text] -> Text
T.intercalate Text
"," [Text]
values)

-- | Sets both @Content-Type@ and @Accept@ fields to @application/json@
addJsonHeaders :: RequestBuilder site ()
addJsonHeaders :: forall site. RequestBuilder site ()
addJsonHeaders = do
  Header -> RequestBuilder site ()
forall site. Header -> RequestBuilder site ()
addRequestHeader (HeaderName
hContentType, ByteString
"application/json")
  Header -> RequestBuilder site ()
forall site. Header -> RequestBuilder site ()
addRequestHeader (HeaderName
hAccept, ByteString
"application/json")

-- | Assert the last response status is as expected
--
-- If the status code doesn't match, a portion of the body is also
-- printed to aid in debugging.
statusIs
  :: forall m site. (MonadYesodExample site m, HasCallStack) => Int -> m ()
statusIs :: forall (m :: * -> *) site.
(MonadYesodExample site m, HasCallStack) =>
Int -> m ()
statusIs = YesodExample site () -> m ()
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample (YesodExample site () -> m ())
-> (Int -> YesodExample site ()) -> Int -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> YesodExample site ()
forall site. HasCallStack => Int -> YesodExample site ()
Yesod.Test.statusIs

-- | Assert that the given header field's value satisfied some predicate
assertHeaderSatisfies
  :: forall m site
   . MonadYesodExample site m
  => CI ByteString
  -- ^ Field name
  -> String
  -- ^ Some description of the predicate; this is included
  --   in the error message if the assertion fails
  -> (ByteString -> Bool)
  -- ^ Predicate applied to the field value which is expected
  --   to return 'True'
  -> m ()
assertHeaderSatisfies :: forall (m :: * -> *) site.
MonadYesodExample site m =>
HeaderName -> String -> (ByteString -> Bool) -> m ()
assertHeaderSatisfies HeaderName
header String
predicateDesc ByteString -> Bool
predicate = YesodExample site () -> m ()
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample (YesodExample site () -> m ()) -> YesodExample site () -> m ()
forall a b. (a -> b) -> a -> b
$ (SResponse -> YesodExample site ()) -> YesodExample site ()
forall site a.
HasCallStack =>
(SResponse -> YesodExample site a) -> YesodExample site a
withResponse ((SResponse -> YesodExample site ()) -> YesodExample site ())
-> (SResponse -> YesodExample site ()) -> YesodExample site ()
forall a b. (a -> b) -> a -> b
$ \SResponse
res ->
  case HeaderName -> [Header] -> Maybe ByteString
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup HeaderName
header ([Header] -> Maybe ByteString) -> [Header] -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ SResponse -> [Header]
simpleHeaders SResponse
res of
    Just ByteString
value | ByteString -> Bool
predicate ByteString
value -> () -> YesodExample site ()
forall a. a -> SIO (YesodExampleData site) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
    Just ByteString
value ->
      String -> YesodExample site ()
forall (m :: * -> *). (HasCallStack, MonadIO m) => String -> m ()
expectationFailure (String -> YesodExample site ()) -> String -> YesodExample site ()
forall a b. (a -> b) -> a -> b
$
        [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
          [ String
"Expected header "
          , HeaderName -> String
forall a. Show a => a -> String
show HeaderName
header
          , String
" "
          , String
predicateDesc
          , String
", but received "
          , ByteString -> String
forall a. Show a => a -> String
show ByteString
value
          ]
    Maybe ByteString
Nothing ->
      String -> YesodExample site ()
forall (m :: * -> *). (HasCallStack, MonadIO m) => String -> m ()
expectationFailure (String -> YesodExample site ()) -> String -> YesodExample site ()
forall a b. (a -> b) -> a -> b
$
        [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
          [ String
"Expected header "
          , HeaderName -> String
forall a. Show a => a -> String
show HeaderName
header
          , String
predicateDesc
          , String
", but it was not present"
          ]

-- | Assert that the given header field's value contains
--   some particular byte string within it
assertHeaderContains
  :: MonadYesodExample site m
  => CI ByteString
  -- ^ Field name
  -> ByteString
  -- ^ Substring that we expect to find anywhere within the field value
  -> m ()
assertHeaderContains :: forall site (m :: * -> *).
MonadYesodExample site m =>
HeaderName -> ByteString -> m ()
assertHeaderContains HeaderName
header ByteString
substring =
  HeaderName -> String -> (ByteString -> Bool) -> m ()
forall (m :: * -> *) site.
MonadYesodExample site m =>
HeaderName -> String -> (ByteString -> Bool) -> m ()
assertHeaderSatisfies
    HeaderName
header
    (String
"to contain " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> ByteString -> String
forall a. Show a => a -> String
show ByteString
substring)
    (ByteString
substring ByteString -> ByteString -> Bool
`BS.isInfixOf`)

-- | Assert the given header key/value pair was returned
assertHeader
  :: forall m site
   . MonadYesodExample site m
  => CI ByteString
  -- ^ Field name
  -> ByteString
  -- ^ Expected field value
  -> m ()
assertHeader :: forall (m :: * -> *) site.
MonadYesodExample site m =>
HeaderName -> ByteString -> m ()
assertHeader HeaderName
k ByteString
v = YesodExample site () -> m ()
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample (YesodExample site () -> m ()) -> YesodExample site () -> m ()
forall a b. (a -> b) -> a -> b
$ HeaderName -> ByteString -> YesodExample site ()
forall site.
HasCallStack =>
HeaderName -> ByteString -> YesodExample site ()
Yesod.Test.assertHeader HeaderName
k ByteString
v

-- | Follow a redirect, if the last response was a redirect
followRedirect
  :: forall m site
   . MonadYesodExample site m
  => m (Either Text Text)
  -- ^ Left with an error message if not a redirect,
  --   Right with the redirected URL if it was
followRedirect :: forall (m :: * -> *) site.
MonadYesodExample site m =>
m (Either Text Text)
followRedirect = YesodExample site (Either Text Text) -> m (Either Text Text)
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample YesodExample site (Either Text Text)
forall site. Yesod site => YesodExample site (Either Text Text)
Yesod.Test.followRedirect

-- | Perform a GET request to url
get
  :: forall url m site
   . (MonadYesodExample site m, RedirectUrl site url)
  => url
  -> m ()
get :: forall url (m :: * -> *) site.
(MonadYesodExample site m, RedirectUrl site url) =>
url -> m ()
get = YesodExample site () -> m ()
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample (YesodExample site () -> m ())
-> (url -> YesodExample site ()) -> url -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. url -> YesodExample site ()
forall site url.
(Yesod site, RedirectUrl site url) =>
url -> YesodExample site ()
Yesod.Test.get

-- | Perform a POST request to url
post
  :: forall url m site
   . (MonadYesodExample site m, RedirectUrl site url)
  => url
  -> m ()
post :: forall url (m :: * -> *) site.
(MonadYesodExample site m, RedirectUrl site url) =>
url -> m ()
post = YesodExample site () -> m ()
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample (YesodExample site () -> m ())
-> (url -> YesodExample site ()) -> url -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. url -> YesodExample site ()
forall site url.
(Yesod site, RedirectUrl site url) =>
url -> YesodExample site ()
Yesod.Test.post

-- | Get the foundation value used for the current test
getTestYesod :: forall m site. MonadYesodExample site m => m site
getTestYesod :: forall (m :: * -> *) site. MonadYesodExample site m => m site
getTestYesod = YesodExample site site -> m site
forall a. YesodExample site a -> m a
forall site (m :: * -> *) a.
MonadYesodExample site m =>
YesodExample site a -> m a
liftYesodExample YesodExample site site
forall site. YesodExample site site
Yesod.Test.getTestYesod