Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Testing a yesod site.
For a fully-worked example, see sydtest-yesod/blog-example.
Synopsis
- yesodSpec :: YesodDispatch site => site -> YesodSpec site -> Spec
- yesodSpecWithSiteGenerator :: YesodDispatch site => IO site -> YesodSpec site -> Spec
- yesodSpecWithSiteGeneratorAndArgument :: YesodDispatch site => (a -> IO site) -> YesodSpec site -> SpecWith a
- yesodSpecWithSiteSupplier :: YesodDispatch site => (forall r. (site -> IO r) -> IO r) -> YesodSpec site -> Spec
- yesodSpecWithSiteSupplierWith :: YesodDispatch site => (forall r. (site -> IO r) -> inner -> IO r) -> YesodSpec site -> SpecWith inner
- yesodSpecWithSiteSetupFunc :: YesodDispatch site => (Manager -> SetupFunc site) -> TestDef (Manager ': outers) (YesodClient site) -> TestDef (Manager ': outers) ()
- yesodSpecWithSiteSetupFunc' :: YesodDispatch site => (Manager -> inner -> SetupFunc site) -> TestDef (Manager ': outers) (YesodClient site) -> TestDef (Manager ': outers) inner
- yesodClientSetupFunc :: YesodDispatch site => Manager -> site -> SetupFunc (YesodClient site)
- yesodE2ESpec :: URI -> YesodSpec (E2E site) -> Spec
- yesodE2ESpec' :: URI -> YesodSpec (E2E site) -> TestDef '[Manager] ()
- data E2E site = E2E
- localToE2ESpec :: YesodSpec (E2E site) -> YesodSpec site
- localToE2EClient :: YesodClient site -> YesodClient (E2E site)
- type YesodSpec site = TestDef '[Manager] (YesodClient site)
- data YesodClient site = YesodClient {
- yesodClientSite :: !site
- yesodClientManager :: !Manager
- yesodClientSiteURI :: !URI
- data YesodClientState = YesodClientState {}
- newtype YesodClientM site a = YesodClientM {
- unYesodClientM :: StateT YesodClientState (ReaderT (YesodClient site) IO) a
- runYesodClientM :: YesodClient site -> YesodClientM site a -> IO a
- type YesodExample site a = YesodClientM site a
- yit :: forall site. HasCallStack => String -> YesodClientM site () -> YesodSpec site
- ydescribe :: String -> YesodSpec site -> YesodSpec site
- get :: (Yesod site, RedirectUrl site url) => url -> YesodClientM site ()
- post :: (Yesod site, RedirectUrl site url) => url -> YesodClientM site ()
- followRedirect :: Yesod site => YesodExample site (Either Text Text)
- followRedirect_ :: Yesod site => YesodExample site ()
- request :: RequestBuilder site a -> YesodClientM site ()
- setUrl :: (Yesod site, RedirectUrl site url) => url -> RequestBuilder site ()
- setMethod :: Method -> RequestBuilder site ()
- addRequestHeader :: Header -> RequestBuilder site ()
- addGetParam :: Text -> Text -> RequestBuilder site ()
- addPostParam :: Text -> Text -> RequestBuilder site ()
- addFile :: Text -> FilePath -> Text -> RequestBuilder site ()
- addFileWith :: Text -> FilePath -> ByteString -> Maybe Text -> RequestBuilder site ()
- setRequestBody :: ByteString -> RequestBuilder site ()
- performMethod :: (Yesod site, RedirectUrl site url) => Method -> url -> YesodClientM site ()
- performRequest :: Request -> YesodClientM site ()
- newtype RequestBuilder site a = RequestBuilder {
- unRequestBuilder :: StateT (RequestBuilderData site) (YesodClientM site) a
- runRequestBuilder :: RequestBuilder site a -> YesodClientM site Request
- addToken :: HasCallStack => RequestBuilder site ()
- addToken_ :: HasCallStack => Text -> RequestBuilder site ()
- addTokenFromCookie :: HasCallStack => RequestBuilder site ()
- addTokenFromCookieNamedToHeaderNamed :: HasCallStack => ByteString -> CI ByteString -> RequestBuilder site ()
- getStatus :: YesodClientM site (Maybe Int)
- requireStatus :: YesodClientM site Int
- getRequest :: YesodClientM site (Maybe Request)
- requireRequest :: YesodClientM site Request
- getResponse :: YesodClientM site (Maybe (Response ByteString))
- requireResponse :: YesodClientM site (Response ByteString)
- getLocation :: ParseRoute site => YesodClientM localSite (Either Text (Route site))
- requireLocation :: ParseRoute site => YesodClientM localSite (Route site)
- getLast :: YesodClientM site (Maybe (Request, Response ByteString))
- requireLast :: YesodClientM site (Request, Response ByteString)
- statusShouldBe :: HasCallStack => Int -> YesodClientM site ()
- locationShouldBe :: (ParseRoute site, Show (Route site)) => Route site -> YesodClientM localSite ()
- bodyContains :: HasCallStack => String -> YesodExample site ()
- statusIs :: HasCallStack => Int -> YesodClientM site ()
- module Test.Syd.Yesod.Client
- module Test.Syd.Yesod.Def
- module Test.Syd.Yesod.Request
- module Test.Syd.Yesod.E2E
- module Network.HTTP.Types
- module Network.HTTP.Client
Functions to run a test suite
Tests against a local instance of a site
yesodSpec :: YesodDispatch site => site -> YesodSpec site -> Spec Source #
Run a test suite using the given site
.
If your site
contains any resources that need to be set up, you probably want to be using one of the following functions instead.
Example usage with a minimal yesod App
:
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} module Minimal where import Yesod import Test.Syd data App = App -- | Empty App type mkYesod "App" [parseRoutes| / HomeR GET |] instance Yesod App getHomeR :: Handler Html getHomeR = "Hello, world!" main :: IO () main = Yesod.warp 3000 App testMain :: IO () testMain = sydTest spec spec :: Spec spec = yesodSpec App $ do it "returns 200 on the homepage" $ do get HomeR statusIs 200
This function exists for backward compatibility with yesod-test.
yesodSpecWithSiteGenerator :: YesodDispatch site => IO site -> YesodSpec site -> Spec Source #
Run a test suite using the given site
generator.
If your site
contains any resources that you will want to have set up beforhand, you will probably want to use yesodSpecWithSiteGeneratorAndArgument
or yesodSpecWithSiteSupplierWith
instead.
Example usage with a yesod App
that contains a secret key that is generated at startup but not used during tests:
data Key = Key -- The implementation of the actual key is omitted here for brevity. genKey :: IO Key genKey = pure Key data App = App { appSecretKey :: Key } genApp :: IO App genApp = App <$> genKey main :: IO () main = sydTest spec spec :: Spec spec = yesodSpecWithSiteGenerator genApp $ do it "returns 200 on the homepage" $ do get HomeR statusIs 200
This function exists for backward compatibility with yesod-test.
yesodSpecWithSiteGeneratorAndArgument :: YesodDispatch site => (a -> IO site) -> YesodSpec site -> SpecWith a Source #
Run a test suite using the given site
generator which uses an inner resource.
If your site
contains any resources that you need to set up using a withX
function, you will want to use yesodSpecWithSiteSupplier
instead.
This function exists for backward compatibility with yesod-test.
yesodSpecWithSiteSupplier :: YesodDispatch site => (forall r. (site -> IO r) -> IO r) -> YesodSpec site -> Spec Source #
Using a function that supplies a site
, run a test suite.
Example usage with a yesod App
that contains an sqlite database connection. See 'sydtest-persistent-sqlite'.
import Test.Syd.Persistent.Sqlite data App = App { appConnectionPool :: ConnectionPool } main :: IO () main = sydTest spec appSupplier :: (App -> IO r) -> IO r appSupplier func = withConnectionPool myMigration $ \pool -> func $ App { appConnectionPool = pool} spec :: Spec spec = yesodSpecWithSiteSupplier appSupplier $ do it "returns 200 on the homepage" $ do get HomeR statusIs 200
yesodSpecWithSiteSupplierWith :: YesodDispatch site => (forall r. (site -> IO r) -> inner -> IO r) -> YesodSpec site -> SpecWith inner Source #
Using a function that supplies a site
, based on an inner resource, run a test suite.
yesodSpecWithSiteSetupFunc :: YesodDispatch site => (Manager -> SetupFunc site) -> TestDef (Manager ': outers) (YesodClient site) -> TestDef (Manager ': outers) () Source #
Using a function that supplies a site
, using a SetupFunc
This function assumed that you've already set up the Manager
beforehand using something like managerSpec
.
yesodSpecWithSiteSetupFunc' :: YesodDispatch site => (Manager -> inner -> SetupFunc site) -> TestDef (Manager ': outers) (YesodClient site) -> TestDef (Manager ': outers) inner Source #
Using a function that supplies a site
, using a SetupFunc
.
This function assumed that you've already set up the Manager
beforehand using something like managerSpec
.
Setup functions
yesodClientSetupFunc :: YesodDispatch site => Manager -> site -> SetupFunc (YesodClient site) Source #
Tests against a remote instance of a site
yesodE2ESpec :: URI -> YesodSpec (E2E site) -> Spec Source #
Run an end-to-end yesod test suite against a remote server at the given URI
.
If you would like to write tests that can be run against both a local and a remote instance of your site, you can use the following type:
mySpec :: (Yesod site, RedirectUrl site (Route App)) => YesodSpec site mySpec = do it "responds 200 OK to GET HomeR" $ do get HomeR statusIs 200
yesodE2ESpec' :: URI -> YesodSpec (E2E site) -> TestDef '[Manager] () Source #
Like yesodE2ESpec
, but doesn't set up the Manager
for you.
If you are running the end-to-end test against a server that uses
https://
, make sure to use a TLS-enabled Manager
.
You can do this using beforeAll newTlsManager
.
A dummy type that is an instance of Yesod
, with as a phantom type, the app that it represents.
That is to say, E2E site
is an instance of Yesod
that pretends to be a
site
. You can treat it as a site
in end-to-end tests, except that you
cannot use the site
value because there is none in there.
Instances
localToE2ESpec :: YesodSpec (E2E site) -> YesodSpec site Source #
See localToE2EClient
Turn an end-to-end yesod test suite into a local yesod test suite by treating a local instance as remote.
localToE2EClient :: YesodClient site -> YesodClient (E2E site) Source #
Turn a local 'YesodClient site' into a remote 'YesodClient (E2E site)'.
Core
type YesodSpec site = TestDef '[Manager] (YesodClient site) Source #
For backward compatibility with yesod-test
data YesodClient site Source #
A client environment to call a Yesod app.
YesodClient | |
|
Instances
data YesodClientState Source #
The state that is maintained throughout a YesodClientM
YesodClientState | |
|
Instances
Generic YesodClientState Source # | |
Defined in Test.Syd.Yesod.Client type Rep YesodClientState :: Type -> Type # from :: YesodClientState -> Rep YesodClientState x # to :: Rep YesodClientState x -> YesodClientState # | |
MonadState YesodClientState (YesodClientM site) Source # | |
Defined in Test.Syd.Yesod.Client get :: YesodClientM site YesodClientState # put :: YesodClientState -> YesodClientM site () # state :: (YesodClientState -> (a, YesodClientState)) -> YesodClientM site a # | |
type Rep YesodClientState Source # | |
Defined in Test.Syd.Yesod.Client type Rep YesodClientState = D1 ('MetaData "YesodClientState" "Test.Syd.Yesod.Client" "sydtest-yesod-0.3.0.2-KtanN3rUmDp9Q8nAuuA5iX" 'False) (C1 ('MetaCons "YesodClientState" 'PrefixI 'True) (S1 ('MetaSel ('Just "yesodClientStateLast") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 (Maybe (Request, Response ByteString))) :*: S1 ('MetaSel ('Just "yesodClientStateCookies") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 CookieJar))) |
newtype YesodClientM site a Source #
A monad to call a Yesod app.
This has access to a 'YesodClient site'.
YesodClientM | |
|
Instances
runYesodClientM :: YesodClient site -> YesodClientM site a -> IO a Source #
Run a YesodClientM site using a YesodClient site
type YesodExample site a = YesodClientM site a Source #
For backward compatibility
Helper functions to define tests
yit :: forall site. HasCallStack => String -> YesodClientM site () -> YesodSpec site Source #
ydescribe :: String -> YesodSpec site -> YesodSpec site Source #
For compatibility with yesod-test
ydescribe = describe
Making requests
get :: (Yesod site, RedirectUrl site url) => url -> YesodClientM site () Source #
Make a GET
request for the given route
it "returns 200 on the home route" $ do get HomeR statusIs 200
post :: (Yesod site, RedirectUrl site url) => url -> YesodClientM site () Source #
Make a POST
request for the given route
it "returns 200 on the start processing route" $ do post StartProcessingR statusIs 200
:: Yesod site | |
=> YesodExample site (Either Text Text) |
|
Follow a redirect, if the last response was a redirect.
(We consider a request a redirect if the status is 301, 302, 303, 307 or 308, and the Location header is set.)
it "redirects home" $ do get RedirectHomeR statusIs 303 locationShouldBe HomeR _ <- followRedirect statusIs 200
followRedirect_ :: Yesod site => YesodExample site () Source #
Using the request builder
request :: RequestBuilder site a -> YesodClientM site () Source #
Perform the request that is built by the given RequestBuilder
.
it "returns 200 on this post request" $ do request $ do setUrl StartProcessingR setMethod "POST" addPostParam "key" "value" statusIs 200
setUrl :: (Yesod site, RedirectUrl site url) => url -> RequestBuilder site () Source #
Set the url of the RequestBuilder
to the given route.
setMethod :: Method -> RequestBuilder site () Source #
Set the method of the RequestBuilder
.
addRequestHeader :: Header -> RequestBuilder site () Source #
Add the given request header to the RequestBuilder
.
addGetParam :: Text -> Text -> RequestBuilder site () Source #
Add the given GET parameter to the RequestBuilder
.
addPostParam :: Text -> Text -> RequestBuilder site () Source #
Add the given POST parameter to the RequestBuilder
.
:: Text | The parameter name for the file. |
-> FilePath | The path to the file. |
-> Text | The MIME type of the file, e.g. "image/png". |
-> RequestBuilder site () |
:: Text | The parameter name for the file. |
-> FilePath | The path to the file. |
-> ByteString | The contents of the file. |
-> Maybe Text | The MIME type of the file, e.g. "image/png". |
-> RequestBuilder site () |
setRequestBody :: ByteString -> RequestBuilder site () Source #
Set the request body of the RequestBuilder
.
Note that this invalidates any of the other post parameters that may have been set.
Helpers
performMethod :: (Yesod site, RedirectUrl site url) => Method -> url -> YesodClientM site () Source #
Perform a request using an arbitrary method for the given route.
performRequest :: Request -> YesodClientM site () Source #
Perform the given request as-is.
Note that this function does not check whether you are making a request to the site under test. You could make a request to https://example.com if you wanted.
Types
newtype RequestBuilder site a Source #
A request builder monad that allows you to monadically build a request using runRequestBuilder
.
This request builder has access to the entire YesodClientM
underneath.
This includes the Site
under test, as well as cookies etc.
See YesodClientM
for more details.
RequestBuilder | |
|
Instances
runRequestBuilder :: RequestBuilder site a -> YesodClientM site Request Source #
Run a RequestBuilder
to make the Request
that it defines.
Token
addToken :: HasCallStack => RequestBuilder site () Source #
Look up the CSRF token from the only form data and add it to the request header
addToken_ :: HasCallStack => Text -> RequestBuilder site () Source #
Look up the CSRF token from the given form data and add it to the request header
addTokenFromCookie :: HasCallStack => RequestBuilder site () Source #
Look up the CSRF token from the cookie with name defaultCsrfCookieName
and add it to the request header with name defaultCsrfHeaderName
.
addTokenFromCookieNamedToHeaderNamed Source #
:: HasCallStack | |
=> ByteString | The name of the cookie |
-> CI ByteString | The name of the header |
-> RequestBuilder site () |
Looks up the CSRF token stored in the cookie with the given name and adds it to the given request header.
Queries
getStatus :: YesodClientM site (Maybe Int) Source #
Get the status of the most recently received response.
requireStatus :: YesodClientM site Int Source #
Get the status of the most recently received response, and assert that it already exists.
getRequest :: YesodClientM site (Maybe Request) Source #
Get the most recently sent request.
requireRequest :: YesodClientM site Request Source #
Get the most recently sent request.
getResponse :: YesodClientM site (Maybe (Response ByteString)) Source #
Get the most recently received response.
requireResponse :: YesodClientM site (Response ByteString) Source #
Get the most recently received response, and assert that it already exists.
getLocation :: ParseRoute site => YesodClientM localSite (Either Text (Route site)) Source #
Get the Location
header of most recently received response.
requireLocation :: ParseRoute site => YesodClientM localSite (Route site) Source #
Get the Location
header of most recently received response, and assert that it is a valid Route.
getLast :: YesodClientM site (Maybe (Request, Response ByteString)) Source #
Get the most recently sent request and the response to it.
requireLast :: YesodClientM site (Request, Response ByteString) Source #
Get the most recently sent request and the response to it, and assert that they already exist.
Declaring assertions
statusShouldBe :: HasCallStack => Int -> YesodClientM site () Source #
Assert the status of the most recently received response.
it "returns 200 on the home route" $ do get HomeR statusShouldBe 200
locationShouldBe :: (ParseRoute site, Show (Route site)) => Route site -> YesodClientM localSite () Source #
Assert the redirect location of the most recently received response.
it "redirects to the overview on the home route" $ do get HomeR statusIs 301 locationShouldBe OverviewR
bodyContains :: HasCallStack => String -> YesodExample site () Source #
Assert the last response has the given text.
The check is performed using the response body in full text form without any html parsing.
statusIs :: HasCallStack => Int -> YesodClientM site () Source #
Synonym of statusShouldBe
for compatibility with yesod-test
Just to be sure we didn't forget any exports
module Test.Syd.Yesod.Client
module Test.Syd.Yesod.Def
module Test.Syd.Yesod.Request
module Test.Syd.Yesod.E2E
Reexports
module Network.HTTP.Types
module Network.HTTP.Client