tests: don't match JSON bodies literally
The change of hash function with hashable-1.3.1.0 changes object ordering in JSON output, causing some test failures: https://app.circleci.com/pipelines/github/PostgREST/postgrest/805/workflows/067844c9-9ce4-49e8-8790-315625ab309b/jobs/8309 e.g.: > expected: "[{\"b\":\"baz\",\"a\":\"bar\"}]" > but got: "[{\"a\":\"bar\",\"b\":\"baz\"}]" This changes the tests to not compare against the body literally, and instead use the ResponseMatcher instance from Test.Hspec.Wai.JSON.
This commit is contained in:
committed by
Steve Chavez
parent
5baec4819f
commit
3a466aea9a
+58
-55
@@ -2,7 +2,7 @@ module Feature.InsertSpec where
|
||||
|
||||
import Data.List (lookup)
|
||||
import Network.Wai (Application)
|
||||
import Network.Wai.Test (SResponse (simpleBody, simpleHeaders, simpleStatus))
|
||||
import Network.Wai.Test (SResponse (simpleHeaders))
|
||||
import Test.Hspec hiding (pendingWith)
|
||||
import Test.Hspec.Wai.Matcher (bodyEquals)
|
||||
|
||||
@@ -20,17 +20,16 @@ spec actualPgVersion = do
|
||||
describe "Posting new record" $ do
|
||||
context "disparate json types" $ do
|
||||
it "accepts disparate json types" $ do
|
||||
p <- post "/menagerie"
|
||||
post "/menagerie"
|
||||
[json| {
|
||||
"integer": 13, "double": 3.14159, "varchar": "testing!"
|
||||
, "boolean": false, "date": "1900-01-01", "money": "$3.99"
|
||||
, "enum": "foo"
|
||||
} |]
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` ""
|
||||
simpleStatus p `shouldBe` created201
|
||||
-- should not have content type set when body is empty
|
||||
lookup hContentType (simpleHeaders p) `shouldBe` Nothing
|
||||
} |] `shouldRespondWith` ""
|
||||
{ matchStatus = 201
|
||||
-- should not have content type set when body is empty
|
||||
, matchHeaders = [matchHeaderAbsent hContentType]
|
||||
}
|
||||
|
||||
it "filters columns in result using &select" $
|
||||
request methodPost "/menagerie?select=integer,varchar" [("Prefer", "return=representation")]
|
||||
@@ -121,13 +120,13 @@ spec actualPgVersion = do
|
||||
|
||||
context "from an html form" $
|
||||
it "accepts disparate json types" $ do
|
||||
p <- request methodPost "/menagerie"
|
||||
[("Content-Type", "application/x-www-form-urlencoded")]
|
||||
("integer=7&double=2.71828&varchar=forms+are+fun&" <>
|
||||
"boolean=false&date=1900-01-01&money=$3.99&enum=foo")
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` ""
|
||||
simpleStatus p `shouldBe` created201
|
||||
request methodPost "/menagerie"
|
||||
[("Content-Type", "application/x-www-form-urlencoded")]
|
||||
("integer=7&double=2.71828&varchar=forms+are+fun&" <>
|
||||
"boolean=false&date=1900-01-01&money=$3.99&enum=foo")
|
||||
`shouldRespondWith`
|
||||
""
|
||||
{ matchStatus = 201 }
|
||||
|
||||
context "with no pk supplied" $ do
|
||||
context "into a table with auto-incrementing pk" $
|
||||
@@ -162,37 +161,40 @@ spec actualPgVersion = do
|
||||
|
||||
context "into a table with no pk" $ do
|
||||
it "succeeds with 201 but no location header" $ do
|
||||
p <- post "/no_pk" [json| { "a":"foo", "b":"bar" } |]
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` ""
|
||||
lookup hLocation (simpleHeaders p) `shouldBe` Nothing
|
||||
simpleStatus p `shouldBe` created201
|
||||
post "/no_pk" [json| { "a":"foo", "b":"bar" } |]
|
||||
`shouldRespondWith`
|
||||
""
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [matchHeaderAbsent hLocation]
|
||||
}
|
||||
|
||||
it "returns full details of inserted record if asked" $ do
|
||||
p <- request methodPost "/no_pk"
|
||||
[("Prefer", "return=representation")]
|
||||
[json| { "a":"bar", "b":"baz" } |]
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` [json| [{ "a":"bar", "b":"baz" }] |]
|
||||
lookup hLocation (simpleHeaders p) `shouldBe` Nothing
|
||||
simpleStatus p `shouldBe` created201
|
||||
request methodPost "/no_pk"
|
||||
[("Prefer", "return=representation")]
|
||||
[json| { "a":"bar", "b":"baz" } |]
|
||||
`shouldRespondWith`
|
||||
[json| [{ "a":"bar", "b":"baz" }] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [matchHeaderAbsent hLocation]
|
||||
}
|
||||
|
||||
it "returns empty array when no items inserted, and return=rep" $ do
|
||||
p <- request methodPost "/no_pk"
|
||||
[("Prefer", "return=representation")]
|
||||
[json| [] |]
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` [json| [] |]
|
||||
simpleStatus p `shouldBe` created201
|
||||
request methodPost "/no_pk"
|
||||
[("Prefer", "return=representation")]
|
||||
[json| [] |]
|
||||
`shouldRespondWith`
|
||||
[json| [] |]
|
||||
{ matchStatus = 201 }
|
||||
|
||||
it "can post nulls" $ do
|
||||
p <- request methodPost "/no_pk"
|
||||
[("Prefer", "return=representation")]
|
||||
[json| { "a":null, "b":"foo" } |]
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` [json| [{ "a":null, "b":"foo" }] |]
|
||||
lookup hLocation (simpleHeaders p) `shouldBe` Nothing
|
||||
simpleStatus p `shouldBe` created201
|
||||
request methodPost "/no_pk"
|
||||
[("Prefer", "return=representation")]
|
||||
[json| { "a":null, "b":"foo" } |]
|
||||
`shouldRespondWith`
|
||||
[json| [{ "a":null, "b":"foo" }] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [matchHeaderAbsent hLocation]
|
||||
}
|
||||
|
||||
context "with compound pk supplied" $
|
||||
it "builds response location header appropriately" $ do
|
||||
@@ -210,10 +212,12 @@ spec actualPgVersion = do
|
||||
let bulkData = [json| [ {"k1":21, "k2":"hello world"}
|
||||
, {"k1":22, "k2":"bye for now"}]
|
||||
|]
|
||||
p <- request methodPost "/compound_pk" [] bulkData
|
||||
liftIO $ do
|
||||
simpleStatus p `shouldBe` created201
|
||||
lookup hLocation (simpleHeaders p) `shouldBe` Nothing
|
||||
request methodPost "/compound_pk" [] bulkData
|
||||
`shouldRespondWith`
|
||||
""
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [matchHeaderAbsent hLocation]
|
||||
}
|
||||
|
||||
context "with invalid json payload" $
|
||||
it "fails with 400 and error" $
|
||||
@@ -416,13 +420,12 @@ spec actualPgVersion = do
|
||||
|
||||
context "with unicode values" $
|
||||
it "succeeds and returns usable location header" $ do
|
||||
let payload = [json| { "k":"圍棋", "extra":"¥" } |]
|
||||
p <- request methodPost "/simple_pk2?select=extra,k"
|
||||
[("Prefer", "tx=commit"), ("Prefer", "return=representation")]
|
||||
payload
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` "["<>payload<>"]"
|
||||
simpleStatus p `shouldBe` created201
|
||||
[json| { "k":"圍棋", "extra":"¥" } |]
|
||||
pure p `shouldRespondWith`
|
||||
[json|[ { "k":"圍棋", "extra":"¥" } ]|]
|
||||
{ matchStatus = 201 }
|
||||
|
||||
let Just location = lookup hLocation $ simpleHeaders p
|
||||
get location
|
||||
@@ -496,12 +499,12 @@ spec actualPgVersion = do
|
||||
}
|
||||
|
||||
it "can insert in a table with no select and return=minimal" $ do
|
||||
p <- request methodPost "/insertonly"
|
||||
[("Prefer", "return=minimal")]
|
||||
[json| { "v":"some value" } |]
|
||||
liftIO $ do
|
||||
simpleBody p `shouldBe` ""
|
||||
simpleStatus p `shouldBe` created201
|
||||
request methodPost "/insertonly"
|
||||
[("Prefer", "return=minimal")]
|
||||
[json| { "v":"some value" } |]
|
||||
`shouldRespondWith`
|
||||
""
|
||||
{ matchStatus = 201 }
|
||||
|
||||
describe "Inserting into VIEWs" $
|
||||
it "returns a location header" $
|
||||
|
||||
+7
-1
@@ -8,7 +8,7 @@ import qualified Data.Set as S
|
||||
import qualified System.IO.Error as E
|
||||
|
||||
import Data.Aeson (Value (..), decode, encode)
|
||||
import Data.CaseInsensitive (CI (..))
|
||||
import Data.CaseInsensitive (CI (..), original)
|
||||
import Data.List (lookup)
|
||||
import Data.List.NonEmpty (fromList)
|
||||
import Network.Wai.Test (SResponse (simpleBody, simpleHeaders, simpleStatus))
|
||||
@@ -33,6 +33,12 @@ matchContentTypeJson = "Content-Type" <:> "application/json; charset=utf-8"
|
||||
matchContentTypeSingular :: MatchHeader
|
||||
matchContentTypeSingular = "Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"
|
||||
|
||||
matchHeaderAbsent :: HeaderName -> MatchHeader
|
||||
matchHeaderAbsent name = MatchHeader $ \headers _body ->
|
||||
case lookup name headers of
|
||||
Just _ -> Just $ "unexpected header: " <> toS (original name) <> "\n"
|
||||
Nothing -> Nothing
|
||||
|
||||
validateOpenApiResponse :: [Header] -> WaiSession () ()
|
||||
validateOpenApiResponse headers = do
|
||||
r <- request methodGet "/" headers ""
|
||||
|
||||
Reference in New Issue
Block a user