Equivalent of withApplication with app wrapped in IO (e.g. for Scotty)
tomasaschan opened this issue · comments
Hello! Haskell newbie here :) I'm learning how to build a web API in Haskell, and I'm stumbling on figuring out the correct way to test my app. What I want to accomplish is basically to
- set some initial app state
- make an http call
- verify stuff about the response
- verify stuff about the state after the request returns
For now, I don't mind if the test runner has to run the entire cycle for each verification, so 3. and 4. could be lumped together into "verify something about the response or the app state after the action".
I've looked at the examples posted in #36 (as well as in a bunch of other places) but I'm only almost getting all the pieces in place to start writing real tests. The problem I'm currently facing is that in #36, the mkApplication
is of type Connection -> Application
, which seems to follow from the OP there using Servant. I'm using Scotty, where my corresponding function type is MyState -> IO Application
, and I can't figure out how to make that IO
match up with the stuff around it.
Here's my attempt at defining a Spec
:
mkState :: IO (TVar MyState)
mkState = liftIO $ newTVarIO (def :: MyState)
mkApp :: TVar MyState -> IO Network.Wai.Application
mkApp s = scottyAppT (runWithState s) myApp
where
-- WebM is defined as here: https://github.com/scotty-web/scotty/blob/master/examples/globalstate.hs
runWithState :: TVar MyState -> WebM a -> IO a
runWithState s = \m -> runReaderT (runWebM m) s
spec :: Spec
spec = do
before mkState $ do
it "get /" $ \s -> do
withApplication (mkApp s) $ do
Test.Hspec.Wai.pending -- e.g. get "/" `shouldRespondWith` 200
-- or do s' <- readTVar s
getStuff s `shouldBe` expectedStuff
The above snippet fails to build because mkApp s
is expected to return an Application
, but returns an IO Application
. I bet I'm missing something fairly trivial, but I haven't been able to figure out what.
Grateful for all help!
Here's a different sample, that also fails to build:
spec :: Spec
spec = do
before mkSt $ do
it "get /" $ \s -> do
with (mkApp s) $ do
get "/" `shouldRespondWith` 200
This time, it's the last line (get "/" ...
) that fails, because it is of type WaiExpectation
and not SpecWith Application
.