@@ -69,6 +69,34 @@ serversEqualSpec = describe "serversEqual" $ do
6969 show err `shouldContain` "Body: 2"
7070 show err `shouldContain` "Path: /failplz"
7171
72+ context "when JSON is equal but looks a bit different as a ByteString" $ do
73+
74+ it "sanity check: different whitespace same JSON objects bodyEquality fails" $ do
75+ FailedWith err <- withServantServer jsonApi jsonServer1 $ \burl1 ->
76+ withServantServer jsonApi jsonServer2 $ \burl2 -> do
77+ evalExample $ serversEqual jsonApi burl1 burl2 args bodyEquality
78+ show err `shouldContain` "Server equality failed"
79+
80+ it "jsonEquality considers equal JSON apis equal regardless of key ordering or whitespace" $ do
81+ withServantServerAndContext jsonApi ctx jsonServer1 $ \burl1 ->
82+ withServantServerAndContext jsonApi ctx jsonServer2 $ \burl2 ->
83+ serversEqual jsonApi burl1 burl2 args jsonEquality
84+
85+ it "sees when JSON apis are not equal because any value is different" $ do
86+ FailedWith err <- withServantServer jsonApi jsonServer2 $ \burl1 ->
87+ withServantServer jsonApi jsonServer3 $ \burl2 -> do
88+ evalExample $ serversEqual jsonApi burl1 burl2 args jsonEquality
89+ show err `shouldContain` "Server equality failed"
90+ show err `shouldContain` "Path: /jsonComparison"
91+
92+ it "sees when JSON apis are not equal due to different keys but same values" $ do
93+ FailedWith err <- withServantServer jsonApi jsonServer2 $ \burl1 ->
94+ withServantServer jsonApi jsonServer4 $ \burl2 -> do
95+ evalExample $ serversEqual jsonApi burl1 burl2 args jsonEquality
96+ show err `shouldContain` "Server equality failed"
97+ show err `shouldContain` "Path: /jsonComparison"
98+
99+
72100serverSatisfiesSpec :: Spec
73101serverSatisfiesSpec = describe "serverSatisfies" $ do
74102
@@ -262,6 +290,24 @@ octetAPI = Proxy
262290serverOctetAPI :: IO (Server OctetAPI)
263291serverOctetAPI = return $ return "blah"
264292
293+type JsonApi = "jsonComparison" :> Get '[OctetStream] BS.ByteString
294+
295+jsonApi :: Proxy JsonApi
296+jsonApi = Proxy
297+
298+jsonServer1 :: IO (Server JsonApi)
299+jsonServer1 = return $ return "{ \"b\": [\"b\"], \"a\": 1 }" -- whitespace, ordering different
300+
301+jsonServer2 :: IO (Server JsonApi)
302+jsonServer2 = return $ return "{\"a\": 1,\"b\":[\"b\"]}"
303+
304+jsonServer3 :: IO (Server JsonApi)
305+jsonServer3 = return $ return "{\"a\": 2, \"b\": [\"b\"]}"
306+
307+jsonServer4 :: IO (Server JsonApi)
308+jsonServer4 = return $ return "{\"c\": 1, \"d\": [\"b\"]}"
309+
310+
265311ctx :: Context '[BasicAuthCheck ()]
266312ctx = BasicAuthCheck (const . return $ NoSuchUser) :. EmptyContext
267313------------------------------------------------------------------------------