hspec-wai 0.4.1 → 0.5.0
raw patch · 7 files changed
+29/−152 lines, 7 filesdep −aesondep −aeson-qqdep −hspec-waidep ~waiPVP ok
version bump matches the API change (PVP)
Dependencies removed: aeson, aeson-qq, hspec-wai, markdown-unlit, scotty, template-haskell
Dependency ranges changed: wai
API changes (from Hackage documentation)
- Test.Hspec.Wai.JSON: class FromValue a
- Test.Hspec.Wai.JSON: fromValue :: FromValue a => Value -> a
- Test.Hspec.Wai.JSON: instance FromValue ByteString
- Test.Hspec.Wai.JSON: instance FromValue ResponseMatcher
- Test.Hspec.Wai.JSON: json :: QuasiQuoter
+ Test.Hspec.Wai: (<:>) :: HeaderName -> ByteString -> MatchHeader
+ Test.Hspec.Wai: MatchHeader :: ([Header] -> Maybe String) -> MatchHeader
+ Test.Hspec.Wai: data MatchHeader
+ Test.Hspec.Wai.Internal: formatHeader :: Header -> String
- Test.Hspec.Wai: ResponseMatcher :: Int -> [Header] -> Maybe ByteString -> ResponseMatcher
+ Test.Hspec.Wai: ResponseMatcher :: Int -> [MatchHeader] -> Maybe ByteString -> ResponseMatcher
- Test.Hspec.Wai: matchHeaders :: ResponseMatcher -> [Header]
+ Test.Hspec.Wai: matchHeaders :: ResponseMatcher -> [MatchHeader]
Files
- README.lhs +0/−60
- hspec-wai.cabal +1/−21
- src/Test/Hspec/Wai.hs +4/−2
- src/Test/Hspec/Wai/Internal.hs +2/−0
- src/Test/Hspec/Wai/JSON.hs +0/−56
- src/Test/Hspec/Wai/Matcher.hs +21/−12
- src/Test/Hspec/Wai/Util.hs +1/−1
− README.lhs
@@ -1,60 +0,0 @@-hspec-wai [](https://travis-ci.org/hspec/hspec-wai)-===========--Helpers to test [WAI](http://www.yesodweb.com/book/web-application-interface)-applications with [Hspec](http://hspec.github.io/)--## Example--~~~ {.haskell}-{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}-module Main (main) where--import Test.Hspec-import Test.Hspec.Wai-import Test.Hspec.Wai.JSON--import Network.Wai (Application)-import qualified Web.Scotty as S-import Data.Aeson (Value(..), object, (.=))--main :: IO ()-main = hspec spec--app :: IO Application-app = S.scottyApp $ do- S.get "/" $ do- S.text "hello"- S.setHeader "Content-Type" "text/plain"-- S.get "/some-json" $ do- S.json $ object ["foo" .= Number 23, "bar" .= Number 42]- S.setHeader "Content-Type" "application/json"--spec :: Spec-spec = with app $ do- describe "GET /" $ do- it "responds with 200" $ do- get "/" `shouldRespondWith` 200-- it "responds with 'hello'" $ do- get "/" `shouldRespondWith` "hello"-- it "responds with 200 / 'hello'" $ do- get "/" `shouldRespondWith` "hello" {matchStatus = 200}-- it "has Content-Type: text/plain" $ do- get "/" `shouldRespondWith` 200 {matchHeaders = [("Content-Type", "text/plain")]}-- describe "GET /some-json" $ do- it "responds with some JSON" $ do- get "/some-json" `shouldRespondWith` [json|{foo: 23, bar: 42}|]-~~~--## Contributing--1. Fork it-2. Create your feature branch (`git checkout -b my-new-feature`)-3. Commit your changes (`git commit -am 'Add some feature'`)-4. Push to the branch (`git push origin my-new-feature`)-5. Create new Pull Request
hspec-wai.cabal view
@@ -1,5 +1,5 @@ name: hspec-wai-version: 0.4.1+version: 0.5.0 license: MIT license-file: LICENSE copyright: (c) 2012-2014 Fujimura Daisuke,@@ -24,7 +24,6 @@ exposed-modules: Test.Hspec.Wai Test.Hspec.Wai.Internal- Test.Hspec.Wai.JSON other-modules: Test.Hspec.Wai.Util Test.Hspec.Wai.Matcher@@ -38,9 +37,6 @@ , wai >= 3 , wai-extra >= 3 , hspec2- , template-haskell- , aeson- , aeson-qq >= 0.7.3 test-suite spec type:@@ -61,19 +57,3 @@ , wai , wai-extra , hspec2--test-suite README- type:- exitcode-stdio-1.0- ghc-options:- -Wall -pgmL markdown-unlit- main-is:- README.lhs- build-depends:- base == 4.*- , markdown-unlit- , hspec2- , hspec-wai- , aeson- , wai- , scotty
src/Test/Hspec/Wai.hs view
@@ -17,6 +17,8 @@ -- * Matching on the response , shouldRespondWith , ResponseMatcher(..)+, MatchHeader(..)+, (<:>) -- * Helpers and re-exports , liftIO@@ -103,5 +105,5 @@ -- method, request path, headers and body. request :: Method -> ByteString -> [Header] -> LB.ByteString -> WaiSession SResponse request method path headers body = getApp >>= liftIO . runSession (Wai.srequest $ SRequest req body)- where- req = setPath defaultRequest {requestMethod = method, requestHeaders = headers} path+ where+ req = setPath defaultRequest {requestMethod = method, requestHeaders = headers} path
src/Test/Hspec/Wai/Internal.hs view
@@ -7,6 +7,7 @@ , WaiSession(..) , runWaiSession , getApp+, formatHeader ) where import Control.Applicative@@ -16,6 +17,7 @@ import Network.Wai.Test hiding (request) import Test.Hspec import Test.Hspec.Core (Example (..))+import Test.Hspec.Wai.Util (formatHeader) -- | An expectation in the `WaiSession` monad. Failing expectations are -- communicated through exceptions (similar to `Expectation` and
− src/Test/Hspec/Wai/JSON.hs
@@ -1,56 +0,0 @@-{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}-module Test.Hspec.Wai.JSON (--- $setup- json-, FromValue(..)-) where--import Test.Hspec.Wai-import Data.ByteString.Lazy (ByteString)-import Data.Aeson (Value, encode)-import Data.Aeson.QQ-import Language.Haskell.TH.Quote---- $setup--- The examples in this module assume that you have the @QuasiQuotes@ language--- extension enabled and that "Data.ByteString.Lazy.Char8" is imported--- qualified as @L@:------ >>> :set -XQuasiQuotes--- >>> import Data.ByteString.Lazy.Char8 as L---- | A `QuasiQuoter` for constructing JSON values.------ The constructed value is polymorph and unifies to instances of `FromValue`.------ When used as a `ResponseMatcher` it matches a response with------ * a status code of @200@------ * a @Content-Type@ header with value @application/json@------ * the specified JSON as response body------ When used as a @ByteString@ it creates a ByteString from the specified JSON--- that can be used as a request body for e.g. @POST@ and @PUT@ requests.------ Example:------ >>> L.putStrLn [json|[23, {foo: 42}]|]--- [23,{"foo":42}]-json :: QuasiQuoter-json = QuasiQuoter {- quoteExp = \input -> [|fromValue $(quoteExp aesonQQ input)|]-, quotePat = const $ error "No quotePat defined for Test.Hspec.Wai.JSON.json"-, quoteType = const $ error "No quoteType defined for Test.Hspec.Wai.JSON.json"-, quoteDec = const $ error "No quoteDec defined for Test.Hspec.Wai.JSON.json"-}--class FromValue a where- fromValue :: Value -> a--instance FromValue ResponseMatcher where- fromValue v = ResponseMatcher 200 [("Content-Type", "application/json")] (Just . encode $ v)--instance FromValue ByteString where- fromValue = encode
src/Test/Hspec/Wai/Matcher.hs view
@@ -1,15 +1,18 @@ {-# LANGUAGE ViewPatterns #-} module Test.Hspec.Wai.Matcher ( ResponseMatcher(..)+, MatchHeader(..)+, (<:>) , match ) where -+import Control.Applicative import Control.Monad+import Data.Maybe import Data.Monoid-import Data.Functor import Data.String import Data.Text.Lazy.Encoding (encodeUtf8)+import Data.ByteString (ByteString) import qualified Data.ByteString.Lazy as LB import Network.HTTP.Types import Network.Wai.Test@@ -18,10 +21,12 @@ data ResponseMatcher = ResponseMatcher { matchStatus :: Int-, matchHeaders :: [Header]+, matchHeaders :: [MatchHeader] , matchBody :: Maybe LB.ByteString } +data MatchHeader = MatchHeader ([Header] -> Maybe String)+ instance IsString ResponseMatcher where fromString s = ResponseMatcher 200 [] (Just . encodeUtf8 . fromString $ s) @@ -53,13 +58,17 @@ , " but got: " ++ actual ] -checkHeaders :: [Header] -> [Header] -> Maybe String-checkHeaders actual expected = case filter (`notElem` actual) expected of- [] -> Nothing- missing ->- let msg- | length missing == 1 = "missing header:"- | otherwise = "missing headers:"- in Just $ unlines (msg : formatHeaders missing ++ "the actual headers were:" : formatHeaders actual)+checkHeaders :: [Header] -> [MatchHeader] -> Maybe String+checkHeaders headers m = case go m of+ [] -> Nothing+ xs -> Just (mconcat xs ++ "the actual headers were:\n" ++ unlines (map formatHeader headers)) where- formatHeaders = map ((" " ++) . formatHeader)+ go = catMaybes . map (\(MatchHeader p) -> p headers)++(<:>) :: HeaderName -> ByteString -> MatchHeader+name <:> value = MatchHeader $ \headers -> guard (header `notElem` headers) >> (Just . unlines) [+ "missing header:"+ , formatHeader header+ ]+ where+ header = (name, value)
src/Test/Hspec/Wai/Util.hs view
@@ -14,7 +14,7 @@ import Network.HTTP.Types formatHeader :: Header -> String-formatHeader header@(name, value) = fromMaybe (show header) (safeToString $ B.concat [CI.original name, ": ", value])+formatHeader header@(name, value) = " " ++ fromMaybe (show header) (safeToString $ B.concat [CI.original name, ": ", value]) safeToString :: ByteString -> Maybe String safeToString bs = do