aboutsummaryrefslogtreecommitdiff
path: root/tests/Language/GraphQL
diff options
context:
space:
mode:
Diffstat (limited to 'tests/Language/GraphQL')
-rw-r--r--tests/Language/GraphQL/AST/ParserSpec.hs11
-rw-r--r--tests/Language/GraphQL/Execute/CoerceSpec.hs122
-rw-r--r--tests/Language/GraphQL/ExecuteSpec.hs75
-rw-r--r--tests/Language/GraphQL/Type/OutSpec.hs14
4 files changed, 220 insertions, 2 deletions
diff --git a/tests/Language/GraphQL/AST/ParserSpec.hs b/tests/Language/GraphQL/AST/ParserSpec.hs
index 4fae5b1..2801b57 100644
--- a/tests/Language/GraphQL/AST/ParserSpec.hs
+++ b/tests/Language/GraphQL/AST/ParserSpec.hs
@@ -8,7 +8,7 @@ import Data.List.NonEmpty (NonEmpty(..))
import Language.GraphQL.AST.Document
import Language.GraphQL.AST.Parser
import Test.Hspec (Spec, describe, it)
-import Test.Hspec.Megaparsec (shouldParse, shouldSucceedOn)
+import Test.Hspec.Megaparsec (shouldParse, shouldFailOn, shouldSucceedOn)
import Text.Megaparsec (parse)
import Text.RawString.QQ (r)
@@ -141,4 +141,11 @@ spec = describe "Parser" $ do
extend type Story {
isHiddenLocally: Boolean
}
- |] \ No newline at end of file
+ |]
+
+ it "rejects variables in DefaultValue" $
+ parse document "" `shouldFailOn` [r|
+ query ($book: String = "Zarathustra", $author: String = $book) {
+ title
+ }
+ |]
diff --git a/tests/Language/GraphQL/Execute/CoerceSpec.hs b/tests/Language/GraphQL/Execute/CoerceSpec.hs
new file mode 100644
index 0000000..339c2e3
--- /dev/null
+++ b/tests/Language/GraphQL/Execute/CoerceSpec.hs
@@ -0,0 +1,122 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Language.GraphQL.Execute.CoerceSpec
+ ( spec
+ ) where
+
+import Data.Aeson as Aeson ((.=))
+import qualified Data.Aeson as Aeson
+import qualified Data.Aeson.Types as Aeson
+import qualified Data.HashMap.Strict as HashMap
+import Data.Maybe (isNothing)
+import Data.Scientific (scientific)
+import qualified Language.GraphQL.Execute.Coerce as Coerce
+import Language.GraphQL.Type
+import qualified Language.GraphQL.Type.In as In
+import Prelude hiding (id)
+import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)
+
+direction :: EnumType
+direction = EnumType "Direction" Nothing $ HashMap.fromList
+ [ ("NORTH", EnumValue Nothing)
+ , ("EAST", EnumValue Nothing)
+ , ("SOUTH", EnumValue Nothing)
+ , ("WEST", EnumValue Nothing)
+ ]
+
+singletonInputObject :: In.Type
+singletonInputObject = In.NamedInputObjectType type'
+ where
+ type' = In.InputObjectType "ObjectName" Nothing inputFields
+ inputFields = HashMap.singleton "field" field
+ field = In.InputField Nothing (In.NamedScalarType string) Nothing
+
+namedIdType :: In.Type
+namedIdType = In.NamedScalarType id
+
+spec :: Spec
+spec = do
+ describe "VariableValue Aeson" $ do
+ it "coerces strings" $
+ let expected = Just (String "asdf")
+ actual = Coerce.coerceVariableValue
+ (In.NamedScalarType string) (Aeson.String "asdf")
+ in actual `shouldBe` expected
+ it "coerces non-null strings" $
+ let expected = Just (String "asdf")
+ actual = Coerce.coerceVariableValue
+ (In.NonNullScalarType string) (Aeson.String "asdf")
+ in actual `shouldBe` expected
+ it "coerces booleans" $
+ let expected = Just (Boolean True)
+ actual = Coerce.coerceVariableValue
+ (In.NamedScalarType boolean) (Aeson.Bool True)
+ in actual `shouldBe` expected
+ it "coerces zero to an integer" $
+ let expected = Just (Int 0)
+ actual = Coerce.coerceVariableValue
+ (In.NamedScalarType int) (Aeson.Number 0)
+ in actual `shouldBe` expected
+ it "rejects fractional if an integer is expected" $
+ let actual = Coerce.coerceVariableValue
+ (In.NamedScalarType int) (Aeson.Number $ scientific 14 (-1))
+ in actual `shouldSatisfy` isNothing
+ it "coerces float numbers" $
+ let expected = Just (Float 1.4)
+ actual = Coerce.coerceVariableValue
+ (In.NamedScalarType float) (Aeson.Number $ scientific 14 (-1))
+ in actual `shouldBe` expected
+ it "coerces IDs" $
+ let expected = Just (String "1234")
+ json = Aeson.String "1234"
+ actual = Coerce.coerceVariableValue namedIdType json
+ in actual `shouldBe` expected
+ it "coerces input objects" $
+ let actual = Coerce.coerceVariableValue singletonInputObject
+ $ Aeson.object ["field" .= ("asdf" :: Aeson.Value)]
+ expected = Just $ Object $ HashMap.singleton "field" "asdf"
+ in actual `shouldBe` expected
+ it "skips the field if it is missing in the variables" $
+ let actual = Coerce.coerceVariableValue
+ singletonInputObject Aeson.emptyObject
+ expected = Just $ Object HashMap.empty
+ in actual `shouldBe` expected
+ it "fails if input object value contains extra fields" $
+ let actual = Coerce.coerceVariableValue singletonInputObject
+ $ Aeson.object variableFields
+ variableFields =
+ [ "field" .= ("asdf" :: Aeson.Value)
+ , "extra" .= ("qwer" :: Aeson.Value)
+ ]
+ in actual `shouldSatisfy` isNothing
+ it "preserves null" $
+ let actual = Coerce.coerceVariableValue namedIdType Aeson.Null
+ in actual `shouldBe` Just Null
+ it "preserves list order" $
+ let list = Aeson.toJSONList ["asdf" :: Aeson.Value, "qwer"]
+ listType = (In.ListType $ In.NamedScalarType string)
+ actual = Coerce.coerceVariableValue listType list
+ expected = Just $ List [String "asdf", String "qwer"]
+ in actual `shouldBe` expected
+
+ describe "coerceInputLiteral" $ do
+ it "coerces enums" $
+ let expected = Just (Enum "NORTH")
+ actual = Coerce.coerceInputLiteral
+ (In.NamedEnumType direction) (Enum "NORTH")
+ in actual `shouldBe` expected
+ it "fails with non-existing enum value" $
+ let actual = Coerce.coerceInputLiteral
+ (In.NamedEnumType direction) (Enum "NORTH_EAST")
+ in actual `shouldSatisfy` isNothing
+ it "coerces integers to IDs" $
+ let expected = Just (String "1234")
+ actual = Coerce.coerceInputLiteral namedIdType (Int 1234)
+ in actual `shouldBe` expected
+ it "coerces nulls" $ do
+ let actual = Coerce.coerceInputLiteral namedIdType Null
+ in actual `shouldBe` Just Null
+ it "wraps singleton lists" $ do
+ let expected = Just $ List [List [String "1"]]
+ embeddedType = In.ListType $ In.ListType namedIdType
+ actual = Coerce.coerceInputLiteral embeddedType (String "1")
+ in actual `shouldBe` expected
diff --git a/tests/Language/GraphQL/ExecuteSpec.hs b/tests/Language/GraphQL/ExecuteSpec.hs
new file mode 100644
index 0000000..30568be
--- /dev/null
+++ b/tests/Language/GraphQL/ExecuteSpec.hs
@@ -0,0 +1,75 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Language.GraphQL.ExecuteSpec
+ ( spec
+ ) where
+
+import Data.Aeson ((.=))
+import qualified Data.Aeson as Aeson
+import Data.Functor.Identity (Identity(..))
+import Data.HashMap.Strict (HashMap)
+import qualified Data.HashMap.Strict as HashMap
+import Language.GraphQL.AST (Name)
+import Language.GraphQL.AST.Parser (document)
+import Language.GraphQL.Error
+import Language.GraphQL.Execute
+import Language.GraphQL.Type as Type
+import Language.GraphQL.Type.Out as Out
+import Test.Hspec (Spec, describe, it, shouldBe)
+import Text.Megaparsec (parse)
+
+schema :: Schema Identity
+schema = Schema {query = queryType, mutation = Nothing}
+
+queryType :: Out.ObjectType Identity
+queryType = Out.ObjectType "Query" Nothing []
+ $ HashMap.singleton "philosopher"
+ $ Out.Resolver philosopherField
+ $ pure
+ $ Type.Object mempty
+ where
+ philosopherField =
+ Out.Field Nothing (Out.NonNullObjectType philosopherType) HashMap.empty
+
+philosopherType :: Out.ObjectType Identity
+philosopherType = Out.ObjectType "Philosopher" Nothing []
+ $ HashMap.fromList resolvers
+ where
+ resolvers =
+ [ ("firstName", firstNameResolver)
+ , ("lastName", lastNameResolver)
+ ]
+ firstNameResolver = Out.Resolver firstNameField $ pure $ Type.String "Friedrich"
+ lastNameResolver = Out.Resolver lastNameField $ pure $ Type.String "Nietzsche"
+ firstNameField = Out.Field Nothing (Out.NonNullScalarType string) HashMap.empty
+ lastNameField = Out.Field Nothing (Out.NonNullScalarType string) HashMap.empty
+
+spec :: Spec
+spec =
+ describe "execute" $ do
+ it "skips unknown fields" $
+ let expected = Aeson.object
+ [ "data" .= Aeson.object
+ [ "philosopher" .= Aeson.object
+ [ "firstName" .= ("Friedrich" :: String)
+ ]
+ ]
+ ]
+ execute' = execute schema (mempty :: HashMap Name Aeson.Value)
+ actual = runIdentity
+ $ either parseError execute'
+ $ parse document "" "{ philosopher { firstName surname } }"
+ in actual `shouldBe` expected
+ it "merges selections" $
+ let expected = Aeson.object
+ [ "data" .= Aeson.object
+ [ "philosopher" .= Aeson.object
+ [ "firstName" .= ("Friedrich" :: String)
+ , "lastName" .= ("Nietzsche" :: String)
+ ]
+ ]
+ ]
+ execute' = execute schema (mempty :: HashMap Name Aeson.Value)
+ actual = runIdentity
+ $ either parseError execute'
+ $ parse document "" "{ philosopher { firstName } philosopher { lastName } }"
+ in actual `shouldBe` expected
diff --git a/tests/Language/GraphQL/Type/OutSpec.hs b/tests/Language/GraphQL/Type/OutSpec.hs
new file mode 100644
index 0000000..eecc374
--- /dev/null
+++ b/tests/Language/GraphQL/Type/OutSpec.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Language.GraphQL.Type.OutSpec
+ ( spec
+ ) where
+
+import Language.GraphQL.Type
+import Test.Hspec (Spec, describe, it, shouldBe)
+
+spec :: Spec
+spec =
+ describe "Value" $
+ it "supports overloaded strings" $
+ let nietzsche = "Goldstaub abblasen." :: Value
+ in nietzsche `shouldBe` String "Goldstaub abblasen."