1
1
{-# LANGUAGE DataKinds #-}
2
+ {-# LANGUAGE DeriveGeneric #-}
2
3
{-# LANGUAGE QuasiQuotes #-}
4
+ {-# LANGUAGE TypeOperators #-}
3
5
-- | Tests that span the entire system.
4
6
--
5
7
-- These tests function both as examples of how to use the API, as well as
@@ -11,10 +13,10 @@ import Protolude
11
13
import Data.Aeson (Value (Null ), toJSON , object , (.=) )
12
14
import qualified Data.Map as Map
13
15
import GraphQL (makeSchema , compileQuery , executeQuery , interpretAnonymousQuery , interpretQuery )
14
- import GraphQL.API (Object , Field )
16
+ import GraphQL.API (Object , Field , Argument , (:>) , Defaultable ( .. ), HasAnnotatedInputType ( .. ) )
15
17
import GraphQL.Internal.Syntax.AST (Variable (.. ))
16
18
import GraphQL.Resolver ((:<>) (.. ), Handler )
17
- import GraphQL.Value (ToValue (.. ), makeName )
19
+ import GraphQL.Value (ToValue (.. ), FromValue ( .. ), makeName )
18
20
import Test.Tasty (TestTree )
19
21
import Test.Tasty.Hspec (testSpec , describe , it , shouldBe )
20
22
import Text.RawString.QQ (r )
@@ -26,14 +28,27 @@ import ExampleSchema
26
28
-- @
27
29
-- type QueryRoot {
28
30
-- dog: Dog
31
+ -- describeDog(dog: DEFAULT): String
29
32
-- }
30
33
-- @
31
34
--
32
35
-- Drawn from <https://facebook.github.io/graphql/#sec-Validation>.
33
36
type QueryRoot = Object " QueryRoot" '[]
34
37
'[ Field " dog" Dog
38
+ , Argument " dog" DogStuff :> Field " describeDog" Text
35
39
]
36
40
41
+ -- | An object that is passed as an argument. i.e. an input object.
42
+ --
43
+ -- TODO: Ideally this would be Dog itself, or ServerDog at worst.
44
+ -- Unfortunately, jml cannot figure out how to do that.
45
+ data DogStuff = DogStuff { toy :: Text , likesTreats :: Bool } deriving (Show , Generic )
46
+ instance FromValue DogStuff
47
+ instance HasAnnotatedInputType DogStuff
48
+ instance Defaultable DogStuff where
49
+ defaultFor " dog" = pure DogStuff { toy = " shoe" , likesTreats = False }
50
+ defaultFor _ = empty
51
+
37
52
-- | Our server's internal representation of a 'Dog'.
38
53
data ServerDog
39
54
= ServerDog
@@ -66,6 +81,14 @@ viewServerDog dog@ServerDog{..} = pure $
66
81
pure . isHouseTrained dog :<>
67
82
viewServerHuman owner
68
83
84
+ describeDog :: DogStuff -> Handler IO Text
85
+ describeDog (DogStuff toy likesTreats)
86
+ | likesTreats = pure $ " likes treats and their favorite toy is a " <> toy
87
+ | otherwise = pure $ " their favorite toy is a " <> toy
88
+
89
+ rootHandler :: ServerDog -> Handler IO QueryRoot
90
+ rootHandler dog = pure $ viewServerDog dog :<> describeDog
91
+
69
92
-- | jml has a stuffed black dog called "Mortgage".
70
93
mortgage :: ServerDog
71
94
mortgage = ServerDog
@@ -90,18 +113,18 @@ viewServerHuman (ServerHuman name) = pure (pure name)
90
113
jml :: ServerHuman
91
114
jml = ServerHuman " jml"
92
115
116
+
93
117
tests :: IO TestTree
94
118
tests = testSpec " End-to-end tests" $ do
95
119
describe " interpretAnonymousQuery" $ do
96
120
it " Handles the simplest possible valid query" $ do
97
- let root = pure (viewServerDog mortgage)
98
121
let query = [r |{
99
122
dog {
100
123
name
101
124
}
102
125
}
103
126
|]
104
- response <- interpretAnonymousQuery @ QueryRoot root query
127
+ response <- interpretAnonymousQuery @ QueryRoot (rootHandler mortgage) query
105
128
let expected =
106
129
object
107
130
[ " data" .= object
@@ -112,15 +135,14 @@ tests = testSpec "End-to-end tests" $ do
112
135
]
113
136
toJSON (toValue response) `shouldBe` expected
114
137
it " Handles more than one field" $ do
115
- let root = pure (viewServerDog mortgage)
116
138
let query = [r |{
117
139
dog {
118
140
name
119
141
barkVolume
120
142
}
121
143
}
122
144
|]
123
- response <- interpretAnonymousQuery @ QueryRoot root query
145
+ response <- interpretAnonymousQuery @ QueryRoot (rootHandler mortgage) query
124
146
let expected =
125
147
object
126
148
[ " data" .= object
@@ -132,7 +154,6 @@ tests = testSpec "End-to-end tests" $ do
132
154
]
133
155
toJSON (toValue response) `shouldBe` expected
134
156
it " Handles nested queries" $ do
135
- let root = pure (viewServerDog mortgage)
136
157
let query = [r |{
137
158
dog {
138
159
name
@@ -142,7 +163,7 @@ tests = testSpec "End-to-end tests" $ do
142
163
}
143
164
}
144
165
|]
145
- response <- interpretAnonymousQuery @ QueryRoot root query
166
+ response <- interpretAnonymousQuery @ QueryRoot (rootHandler mortgage) query
146
167
let expected =
147
168
object
148
169
[ " data" .= object
@@ -156,7 +177,6 @@ tests = testSpec "End-to-end tests" $ do
156
177
]
157
178
toJSON (toValue response) `shouldBe` expected
158
179
it " It aliases fields" $ do
159
- let root = pure (viewServerDog mortgage)
160
180
let query = [r |{
161
181
dog {
162
182
name
@@ -166,7 +186,7 @@ tests = testSpec "End-to-end tests" $ do
166
186
}
167
187
}
168
188
|]
169
- response <- interpretAnonymousQuery @ QueryRoot root query
189
+ response <- interpretAnonymousQuery @ QueryRoot (rootHandler mortgage) query
170
190
let expected =
171
191
object
172
192
[ " data" .= object
@@ -180,15 +200,14 @@ tests = testSpec "End-to-end tests" $ do
180
200
]
181
201
toJSON (toValue response) `shouldBe` expected
182
202
it " Passes arguments to functions" $ do
183
- let root = pure (viewServerDog mortgage)
184
203
let query = [r |{
185
204
dog {
186
205
name
187
206
doesKnowCommand(dogCommand: Sit)
188
207
}
189
208
}
190
209
|]
191
- response <- interpretAnonymousQuery @ QueryRoot root query
210
+ response <- interpretAnonymousQuery @ QueryRoot (rootHandler mortgage) query
192
211
let expected =
193
212
object
194
213
[ " data" .= object
@@ -199,8 +218,31 @@ tests = testSpec "End-to-end tests" $ do
199
218
]
200
219
]
201
220
toJSON (toValue response) `shouldBe` expected
221
+ it " Passes arguments that are objects to functions" $ do
222
+ let query = [r |{
223
+ describeDog(dog: {toy: "bone", likesTreats: true})
224
+ }
225
+ |]
226
+ response <- interpretAnonymousQuery @ QueryRoot (rootHandler mortgage) query
227
+ let expected =
228
+ object
229
+ [ " data" .= object
230
+ [ " describeDog" .= (" likes treats and their favorite toy is a bone" :: Text ) ]
231
+ ]
232
+ toJSON (toValue response) `shouldBe` expected
233
+ it " Passes default arguments that are objects to functions" $ do
234
+ let query = [r |{
235
+ describeDog
236
+ }
237
+ |]
238
+ response <- interpretAnonymousQuery @ QueryRoot (rootHandler mortgage) query
239
+ let expected =
240
+ object
241
+ [ " data" .= object
242
+ [ " describeDog" .= (" their favorite toy is a shoe" :: Text ) ]
243
+ ]
244
+ toJSON (toValue response) `shouldBe` expected
202
245
it " Handles fairly complex queries" $ do
203
- let root = pure (viewServerDog mortgage)
204
246
-- TODO: jml would like to put some union checks in here, but we don't
205
247
-- have any unions reachable from Dog!
206
248
let query = [r |{
@@ -221,7 +263,7 @@ tests = testSpec "End-to-end tests" $ do
221
263
}
222
264
}
223
265
|]
224
- response <- interpretAnonymousQuery @ QueryRoot root query
266
+ response <- interpretAnonymousQuery @ QueryRoot (rootHandler mortgage) query
225
267
let expected =
226
268
object
227
269
[ " data" .= object
@@ -236,14 +278,13 @@ tests = testSpec "End-to-end tests" $ do
236
278
toJSON (toValue response) `shouldBe` expected
237
279
describe " interpretQuery" $ do
238
280
it " Handles the simplest named query" $ do
239
- let root = pure (viewServerDog mortgage)
240
281
let query = [r |query myQuery {
241
282
dog {
242
283
name
243
284
}
244
285
}
245
286
|]
246
- response <- interpretQuery @ QueryRoot root query Nothing mempty
287
+ response <- interpretQuery @ QueryRoot (rootHandler mortgage) query Nothing mempty
247
288
let expected =
248
289
object
249
290
[ " data" .= object
@@ -254,15 +295,14 @@ tests = testSpec "End-to-end tests" $ do
254
295
]
255
296
toJSON (toValue response) `shouldBe` expected
256
297
it " Allows calling query by name" $ do
257
- let root = pure (viewServerDog mortgage)
258
298
let query = [r |query myQuery {
259
299
dog {
260
300
name
261
301
}
262
302
}
263
303
|]
264
304
let Right name = makeName " myQuery"
265
- response <- interpretQuery @ QueryRoot root query (Just name) mempty
305
+ response <- interpretQuery @ QueryRoot (rootHandler mortgage) query (Just name) mempty
266
306
let expected =
267
307
object
268
308
[ " data" .= object
@@ -273,7 +313,6 @@ tests = testSpec "End-to-end tests" $ do
273
313
]
274
314
toJSON (toValue response) `shouldBe` expected
275
315
describe " Handles variables" $ do
276
- let root = pure (viewServerDog mortgage)
277
316
let Right schema = makeSchema @ Dog
278
317
let Right query =
279
318
compileQuery schema
@@ -285,7 +324,7 @@ tests = testSpec "End-to-end tests" $ do
285
324
}
286
325
|]
287
326
it " Errors when no variables provided" $ do
288
- response <- executeQuery @ QueryRoot root query Nothing mempty
327
+ response <- executeQuery @ QueryRoot (rootHandler mortgage) query Nothing mempty
289
328
let expected =
290
329
object
291
330
[ " data" .= object
@@ -315,7 +354,7 @@ tests = testSpec "End-to-end tests" $ do
315
354
-- <https://github.com/jml/graphql-api/issues/96>
316
355
let Right varName = makeName " whichCommand"
317
356
let vars = Map. singleton (Variable varName) (toValue Sit )
318
- response <- executeQuery @ QueryRoot root query Nothing vars
357
+ response <- executeQuery @ QueryRoot (rootHandler mortgage) query Nothing vars
319
358
let expected =
320
359
object
321
360
[ " data" .= object
0 commit comments