diff options
Diffstat (limited to 'tests/Language')
| -rw-r--r-- | tests/Language/GraphQL/AST/ParserSpec.hs | 11 | ||||
| -rw-r--r-- | tests/Language/GraphQL/Execute/CoerceSpec.hs | 122 | ||||
| -rw-r--r-- | tests/Language/GraphQL/ExecuteSpec.hs | 75 | ||||
| -rw-r--r-- | tests/Language/GraphQL/Type/OutSpec.hs | 14 |
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." |
