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?