aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Language/GraphQL/AST/EncoderSpec.hs49
-rw-r--r--tests/Language/GraphQL/AST/ParserSpec.hs12
-rw-r--r--tests/Test/DirectiveSpec.hs84
-rw-r--r--tests/Test/FragmentSpec.hs237
4 files changed, 266 insertions, 116 deletions
diff --git a/tests/Language/GraphQL/AST/EncoderSpec.hs b/tests/Language/GraphQL/AST/EncoderSpec.hs
index a418a61..0067c83 100644
--- a/tests/Language/GraphQL/AST/EncoderSpec.hs
+++ b/tests/Language/GraphQL/AST/EncoderSpec.hs
@@ -1,19 +1,46 @@
{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
module Language.GraphQL.AST.EncoderSpec
( spec
) where
-import Language.GraphQL.AST (Value(..))
+import Language.GraphQL.AST
import Language.GraphQL.AST.Encoder
-import Test.Hspec ( Spec
- , describe
- , it
- , shouldBe
- )
+import Test.Hspec (Spec, context, describe, it, shouldBe)
+import Text.RawString.QQ (r)
spec :: Spec
-spec = describe "value" $ do
- it "escapes \\" $
- value minified (String "\\") `shouldBe` "\"\\\\\""
- it "escapes quotes" $
- value minified (String "\"") `shouldBe` "\"\\\"\""
+spec = do
+ describe "value" $ do
+ context "minified" $ do
+ it "escapes \\" $
+ value minified (String "\\") `shouldBe` "\"\\\\\""
+ it "escapes quotes" $
+ value minified (String "\"") `shouldBe` "\"\\\"\""
+ it "escapes backspace" $
+ value minified (String "a\bc") `shouldBe` "\"a\\bc\""
+ it "escapes Unicode" $
+ value minified (String "\0") `shouldBe` "\"\\u0000\""
+
+ context "pretty" $ do
+ it "uses strings for short string values" $
+ value pretty (String "Short text") `shouldBe` "\"Short text\""
+ it "uses block strings for text with new lines" $
+ value pretty (String "Line 1\nLine 2")
+ `shouldBe` "\"\"\"\n Line 1\n Line 2\n\"\"\""
+ it "escapes \\ in short strings" $
+ value pretty (String "\\") `shouldBe` "\"\\\\\""
+
+ describe "definition" $
+ it "indents block strings in arguments" $
+ let arguments = [Argument "message" (String "line1\nline2")]
+ field = Field Nothing "field" arguments [] []
+ set = OperationSelectionSet $ pure $ SelectionField field
+ operation = DefinitionOperation set
+ in definition pretty operation `shouldBe` [r|{
+ field(message: """
+ line1
+ line2
+ """)
+}
+|]
diff --git a/tests/Language/GraphQL/AST/ParserSpec.hs b/tests/Language/GraphQL/AST/ParserSpec.hs
index 3e20e8f..420d3cf 100644
--- a/tests/Language/GraphQL/AST/ParserSpec.hs
+++ b/tests/Language/GraphQL/AST/ParserSpec.hs
@@ -30,3 +30,15 @@ spec = describe "Parser" $ do
mutation auth($username: String!, $password: String!){
test
}|]
+
+ it "accepts two string arguments" $
+ parse document "" `shouldSucceedOn` [r|
+ mutation auth{
+ test(username: "username", password: "password")
+ }|]
+
+ it "accepts two block string arguments" $
+ parse document "" `shouldSucceedOn` [r|
+ mutation auth{
+ test(username: """username""", password: """password""")
+ }|]
diff --git a/tests/Test/DirectiveSpec.hs b/tests/Test/DirectiveSpec.hs
new file mode 100644
index 0000000..2224bc5
--- /dev/null
+++ b/tests/Test/DirectiveSpec.hs
@@ -0,0 +1,84 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+module Test.DirectiveSpec
+ ( spec
+ ) where
+
+import Data.Aeson (Value, object, (.=))
+import Data.List.NonEmpty (NonEmpty(..))
+import Language.GraphQL
+import qualified Language.GraphQL.Schema as Schema
+import Test.Hspec (Spec, describe, it, shouldBe)
+import Text.RawString.QQ (r)
+
+experimentalResolver :: Schema.Resolver IO
+experimentalResolver = Schema.scalar "experimentalField" $ pure (5 :: Int)
+
+emptyObject :: Value
+emptyObject = object
+ [ "data" .= object []
+ ]
+
+spec :: Spec
+spec =
+ describe "Directive executor" $ do
+ it "should be able to @skip fields" $ do
+ let query = [r|
+ {
+ experimentalField @skip(if: true)
+ }
+ |]
+
+ actual <- graphql (experimentalResolver :| []) query
+ actual `shouldBe` emptyObject
+
+ it "should not skip fields if @skip is false" $ do
+ let query = [r|
+ {
+ experimentalField @skip(if: false)
+ }
+ |]
+ expected = object
+ [ "data" .= object
+ [ "experimentalField" .= (5 :: Int)
+ ]
+ ]
+
+ actual <- graphql (experimentalResolver :| []) query
+ actual `shouldBe` expected
+
+ it "should skip fields if @include is false" $ do
+ let query = [r|
+ {
+ experimentalField @include(if: false)
+ }
+ |]
+
+ actual <- graphql (experimentalResolver :| []) query
+ actual `shouldBe` emptyObject
+
+ it "should be able to @skip a fragment spread" $ do
+ let query = [r|
+ {
+ ...experimentalFragment @skip(if: true)
+ }
+
+ fragment experimentalFragment on ExperimentalType {
+ experimentalField
+ }
+ |]
+
+ actual <- graphql (experimentalResolver :| []) query
+ actual `shouldBe` emptyObject
+
+ it "should be able to @skip an inline fragment" $ do
+ let query = [r|
+ {
+ ... on ExperimentalType @skip(if: true) {
+ experimentalField
+ }
+ }
+ |]
+
+ actual <- graphql (experimentalResolver :| []) query
+ actual `shouldBe` emptyObject
diff --git a/tests/Test/FragmentSpec.hs b/tests/Test/FragmentSpec.hs
index 69f1344..de10d63 100644
--- a/tests/Test/FragmentSpec.hs
+++ b/tests/Test/FragmentSpec.hs
@@ -48,117 +48,144 @@ hasErrors (Object object') = HashMap.member "errors" object'
hasErrors _ = True
spec :: Spec
-spec = describe "Inline fragment executor" $ do
- it "chooses the first selection if the type matches" $ do
- actual <- graphql (garment "Hat" :| []) inlineQuery
- let expected = object
- [ "data" .= object
- [ "garment" .= object
- [ "circumference" .= (60 :: Int)
+spec = do
+ describe "Inline fragment executor" $ do
+ it "chooses the first selection if the type matches" $ do
+ actual <- graphql (garment "Hat" :| []) inlineQuery
+ let expected = object
+ [ "data" .= object
+ [ "garment" .= object
+ [ "circumference" .= (60 :: Int)
+ ]
+ ]
+ ]
+ in actual `shouldBe` expected
+
+ it "chooses the last selection if the type matches" $ do
+ actual <- graphql (garment "Shirt" :| []) inlineQuery
+ let expected = object
+ [ "data" .= object
+ [ "garment" .= object
+ [ "size" .= ("L" :: Text)
+ ]
]
]
- ]
- in actual `shouldBe` expected
-
- it "chooses the last selection if the type matches" $ do
- actual <- graphql (garment "Shirt" :| []) inlineQuery
- let expected = object
- [ "data" .= object
- [ "garment" .= object
- [ "size" .= ("L" :: Text)
+ in actual `shouldBe` expected
+
+ it "embeds inline fragments without type" $ do
+ let query = [r|{
+ garment {
+ circumference
+ ... {
+ size
+ }
+ }
+ }|]
+ resolvers = Schema.object "garment" $ return [circumference, size]
+
+ actual <- graphql (resolvers :| []) query
+ let expected = object
+ [ "data" .= object
+ [ "garment" .= object
+ [ "circumference" .= (60 :: Int)
+ , "size" .= ("L" :: Text)
+ ]
]
]
- ]
- in actual `shouldBe` expected
-
- it "embeds inline fragments without type" $ do
- let query = [r|{
- garment {
- circumference
- ... {
- size
- }
- }
- }|]
- resolvers = Schema.object "garment" $ return [circumference, size]
-
- actual <- graphql (resolvers :| []) query
- let expected = object
- [ "data" .= object
- [ "garment" .= object
+ in actual `shouldBe` expected
+
+ it "evaluates fragments on Query" $ do
+ let query = [r|{
+ ... {
+ size
+ }
+ }|]
+
+ actual <- graphql (size :| []) query
+ actual `shouldNotSatisfy` hasErrors
+
+ describe "Fragment spread executor" $ do
+ it "evaluates fragment spreads" $ do
+ let query = [r|
+ {
+ ...circumferenceFragment
+ }
+
+ fragment circumferenceFragment on Hat {
+ circumference
+ }
+ |]
+
+ actual <- graphql (circumference :| []) query
+ let expected = object
+ [ "data" .= object
[ "circumference" .= (60 :: Int)
- , "size" .= ("L" :: Text)
]
]
- ]
- in actual `shouldBe` expected
-
- it "evaluates fragments on Query" $ do
- let query = [r|{
- ... {
- size
- }
- }|]
-
- actual <- graphql (size :| []) query
- actual `shouldNotSatisfy` hasErrors
-
- it "evaluates nested fragments" $ do
- let query = [r|
- {
- ...circumferenceFragment
- }
-
- fragment circumferenceFragment on Hat {
- circumference
- }
-
- fragment hatFragment on Hat {
- ...circumferenceFragment
- }
- |]
-
- actual <- graphql (circumference :| []) query
- let expected = object
- [ "data" .= object
- [ "circumference" .= (60 :: Int)
+ in actual `shouldBe` expected
+
+ it "evaluates nested fragments" $ do
+ let query = [r|
+ {
+ garment {
+ ...circumferenceFragment
+ }
+ }
+
+ fragment circumferenceFragment on Hat {
+ ...hatFragment
+ }
+
+ fragment hatFragment on Hat {
+ circumference
+ }
+ |]
+
+ actual <- graphql (garment "Hat" :| []) query
+ let expected = object
+ [ "data" .= object
+ [ "garment" .= object
+ [ "circumference" .= (60 :: Int)
+ ]
+ ]
]
- ]
- in actual `shouldBe` expected
-
- it "evaluates fragments defined in any order" $ do
- let query = [r|
- {
- ...circumferenceFragment
- }
-
- fragment circumferenceFragment on Hat {
- ...hatFragment
- }
-
- fragment hatFragment on Hat {
- circumference
- }
- |]
-
- actual <- graphql (circumference :| []) query
- let expected = object
- [ "data" .= object
- [ "circumference" .= (60 :: Int)
+ in actual `shouldBe` expected
+
+ it "rejects recursive fragments" $ do
+ let query = [r|
+ {
+ ...circumferenceFragment
+ }
+
+ fragment circumferenceFragment on Hat {
+ ...circumferenceFragment
+ }
+ |]
+
+ actual <- graphql (circumference :| []) query
+ actual `shouldSatisfy` hasErrors
+
+ it "considers type condition" $ do
+ let query = [r|
+ {
+ garment {
+ ...circumferenceFragment
+ ...sizeFragment
+ }
+ }
+ fragment circumferenceFragment on Hat {
+ circumference
+ }
+ fragment sizeFragment on Shirt {
+ size
+ }
+ |]
+ expected = object
+ [ "data" .= object
+ [ "garment" .= object
+ [ "circumference" .= (60 :: Int)
+ ]
+ ]
]
- ]
- in actual `shouldBe` expected
-
- it "rejects recursive" $ do
- let query = [r|
- {
- ...circumferenceFragment
- }
-
- fragment circumferenceFragment on Hat {
- ...circumferenceFragment
- }
- |]
-
- actual <- graphql (circumference :| []) query
- actual `shouldSatisfy` hasErrors
+ actual <- graphql (garment "Hat" :| []) query
+ actual `shouldBe` expected