Test Snap Web Framework Handler

606 views Asked by At

I want to write little integration tests for my Snap web handlers but I am stuck. Here is the scenario. I have a Snap web handler that (run-of-the-mill style) CRUDs up a type and it looks something like this:

create :: AppHandler ()
create = method POST $ do
         lastName  <- decodeUtf8 . fromJust <$> getParam "lastName"
         firstName <- decodeUtf8 . fromJust <$> getParam "firstName"
         createPerson $ Person firstName lastName
         modifyResponse (setResponseCode 204)

The Snap.Test module has some things to help build up a request and I use it to make a request for my handler:

createOwnerReq :: RequestBuilder IO () 
createOwnerReq = postUrlEncoded "host/person/create" $
                 fromList [ ("firstName", ["Greg-Shaw"])
                          , ("lastName",  ["Snoy'Sullivan"])
                          ]

Here's the problem, I want to make a TestUnit TestCase for this handler so I need the run the handler on the createOwnerReq request. The module Snap.Test provides:

 runHandler :: MonadIO a => RequestBuilder m () -> Snap a -> m Response

so

 ... do 
     resp <- runHandler createOwnerReq ??? 

But wait!!! My request handler is of type AppHandler () but runHandler requires a Handler of type Snap a. How do I lift my AppHandler type into the Snap monad? Help please, this is kind of trippin' me out.

1

There are 1 answers

0
mightybyte On

Ibolla's return create trick probably doesn't do what you want. It compiles correctly because runHandler takes a Snap a which will work on a Snap action with any return value. return create :: Snap (AppHandler ()), which is very different from the Snap () that you were probably expecting.

We are working on a Snap.Snaplet.Test equivalent that will wrap the runHandler function provided by Snap.Test to allow you to test Handlers. This will probably be included in the 0.10 release of the snap package.

In the interim, you can solve the problem manually by using runSnaplet to convert your SnapletInit into a Snap () action that can be passed to Snap.Test.runHandler. This won't let you test an individual Handler, but it will let you test any of the routes defined in your application's initializer.

EDIT: In snap-0.10, we added test support for snaplets.