How to test Scotty endpoints

188 views Asked by At

With the following Scotty endpoint:

myendpoint :: Text -> ScottyM ()
myendpoint info =
    post "/foo/bar/:var" $ do
        var :: Text <- param "var"
        query :: Query <- jsonData
        result <- liftIO $ retrieveResult info var query
        json $ result

runApi :: IO ()
runApi = scotty 4602 $ do
    myendpoint

How to test myendpoint with different possible inputs, for instance

info1 = "foo"
query1 = Query { qParam1 = "foo", qParam2 = "bar" }
var1 = "bar"
expect1 = Result { foo = "foo", bar = "bar" }

res1 = decode $ test_myendpoint info1 query1 var1
res1 `shouldBe` expect1

info2 = "baz"
query2 = Query { qParam1 = "hello", qParam2 = "there" }
var2 = "boo"
expect2 = Result { foo = "biz", bar = "dev" }

res2 = decode $ test_myendpoint info2 query2 var2
res2 `shouldBe` expect2

I'm tempted to simply run the API in another thread, then query the endpoint for real with some JSON, but is there a cleaner way to do this? (although the benefit of the above would be real end-to-end testing)

1

There are 1 answers

0
Jivan On

Found the answer. Need to import hspec-wai and hspec-wai-json.

Then instead of running the api directly, we create an api function that returns an IO Application, and then another runApi function that actually runs the thing.

import           Network.Wai                 (Application)
import           Network.Wai.Handler.Warp    (run)

api :: IO Application
api = scottyApp $ do
    myendpoint

runApi :: IO ()
runApi =
    api >>= run 460

Now we're free to use with api in the tests:

import           Test.Hspec
import           Test.Hspec.Wai      as W
import           Test.Hspec.Wai.JSON

spec :: Spec
spec = with api $ do
    describe "testing some endpoint" $ do
        it "should return correct data" $ do
            get "/foo/bar/whatever" `shouldRespondWith`
                [json|{foo: "foo", bar: "bar"}|]