More specifically, I'm looking for a function of type:

f :: site -> SpecM (TestApp site) b -> IO b

or similar.

In other words, I am looking for the inverse function of:

liftIO :: IO b -> SpecM (TestApp _site) b

I've looked in the Yesod.Test docs and source code and tried to construct it myself too, but I don't seem to find it anywhere and it doesn't seem to be simple to construct either. Have I overlooked something, and might it exist somewhere? Or could it be simple to construct in a way I have not considered?

Background

I've run into the need for such a function multiple times, but so far I've always been able to workaround or do without. But in my latest situation it doesn't seem possible to work around: I want to write a Monadic QuickCheck property that would set up an arbitrary db environment (runDB . insert) and run some handlers on it to test for certain invariants of my application.

This is the farthest I've gotten with my attempts:

propSpec = do
  context "qt" $ do
    it "monadic" $ property $ \a b -> monadicIO $ do
      run $ withServer $ \site -> yesodSpec site $ runDB $ insert $ User{..}
      assert $ a /= b

withServer cont = do
  p <- runLogging $ withSqlitePool "database_test.db3" 10 $ \pool -> do
    runSqlPool (runMigration migrateAll) pool
    return pool

  wipeDB (MyApp p)

  cont (MyApp p, id)

Which, somewhat understandably, results in the following type error:

/path/to/project/spec/Spec.hs:301:35: error:
    • Couldn't match type ‘hspec-core-2.2.4:Test.Hspec.Core.Spec.Monad.SpecM
                             () ()’
                     with ‘IO a0’
      Expected type: IO a0
        Actual type: Spec
    • In the expression:
        yesodSpec site $ runDB $ insert $ User{..}
      In the second argument of ‘($)’, namely
        ‘\ site
           -> yesodSpec site $ runDB $ insert $ User{..}’
      In the second argument of ‘($)’, namely
        ‘withServer
         $ \ site
             -> yesodSpec site $ runDB $ insert $ User{..}’

/path/to/project/spec/Spec.hs:301:52: error:
    • Couldn't match type ‘ST.StateT
                             (YesodExampleData MyApp) IO (Key User)’
                     with ‘transformers-0.5.2.0:Control.Monad.Trans.Writer.Lazy.WriterT
                             [YesodSpecTree (MyApp, a1 -> a1)]
                             Data.Functor.Identity.Identity
                             ()’
      Expected type: YesodSpec (MyApp, a1 -> a1)
        Actual type: YesodExample MyApp (Key User)
    • In the second argument of ‘($)’, namely
        ‘runDB $ insert $ User{..}’
      In the expression:
        yesodSpec site $ runDB $ insert $ User{..}
      In the second argument of ‘($)’, namely
        ‘\ site
           -> yesodSpec site $ runDB $ insert $ User{..}’
    • Relevant bindings include
        site :: (MyApp, a1 -> a1)
          (bound at /path/to/project/spec/Spec.hs:301:27)

Any ideas?

Also, has anyone before used Test.QuickCheck.Monadic successfully in conjunction with Yesod.Test? Or if perhaps not successfully, at least attempted to do so?

0

There are 0 best solutions below