summaryrefslogtreecommitdiff
path: root/tests/Test/StarWars/QuerySpec.hs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/Test/StarWars/QuerySpec.hs')
-rw-r--r--tests/Test/StarWars/QuerySpec.hs351
1 files changed, 351 insertions, 0 deletions
diff --git a/tests/Test/StarWars/QuerySpec.hs b/tests/Test/StarWars/QuerySpec.hs
new file mode 100644
index 0000000..0f6a2ef
--- /dev/null
+++ b/tests/Test/StarWars/QuerySpec.hs
@@ -0,0 +1,351 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+module Test.StarWars.QuerySpec
+ ( spec
+ ) where
+
+import qualified Data.Aeson as Aeson
+import Data.Aeson ( object
+ , (.=)
+ )
+import Data.Text (Text)
+import Language.GraphQL
+import Language.GraphQL.Schema (Subs)
+import Text.RawString.QQ (r)
+import Test.Hspec.Expectations ( Expectation
+ , shouldBe
+ )
+import Test.Hspec ( Spec
+ , describe
+ , it
+ )
+import Test.StarWars.Schema
+
+-- * Test
+-- See https://github.com/graphql/graphql-js/blob/master/src/__tests__/starWarsQueryTests.js
+
+spec :: Spec
+spec = describe "Star Wars Query Tests" $ do
+ describe "Basic Queries" $ do
+ it "R2-D2 hero" $ testQuery
+ [r| query HeroNameQuery {
+ hero {
+ id
+ }
+ }
+ |]
+ $ object [ "data" .= object ["hero" .= object ["id" .= ("2001" :: Text)]]]
+ it "R2-D2 ID and friends" $ testQuery
+ [r| query HeroNameAndFriendsQuery {
+ hero {
+ id
+ name
+ friends {
+ name
+ }
+ }
+ }
+ |]
+ $ object [ "data" .= object [
+ "hero" .= object
+ [ "id" .= ("2001" :: Text)
+ , r2d2Name
+ , "friends" .=
+ [ object [lukeName]
+ , object [hanName]
+ , object [leiaName]
+ ]
+ ]
+ ]]
+
+ describe "Nested Queries" $ do
+ it "R2-D2 friends" $ testQuery
+ [r| query NestedQuery {
+ hero {
+ name
+ friends {
+ name
+ appearsIn
+ friends {
+ name
+ }
+ }
+ }
+ }
+ |]
+ $ object [ "data" .= object [
+ "hero" .= object [
+ "name" .= ("R2-D2" :: Text)
+ , "friends" .= [
+ object [
+ "name" .= ("Luke Skywalker" :: Text)
+ , "appearsIn" .= ["NEWHOPE","EMPIRE","JEDI" :: Text]
+ , "friends" .= [
+ object [hanName]
+ , object [leiaName]
+ , object [c3poName]
+ , object [r2d2Name]
+ ]
+ ]
+ , object [
+ hanName
+ , "appearsIn" .= [ "NEWHOPE","EMPIRE","JEDI" :: Text]
+ , "friends" .= [
+ object [lukeName]
+ , object [leiaName]
+ , object [r2d2Name]
+ ]
+ ]
+ , object [
+ leiaName
+ , "appearsIn" .= [ "NEWHOPE","EMPIRE","JEDI" :: Text]
+ , "friends" .= [
+ object [lukeName]
+ , object [hanName]
+ , object [c3poName]
+ , object [r2d2Name]
+ ]
+ ]
+ ]
+ ]
+ ]]
+ it "Luke ID" $ testQuery
+ [r| query FetchLukeQuery {
+ human(id: "1000") {
+ name
+ }
+ }
+ |]
+ $ object [ "data" .= object [
+ "human" .= object [lukeName]
+ ]]
+
+ it "Luke ID with variable" $ testQueryParams
+ (\v -> if v == "someId" then Just "1000" else Nothing)
+ [r| query FetchSomeIDQuery($someId: String!) {
+ human(id: $someId) {
+ name
+ }
+ }
+ |]
+ $ object [ "data" .= object [
+ "human" .= object [lukeName]
+ ]]
+ it "Han ID with variable" $ testQueryParams
+ (\v -> if v == "someId" then Just "1002" else Nothing)
+ [r| query FetchSomeIDQuery($someId: String!) {
+ human(id: $someId) {
+ name
+ }
+ }
+ |]
+ $ object [ "data" .= object [
+ "human" .= object [hanName]
+ ]]
+ it "Invalid ID" $ testQueryParams
+ (\v -> if v == "id" then Just "Not a valid ID" else Nothing)
+ [r| query humanQuery($id: String!) {
+ human(id: $id) {
+ name
+ }
+ }
+ |] $ object ["data" .= object ["human" .= Aeson.Null]]
+ it "Luke aliased" $ testQuery
+ [r| query FetchLukeAliased {
+ luke: human(id: "1000") {
+ name
+ }
+ }
+ |]
+ $ object [ "data" .= object [
+ "luke" .= object [lukeName]
+ ]]
+ it "R2-D2 ID and friends aliased" $ testQuery
+ [r| query HeroNameAndFriendsQuery {
+ hero {
+ id
+ name
+ friends {
+ friendName: name
+ }
+ }
+ }
+ |]
+ $ object [ "data" .= object [
+ "hero" .= object [
+ "id" .= ("2001" :: Text)
+ , r2d2Name
+ , "friends" .= [
+ object ["friendName" .= ("Luke Skywalker" :: Text)]
+ , object ["friendName" .= ("Han Solo" :: Text)]
+ , object ["friendName" .= ("Leia Organa" :: Text)]
+ ]
+ ]
+ ]]
+ it "Luke and Leia aliased" $ testQuery
+ [r| query FetchLukeAndLeiaAliased {
+ luke: human(id: "1000") {
+ name
+ }
+ leia: human(id: "1003") {
+ name
+ }
+ }
+ |]
+ $ object [ "data" .= object [
+ "luke" .= object [lukeName]
+ , "leia" .= object [leiaName]
+ ]]
+
+ describe "Fragments for complex queries" $ do
+ it "Aliases to query for duplicate content" $ testQuery
+ [r| query DuplicateFields {
+ luke: human(id: "1000") {
+ name
+ homePlanet
+ }
+ leia: human(id: "1003") {
+ name
+ homePlanet
+ }
+ }
+ |]
+ $ object [ "data" .= object [
+ "luke" .= object [lukeName, tatooine]
+ , "leia" .= object [leiaName, alderaan]
+ ]]
+ it "Fragment for duplicate content" $ testQuery
+ [r| query UseFragment {
+ luke: human(id: "1000") {
+ ...HumanFragment
+ }
+ leia: human(id: "1003") {
+ ...HumanFragment
+ }
+ }
+ fragment HumanFragment on Human {
+ name
+ homePlanet
+ }
+ |]
+ $ object [ "data" .= object [
+ "luke" .= object [lukeName, tatooine]
+ , "leia" .= object [leiaName, alderaan]
+ ]]
+
+ describe "__typename" $ do
+ it "R2D2 is a Droid" $ testQuery
+ [r| query CheckTypeOfR2 {
+ hero {
+ __typename
+ name
+ }
+ }
+ |]
+ $ object ["data" .= object [
+ "hero" .= object ["__typename" .= ("Droid" :: Text), r2d2Name]
+ ]]
+ it "Luke is a human" $ testQuery
+ [r| query CheckTypeOfLuke {
+ hero(episode: EMPIRE) {
+ __typename
+ name
+ }
+ }
+ |]
+ $ object ["data" .= object [
+ "hero" .= object ["__typename" .= ("Human" :: Text), lukeName]
+ ]]
+
+ describe "Errors in resolvers" $ do
+ it "error on secretBackstory" $ testQuery
+ [r|
+ query HeroNameQuery {
+ hero {
+ name
+ secretBackstory
+ }
+ }
+ |]
+ $ object
+ [ "data" .= object
+ [ "hero" .= object
+ [ "name" .= ("R2-D2" :: Text)
+ , "secretBackstory" .= Aeson.Null
+ ]
+ ]
+ , "errors" .=
+ [ object
+ ["message" .= ("secretBackstory is secret." :: Text)]
+ ]
+ ]
+ it "Error in a list" $ testQuery
+ [r| query HeroNameQuery {
+ hero {
+ name
+ friends {
+ name
+ secretBackstory
+ }
+ }
+ }
+ |]
+ $ object ["data" .= object
+ [ "hero" .= object
+ [ "name" .= ("R2-D2" :: Text)
+ , "friends" .=
+ [ object
+ [ "name" .= ("Luke Skywalker" :: Text)
+ , "secretBackstory" .= Aeson.Null
+ ]
+ , object
+ [ "name" .= ("Han Solo" :: Text)
+ , "secretBackstory" .= Aeson.Null
+ ]
+ , object
+ [ "name" .= ("Leia Organa" :: Text)
+ , "secretBackstory" .= Aeson.Null
+ ]
+ ]
+ ]
+ ]
+ , "errors" .=
+ [ object ["message" .= ("secretBackstory is secret." :: Text)]
+ , object ["message" .= ("secretBackstory is secret." :: Text)]
+ , object ["message" .= ("secretBackstory is secret." :: Text)]
+ ]
+ ]
+ it "error on secretBackstory with alias" $ testQuery
+ [r| query HeroNameQuery {
+ mainHero: hero {
+ name
+ story: secretBackstory
+ }
+ }
+ |]
+ $ object
+ [ "data" .= object
+ [ "mainHero" .= object
+ [ "name" .= ("R2-D2" :: Text)
+ , "story" .= Aeson.Null
+ ]
+ ]
+ , "errors" .=
+ [ object ["message" .= ("secretBackstory is secret." :: Text)]
+ ]
+ ]
+
+ where
+ lukeName = "name" .= ("Luke Skywalker" :: Text)
+ leiaName = "name" .= ("Leia Organa" :: Text)
+ hanName = "name" .= ("Han Solo" :: Text)
+ r2d2Name = "name" .= ("R2-D2" :: Text)
+ c3poName = "name" .= ("C-3PO" :: Text)
+ tatooine = "homePlanet" .= ("Tatooine" :: Text)
+ alderaan = "homePlanet" .= ("Alderaan" :: Text)
+
+testQuery :: Text -> Aeson.Value -> Expectation
+testQuery q expected = graphql schema q >>= flip shouldBe expected
+
+testQueryParams :: Subs -> Text -> Aeson.Value -> Expectation
+testQueryParams f q expected = graphqlSubs schema f q >>= flip shouldBe expected