Safe Haskell | Safe-Infered |
---|
Yesod.Test is a pragmatic framework for testing web applications built using wai and persistent.
By pragmatic I may also mean dirty
. It's main goal is to encourage integration
and system testing of web applications by making everything easy to test.
Your tests are like browser sessions that keep track of cookies and the last visited page. You can perform assertions on the content of HTML responses, using css selectors to explore the document more easily.
You can also easily build requests using forms present in the current page.
This is very useful for testing web applications built in yesod for example,
were your forms may have field names generated by the framework or a randomly
generated _nonce
field.
Your database is also directly available so you can use runDBRunner to set up backend pre-conditions, or to assert that your session is having the desired effect.
- runTests :: Application -> Pool conn -> SpecsConn conn -> IO ()
- describe :: String -> SpecsConn conn -> SpecsConn conn
- it :: String -> OneSpec conn () -> SpecsConn conn
- type SpecsConn conn = StateT (SpecsData conn) IO ()
- type OneSpec conn = StateT (OneSpecData conn) IO
- post :: ByteString -> RequestBuilder () -> OneSpec conn ()
- post_ :: ByteString -> OneSpec conn ()
- get :: ByteString -> RequestBuilder () -> OneSpec conn ()
- get_ :: ByteString -> OneSpec conn ()
- doRequest :: Method -> ByteString -> RequestBuilder a -> OneSpec conn ()
- byName :: Text -> Text -> RequestBuilder ()
- fileByName :: Text -> FilePath -> Text -> RequestBuilder ()
- byLabel :: Text -> Text -> RequestBuilder ()
- fileByLabel :: Text -> FilePath -> Text -> RequestBuilder ()
- addNonce :: RequestBuilder ()
- addNonce_ :: Query -> RequestBuilder ()
- runDBRunner :: (MonadBaseControl IO m, MonadIO m) => (poolrunner m a -> Pool conn -> IO a) -> poolrunner m a -> OneSpec conn a
- assertEqual :: Eq a => String -> a -> a -> OneSpec conn ()
- assertHeader :: HoldsResponse a => CI ByteString -> ByteString -> StateT a IO ()
- assertNoHeader :: HoldsResponse a => CI ByteString -> StateT a IO ()
- statusIs :: HoldsResponse a => Int -> StateT a IO ()
- bodyEquals :: HoldsResponse a => String -> StateT a IO ()
- bodyContains :: HoldsResponse a => String -> StateT a IO ()
- htmlAllContain :: HoldsResponse a => Query -> String -> StateT a IO ()
- htmlCount :: HoldsResponse a => Query -> Int -> StateT a IO ()
- printBody :: HoldsResponse a => StateT a IO ()
- printMatches :: HoldsResponse a => Query -> StateT a IO ()
- htmlQuery :: HoldsResponse a => Query -> StateT a IO [Html]
- parseHTML :: Html -> Cursor
- withResponse :: HoldsResponse a => (SResponse -> StateT a IO b) -> StateT a IO b
Declaring and running your test suite
runTests :: Application -> Pool conn -> SpecsConn conn -> IO ()Source
Runs your test suite, using you wai Application
and ConnectionPool
for performing
the database queries in your tests.
You application may already have your connection pool but you need to pass another one separately here.
Look at the examples directory on this package to get an idea of the (small) amount of boilerplate code you'll need to write before calling this.
describe :: String -> SpecsConn conn -> SpecsConn connSource
Start describing a Tests suite keeping cookies and a reference to the tested Application
and ConnectionPool
it :: String -> OneSpec conn () -> SpecsConn connSource
Describe a single test that keeps cookies, and a reference to the last response.
type SpecsConn conn = StateT (SpecsData conn) IO ()Source
The specs state monad is where describe
runs.
parameterized by a database connection.
You should create type Specs = SpecsConn MyDBConnection
Making requests
To make a request you need to point to an url and pass in some parameters.
To build your parameters you will use the RequestBuilder monad that lets you add values, add files, lookup fields by label and find the current nonce value and add it to your request too.
post :: ByteString -> RequestBuilder () -> OneSpec conn ()Source
Perform a POST request to url, using params
post_ :: ByteString -> OneSpec conn ()Source
Perform a POST request without params
get :: ByteString -> RequestBuilder () -> OneSpec conn ()Source
Perform a GET request to url, using params
get_ :: ByteString -> OneSpec conn ()Source
Perform a GET request without params
doRequest :: Method -> ByteString -> RequestBuilder a -> OneSpec conn ()Source
General interface to performing requests, letting you specify the request method and extra headers.
fileByName :: Text -> FilePath -> Text -> RequestBuilder ()Source
Add a file to be posted with the current request
Adding a file will automatically change your request content-type to be multipart/form-data
Yesod cat auto generate field ids, so you are never sure what the argument name should be for each one of your args when constructing your requests. What you do know is the label of the field. These functions let you add parameters to your request based on currently displayed label names.
Does the current form have a _nonce? Use any of these to add it to your request parameters.
addNonce :: RequestBuilder ()Source
For responses that display a single form, just lookup the only nonce available.
addNonce_ :: Query -> RequestBuilder ()Source
Lookup a _nonce form field and add it's value to the params. Receives a CSS selector that should resolve to the form element containing the nonce.
Running database queries
runDBRunner :: (MonadBaseControl IO m, MonadIO m) => (poolrunner m a -> Pool conn -> IO a) -> poolrunner m a -> OneSpec conn aSource
Run a persistent db query. For asserting on the results of performed actions or setting up pre-conditions. At the moment this part is still very raw.
It is intended that you parametize the first argument of this function for your backend runDB = runDBRunnder SqlPersist
Assertions
assertEqual :: Eq a => String -> a -> a -> OneSpec conn ()Source
Asserts that the two given values are equal.
assertHeader :: HoldsResponse a => CI ByteString -> ByteString -> StateT a IO ()Source
Assert the given header key/value pair was returned.
assertNoHeader :: HoldsResponse a => CI ByteString -> StateT a IO ()Source
Assert the given header was not included in the response.
statusIs :: HoldsResponse a => Int -> StateT a IO ()Source
Assert the last response status is as expected.
bodyEquals :: HoldsResponse a => String -> StateT a IO ()Source
Assert the last response is exactly equal to the given text. This is useful for testing API responses.
bodyContains :: HoldsResponse a => String -> StateT a IO ()Source
Assert the last response has the given text. The check is performed using the response body in full text form.
htmlAllContain :: HoldsResponse a => Query -> String -> StateT a IO ()Source
Queries the html using a css selector, and all matched elements must contain the given string.
htmlCount :: HoldsResponse a => Query -> Int -> StateT a IO ()Source
Performs a css query on the last response and asserts the matched elements are as many as expected.
Utils for debugging tests
printBody :: HoldsResponse a => StateT a IO ()Source
Outputs the last response body to stderr (So it doesn't get captured by HSpec)
printMatches :: HoldsResponse a => Query -> StateT a IO ()Source
Performs a CSS query and print the matches to stderr.
Utils for building your own assertions
Please consider generalizing and contributing the assertions you write.
htmlQuery :: HoldsResponse a => Query -> StateT a IO [Html]Source
Query the last response using css selectors, returns a list of matched fragments