New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[yesod-test] Adds requireJSONResponse function #1646
Changes from 3 commits
6d0b723
596db81
92afb11
91b7574
0025226
42d41f7
561adc2
8ee7718
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -125,6 +125,7 @@ module Yesod.Test | |
, htmlAnyContain | ||
, htmlNoneContain | ||
, htmlCount | ||
, requireJSONResponse | ||
|
||
-- * Grab information | ||
, getTestYesod | ||
|
@@ -195,6 +196,9 @@ import GHC.Exts (Constraint) | |
type HasCallStack = (() :: Constraint) | ||
#endif | ||
import Data.ByteArray.Encoding (convertToBase, Base(..)) | ||
import Network.HTTP.Types.Header (hContentType) | ||
import Data.Aeson (FromJSON, eitherDecode') | ||
import Control.Monad (unless) | ||
|
||
{-# DEPRECATED byLabel "This function seems to have multiple bugs (ref: https://github.com/yesodweb/yesod/pull/1459). Use byLabelExact, byLabelContain, byLabelPrefix or byLabelSuffix instead" #-} | ||
{-# DEPRECATED fileByLabel "This function seems to have multiple bugs (ref: https://github.com/yesodweb/yesod/pull/1459). Use fileByLabelExact, fileByLabelContain, fileByLabelPrefix or fileByLabelSuffix instead" #-} | ||
|
@@ -598,6 +602,29 @@ htmlCount query count = do | |
liftIO $ flip HUnit.assertBool (matches == count) | ||
("Expected "++(show count)++" elements to match "++T.unpack query++", found "++(show matches)) | ||
|
||
-- | Parses the response body from JSON into a Haskell value, throwing an error if parsing fails. | ||
-- | ||
-- This function also checks that the @Content-Type@ of the response is @application/json@. | ||
-- | ||
-- ==== __Examples__ | ||
-- | ||
-- > get CommentR | ||
-- > (comment :: Comment) <- requireJSONResponse | ||
-- | ||
-- @since 1.6.9 | ||
requireJSONResponse :: (HasCallStack, FromJSON a) => YesodExample site a | ||
requireJSONResponse = do | ||
withResponse $ \(SResponse _status headers body) -> do | ||
let mContentType = lookup hContentType headers | ||
isJSONContentType = maybe False (\contentType -> BS8.takeWhile (/= ';') contentType == "application/json") mContentType | ||
unless | ||
isJSONContentType | ||
(failure $ T.pack $ "Expected `Content-Type: application/json` in the headers, got: " ++ show headers) | ||
case eitherDecode' body of | ||
-- TODO: include full body in error message? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could do this if there's a failure. I think it would mostly be quite useful, but would be large and sometimes extremely large (e.g. Base64 encoded images). Thoughts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about including the first 256 (arbitrary number) bytes? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems pretty reasonable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool, implemented the body preview |
||
Left err -> failure $ T.concat ["Failed to parse JSON response; error: ", T.pack err] | ||
Right v -> return v | ||
|
||
-- | Outputs the last response body to stderr (So it doesn't get captured by HSpec) | ||
printBody :: YesodExample site () | ||
printBody = withResponse $ \ SResponse { simpleBody = b } -> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copied from
acceptsJson
, mostlyThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it work to use
acceptsJson
here? That would be preferable, since the set of acceptable JSON mime types may expand in the future.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
acceptsJson
isMonadHandler
, so we couldn't just drop it in here I don't think, but I could create a new function exposed from yesod-core that takes a list of headers ([(CI ByteString, ByteString)]
, akaRequestHeaders
) and returned if one of the was a JSON content type?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds good
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Realized that the
Accept
header is slightly different, since it has a list of preferred MIME types. I added acontentTypeIsJson
function for general use on Content-Type.