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 runDB to set up backend pre-conditions, or to assert that your session is having the desired effect.
- runTests :: Application -> ConnectionPool -> Specs -> IO a
- describe :: String -> Specs -> Specs
- it :: String -> OneSpec () -> Specs
- type Specs = StateT SpecsData IO ()
- type OneSpec = StateT OneSpecData IO
- post :: ByteString -> RequestBuilder () -> OneSpec ()
- post_ :: ByteString -> OneSpec ()
- get :: ByteString -> RequestBuilder () -> OneSpec ()
- get_ :: ByteString -> OneSpec ()
- doRequest :: Method -> ByteString -> RequestBuilder a -> OneSpec ()
- byName :: String -> String -> RequestBuilder ()
- fileByName :: String -> FilePath -> String -> RequestBuilder ()
- byLabel :: String -> String -> RequestBuilder ()
- fileByLabel :: String -> FilePath -> String -> RequestBuilder ()
- addNonce :: RequestBuilder ()
- addNonce_ :: Query -> RequestBuilder ()
- runDB :: SqlPersist IO a -> OneSpec a
- assertEqual :: Eq a => String -> a -> a -> OneSpec ()
- 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 -> LA XmlTree a -> [a]
- withResponse :: HoldsResponse a => (SResponse -> StateT a IO b) -> StateT a IO b
Declaring and running your test suite
runTests :: Application -> ConnectionPool -> Specs -> IO aSource
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 -> Specs -> SpecsSource
Start describing a Tests suite keeping cookies and a reference to the tested Application
and ConnectionPool
it :: String -> OneSpec () -> SpecsSource
Describe a single test that keeps cookies, and a reference to the last response.
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 ()Source
Perform a POST request to url, using params
post_ :: ByteString -> OneSpec ()Source
Perform a POST request without params
get :: ByteString -> RequestBuilder () -> OneSpec ()Source
Perform a GET request to url, using params
get_ :: ByteString -> OneSpec ()Source
Perform a GET request without params
doRequest :: Method -> ByteString -> RequestBuilder a -> OneSpec ()Source
General interface to performing requests, letting you specify the request method and extra headers.
fileByName :: String -> FilePath -> String -> 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
runDB :: SqlPersist IO a -> OneSpec 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.
Assertions
assertEqual :: Eq a => String -> a -> a -> OneSpec ()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