Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Equivalent of withApplication with app wrapped in IO (e.g. for Scotty) #58

Open
tomasaschan opened this issue Nov 18, 2019 · 1 comment

Comments

@tomasaschan
Copy link

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

  1. set some initial app state
  2. make an http call
  3. verify stuff about the response
  4. 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!

@tomasaschan
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant