{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE UndecidableInstances #-}
module Freckle.App.Test.Yesod
(
MonadYesodExample (..)
, request
, RequestBuilder
, setMethod
, setUrl
, setRequestBody
, addGetParam
, addPostParam
, addRequestHeader
, addJsonHeaders
, setLanguage
, addAcceptLanguage
, addFile
, get
, post
, followRedirect
, getRawBody
, getCsvBody
, getJsonBody
, getResponse
, withResponse
, SResponse (..)
, statusIs
, assertHeader
, assertHeaderContains
, assertHeaderSatisfies
, bodyContains
, getRequestCookies
, testSetCookie
, testDeleteCookie
, testClearCookies
, SIO
, TestApp
, YesodExample
, YesodExampleData (..)
, getTestYesod
)
where
import Freckle.App.Prelude
import Blammo.Logging.Setup (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)
import Data.BCP47 (BCP47)
import Data.BCP47 qualified as BCP47
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.ByteString.Lazy qualified as BSL
import Data.CaseInsensitive (CI)
import Data.Csv qualified as CSV
import Data.Text qualified as T
import Data.Vector qualified as V
import Freckle.App.Test (expectationFailure)
import Network.HTTP.Types.Header (hAccept, hAcceptLanguage, hContentType)
import Network.Wai.Test (SResponse (..))
import Test.HUnit qualified as HUnit
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 Yesod.Test qualified
import Yesod.Test.Internal (getBodyTextPreview)
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
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
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
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
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
getJsonBody
:: forall a m site. (MonadYesodExample site m, FromJSON a, HasCallStack) => m a
getJsonBody :: forall a (m :: * -> *) site.
(MonadYesodExample site m, FromJSON a, HasCallStack) =>
m a
getJsonBody = 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 YesodExample site a
forall a site. (HasCallStack, FromJSON a) => YesodExample site a
Yesod.Test.requireJSONResponse
getCsvBody
:: forall a m site
. (MonadYesodExample site m, CSV.FromNamedRecord a, HasCallStack)
=> m [a]
getCsvBody :: forall a (m :: * -> *) site.
(MonadYesodExample site m, FromNamedRecord a, HasCallStack) =>
m [a]
getCsvBody =
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 (YesodExample site [a] -> m [a]) -> YesodExample site [a] -> m [a]
forall a b. (a -> b) -> a -> b
$
(SResponse -> YesodExample site [a]) -> YesodExample site [a]
forall site a.
HasCallStack =>
(SResponse -> YesodExample site a) -> YesodExample site a
withResponse ((SResponse -> YesodExample site [a]) -> YesodExample site [a])
-> (SResponse -> YesodExample site [a]) -> YesodExample site [a]
forall a b. (a -> b) -> a -> b
$ \(SResponse Status
_status ResponseHeaders
_headers ByteString
body) ->
case ((Header, Vector a) -> [a])
-> Either String (Header, Vector a) -> Either String [a]
forall a b. (a -> b) -> Either String a -> Either String b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (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) (ByteString -> Either String (Header, Vector a)
forall a.
FromNamedRecord a =>
ByteString -> Either String (Header, Vector a)
CSV.decodeByName ByteString
body) of
Left String
err ->
Text -> YesodExample site [a]
forall {m :: * -> *} {b}. MonadIO m => Text -> m b
failure (Text -> YesodExample site [a]) -> Text -> YesodExample site [a]
forall a b. (a -> b) -> a -> b
$
[Text] -> Text
T.concat
[ Text
"Failed to parse CSV response; error: "
, String -> Text
T.pack String
err
, Text
"CSV: "
, ByteString -> Text
getBodyTextPreview ByteString
body
]
Right [a]
v -> [a] -> YesodExample site [a]
forall a. a -> SIO (YesodExampleData site) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [a]
v
where
failure :: Text -> m b
failure Text
reason = do
Any
_ <- IO Any -> m Any
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Any -> m Any) -> IO Any -> m Any
forall a b. (a -> b) -> a -> b
$ String -> IO Any
forall a. HasCallStack => String -> IO a
HUnit.assertFailure (String -> IO Any) -> String -> IO Any
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
reason
String -> m b
forall a. HasCallStack => String -> a
error String
""
getRawBody
:: forall m site. (MonadYesodExample site m, HasCallStack) => m BSL.ByteString
getRawBody :: forall (m :: * -> *) site.
(MonadYesodExample site m, HasCallStack) =>
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
expectationFailure 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
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
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
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
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)
addJsonHeaders :: RequestBuilder site ()
= 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")
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
assertHeaderSatisfies
:: forall m site
. MonadYesodExample site m
=> CI ByteString
-> String
-> (ByteString -> Bool)
-> m ()
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 -> ResponseHeaders -> Maybe ByteString
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup HeaderName
header (ResponseHeaders -> Maybe ByteString)
-> ResponseHeaders -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ SResponse -> ResponseHeaders
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 :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
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 :: * -> *) a. (MonadIO m, HasCallStack) => String -> m a
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"
]
assertHeaderContains
:: MonadYesodExample site m
=> CI ByteString
-> ByteString
-> m ()
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 `BS.isInfixOf`)
assertHeader
:: forall m site
. MonadYesodExample site m
=> CI ByteString
-> ByteString
-> m ()
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
followRedirect
:: forall m site
. MonadYesodExample site m
=> m (Either Text Text)
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
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
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
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