-
Notifications
You must be signed in to change notification settings - Fork 380
When statusIs fails, print a preview of the body #1680
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
Changes from all commits
2ddc63e
34927e3
8f00e76
f50d23c
4ddff42
28e5b60
1d67e3a
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 |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| {-# LANGUAGE OverloadedStrings #-} | ||
|
|
||
| -- | This module exposes functions that are used internally by yesod-test. | ||
| -- The functions exposed here are _not_ a stable API—they may be changed or removed without any major version bump. | ||
| -- | ||
| -- That said, you may find them useful if your application can accept API breakage. | ||
| module Yesod.Test.Internal | ||
| ( getBodyTextPreview | ||
| , contentTypeHeaderIsUtf8 | ||
| , assumedUTF8ContentTypes | ||
|
Member
Author
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. I thought it was plausible people would want these for any custom assertion functions they'd write. But, they don't feel like something that should be part of the stable API
Member
Author
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. But, I'm pretty flexible on this and don't have much experience with releasing Internal modules |
||
| ) where | ||
|
|
||
| import qualified Data.ByteString.Char8 as BS8 | ||
| import qualified Data.ByteString.Lazy as LBS | ||
| import qualified Data.Set as Set | ||
| import qualified Data.Text as T | ||
| import qualified Data.Text.Encoding as TE | ||
| import qualified Data.Text.Lazy as TL | ||
| import qualified Data.Text.Lazy.Encoding as DTLE | ||
| import qualified Yesod.Core.Content as Content | ||
| import Data.Semigroup (Semigroup(..)) | ||
|
|
||
| -- | Helper function to get the first 1024 characters of the body, assuming it is UTF-8. | ||
| -- This function is used to preview the body in case of an assertion failure. | ||
| -- | ||
| -- @since 1.6.10 | ||
| getBodyTextPreview :: LBS.ByteString -> T.Text | ||
| getBodyTextPreview body = | ||
| let characterLimit = 1024 | ||
| textBody = TL.toStrict $ DTLE.decodeUtf8 body | ||
| in if T.length textBody < characterLimit | ||
| then textBody | ||
| else T.take characterLimit textBody <> "... (use `printBody` to see complete response body)" | ||
|
|
||
| -- | Helper function to determine if we can print a body as plain text, for debugging purposes. | ||
| -- | ||
| -- @since 1.6.10 | ||
| contentTypeHeaderIsUtf8 :: BS8.ByteString -> Bool | ||
| contentTypeHeaderIsUtf8 contentTypeBS = | ||
| -- Convert to Text, so we can use T.splitOn | ||
| let contentTypeText = T.toLower $ TE.decodeUtf8 contentTypeBS | ||
| isUTF8FromCharset = case T.splitOn "charset=" contentTypeText of | ||
| -- Either a specific designation as UTF-8, or ASCII (which is a subset of UTF-8) | ||
| [_, charSet] -> any (`T.isInfixOf` charSet) ["utf-8", "us-ascii"] | ||
| _ -> False | ||
|
|
||
| isInferredUTF8FromContentType = BS8.takeWhile (/= ';') contentTypeBS `Set.member` assumedUTF8ContentTypes | ||
|
|
||
| in isUTF8FromCharset || isInferredUTF8FromContentType | ||
|
|
||
| -- | List of Content-Types that are assumed to be UTF-8 (e.g. JSON). | ||
| -- | ||
| -- @since 1.6.10 | ||
| assumedUTF8ContentTypes :: Set.Set BS8.ByteString | ||
| assumedUTF8ContentTypes = Set.fromList $ map Content.simpleContentType | ||
| [ Content.typeHtml | ||
| , Content.typePlain | ||
| , Content.typeJson | ||
| , Content.typeXml | ||
| , Content.typeAtom | ||
| , Content.typeRss | ||
| , Content.typeSvg | ||
| , Content.typeJavascript | ||
| , Content.typeCss | ||
| ] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,6 +45,7 @@ import Control.Monad.IO.Unlift (toIO) | |
| import qualified Web.Cookie as Cookie | ||
| import Data.Maybe (isNothing) | ||
| import qualified Data.Text as T | ||
| import Yesod.Test.Internal (contentTypeHeaderIsUtf8) | ||
|
|
||
| parseQuery_ :: Text -> [[SelectorGroup]] | ||
| parseQuery_ = either error id . parseQuery | ||
|
|
@@ -125,6 +126,19 @@ main = hspec $ do | |
| ] | ||
| ] | ||
| in HD.parseLBS html @?= doc | ||
| describe "identifying text-based bodies" $ do | ||
| it "matches content-types with an explicit UTF-8 charset" $ do | ||
| contentTypeHeaderIsUtf8 "application/custom; charset=UTF-8" @?= True | ||
| contentTypeHeaderIsUtf8 "application/custom; charset=utf-8" @?= True | ||
| it "matches content-types with an ASCII charset" $ do | ||
| contentTypeHeaderIsUtf8 "application/custom; charset=us-ascii" @?= True | ||
| it "matches content-types that we assume are UTF-8" $ do | ||
| contentTypeHeaderIsUtf8 "text/html" @?= True | ||
| contentTypeHeaderIsUtf8 "application/json" @?= True | ||
| it "doesn't match content-type headers that are binary data" $ do | ||
| contentTypeHeaderIsUtf8 "image/gif" @?= False | ||
| contentTypeHeaderIsUtf8 "application/pdf" @?= False | ||
|
Member
Author
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. Technically PDFs can be non-binary Postscript data, but this is fairly rare to my knowledge, and more of a relic |
||
|
|
||
| describe "basic usage" $ yesodSpec app $ do | ||
| ydescribe "tests1" $ do | ||
| yit "tests1a" $ do | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.