tasty-wai (empty) → 0.1.0.0
raw patch · 6 files changed
+267/−0 lines, 6 filesdep +basedep +bytestringdep +http-typessetup-changed
Dependencies added: base, bytestring, http-types, tasty, tasty-wai, wai, wai-extra
Files
- CHANGELOG.md +5/−0
- LICENCE +31/−0
- Setup.hs +2/−0
- src/Test/Tasty/Wai.hs +116/−0
- tasty-wai.cabal +63/−0
- test/Test.hs +50/−0
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for tasty-wai++## 0.1.0.0 -- 2018-12-04++* First version. Released on an unsuspecting world.
+ LICENCE view
@@ -0,0 +1,31 @@+Copyright (c) 2018, Commonwealth Scientific and Industrial Research Organisation+(CSIRO) ABN 41 687 119 230.++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of QFPL nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Test/Tasty/Wai.hs view
@@ -0,0 +1,116 @@+-- | Types and functions for testing 'wai' endpoints using the 'tasty' testing framework.+--+module Test.Tasty.Wai+ (+ -- * Types+ Sess (..)++ -- * Creation+ , testWai++ -- * Helpers+ , get+ , post+ , put+ , assertStatus'++ -- * Request Builders+ , buildRequest+ , buildRequestWithBody++ , module Network.Wai.Test+ ) where++import qualified Control.Exception as E++import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as LBS+import Data.Monoid ((<>))++import Network.HTTP.Types (StdMethod)+import qualified Network.HTTP.Types as HTTP++import Test.Tasty.Providers (IsTest (..), Progress (..), TestName,+ TestTree, singleTest, testFailed,+ testPassed)+import Test.Tasty.Runners (formatMessage)++import Network.Wai (Application, Request, requestMethod)+import Network.Wai.Test++-- | Data structure for carrying around the info needed to build and run a test.+data Sess = S Application TestName (Session ())++instance IsTest Sess where+ -- No options yet+ testOptions = mempty++ run _ (S app tName sess) yieldProgress = do++ -- We don't really have progress to report, so state that we're running a+ -- test but do nothing else.+ yieldProgress $ Progress ("Running " <> tName) 0++ -- The wai-extra testing uses `throwIO` to indicate a test failure and+ -- converts that error into a 'String'. The result of the individual+ -- 'Session a' isn't important for the test?+ E.try (runSession sess app) >>= either toFailure toPass+ where+ toFailure (WaiTestFailure s) = testFailed <$> (formatMessage s)+ toPass _ = pure (testPassed mempty)++-- | Create an empty 'Request' using the given HTTP Method and route.+buildRequest+ :: StdMethod+ -> BS.ByteString+ -> Request+buildRequest mth rpath = flip setPath rpath $ defaultRequest+ { requestMethod = HTTP.renderStdMethod mth+ }++-- | As per 'buildRequest' but requires body content.+buildRequestWithBody+ :: StdMethod+ -> BS.ByteString+ -> LBS.ByteString+ -> SRequest+buildRequestWithBody mth rpath =+ SRequest (buildRequest mth rpath)++-- | Run a test case against a 'Application'.+--+-- This module re-exports the functions from 'wai-extra' for constructing the+-- 'Session' that is executed against a given endpoint.+--+-- A small test case may look like:+--+-- @+-- import MyApp (app)+--+-- testWai app "List Topics" $ do+-- res <- get "fudge/view"+-- assertStatus' HTTP.status200 res+-- @+--+testWai :: Application -> TestName -> Session () -> TestTree+testWai a tn = singleTest tn . S a tn++-- | Submit a 'HTTP.GET' request to the provided endpoint.+get :: BS.ByteString -> Session SResponse+get = request . buildRequest HTTP.GET++-- | Submit a 'HTTP.POST' request to the given endpoint with the provided+-- 'LBS.ByteString' as the body content.+post :: BS.ByteString -> LBS.ByteString -> Session SResponse+post r = srequest . buildRequestWithBody HTTP.POST r++-- | Submit a 'HTTP.PUT' request to the given endpoint with the provided+-- 'LBS.ByteString' as the body content.+put :: BS.ByteString -> LBS.ByteString -> Session SResponse+put r = srequest . buildRequestWithBody HTTP.PUT r++-- | An alternative helper function for checking the status code on a response+-- that lets you use the functions from 'Network.HTTP.Types' as opposed to bare+-- numbers.+assertStatus' :: HTTP.Status -> SResponse -> Session ()+assertStatus' c = assertStatus (HTTP.statusCode c)
+ tasty-wai.cabal view
@@ -0,0 +1,63 @@+-- Initial tasty-wai.cabal generated by cabal init. For further+-- documentation, see http://haskell.org/cabal/users-guide/++name: tasty-wai+version: 0.1.0.0+synopsis: Test 'wai' endpoints via Test.Tasty+description: Helper functions and runners for testing wai endpoints using the Tasty testing infrastructure.+license: BSD3+license-file: LICENCE+author: QFPL @ Data61+maintainer: sean.chalmers@data61.csiro.au++copyright: Copyright (C) 2018 Commonwealth Scientific and Industrial Research Organisation (CSIRO)++category: Testing,Web++build-type: Simple+extra-source-files: CHANGELOG.md+cabal-version: >=1.10++tested-with: GHC == 7.10.3+ , GHC == 8.0.2+ , GHC == 8.2.2+ , GHC == 8.4.1+ , GHC == 8.6.1++source-repository head+ type: git+ location: https://github.com/qfpl/tasty-wai++library+ exposed-modules: Test.Tasty.Wai++ -- other-modules:+ -- other-extensions:++ build-depends: base >=4.8 && <4.13+ , tasty >= 0.8 && < 1.3+ , bytestring == 0.10.*+ , wai == 3.2.*+ , wai-extra == 3.0.*+ , http-types >= 0.9 && < 0.13++ hs-source-dirs: src+ default-language: Haskell2010+++test-suite tests+ default-language: Haskell2010++ type: exitcode-stdio-1.0++ ghc-options: -threaded++ hs-source-dirs: test+ main-is: Test.hs++ build-depends: base >=4.8 && <4.13+ , tasty >= 0.8 && < 1.3+ , bytestring == 0.10.*+ , wai == 3.2.*+ , http-types >= 0.9 && < 0.13+ , tasty-wai
+ test/Test.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE OverloadedStrings #-}+module Main where++import Network.Wai (Application)+import qualified Network.Wai as W++import qualified Network.HTTP.Types as H++import Test.Tasty (defaultMain, testGroup)+import Test.Tasty.Wai (assertBody, assertStatus, assertStatus',+ get, post, testWai)++testApp :: Application+testApp rq cb = do+ let+ mkresp s = W.responseLBS s []+ resp404 = mkresp H.status404+ resp200 = mkresp H.status200++ resp <- case (W.requestMethod rq, W.pathInfo rq) of++ -- Ye olde...+ ("GET", ["hello"]) -> pure $ resp200 "world!"++ -- Echo me this!+ ("POST", ["echo"]) -> resp200 <$> W.strictRequestBody rq++ -- Well, then...+ _ -> pure $ resp404 "no route"++ cb resp++main :: IO ()+main = defaultMain $ testGroup "Tasty-Wai Tests"++ [ testWai testApp "Hello to World" $ do+ res <- get "hello"+ assertBody "world!" res++ , testWai testApp "Echo to thee" $ do+ res <- post "echo" "thus"+ assertStatus' H.status200 res -- Use functions from Network.HTTP.Types+ assertStatus 200 res -- Use raw ints+ assertBody "thus" res++ , testWai testApp "Will die!" $ do+ res <- get "not-a-thing"+ assertStatus' H.status404 res+ assertBody "no route" res+ ]