graphql 0.17.2 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql.rb +1 -0
- data/lib/graphql/analysis/query_depth.rb +1 -1
- data/lib/graphql/base_type.rb +25 -1
- data/lib/graphql/define.rb +2 -0
- data/lib/graphql/define/assign_connection.rb +11 -0
- data/lib/graphql/define/assign_global_id_field.rb +11 -0
- data/lib/graphql/define/assign_object_field.rb +21 -20
- data/lib/graphql/define/defined_object_proxy.rb +2 -2
- data/lib/graphql/define/instance_definable.rb +13 -3
- data/lib/graphql/field.rb +1 -1
- data/lib/graphql/language/generation.rb +57 -6
- data/lib/graphql/language/lexer.rb +434 -212
- data/lib/graphql/language/lexer.rl +18 -0
- data/lib/graphql/language/nodes.rb +75 -0
- data/lib/graphql/language/parser.rb +853 -341
- data/lib/graphql/language/parser.y +114 -17
- data/lib/graphql/query.rb +15 -1
- data/lib/graphql/relay.rb +13 -0
- data/lib/graphql/relay/array_connection.rb +80 -0
- data/lib/graphql/relay/base_connection.rb +138 -0
- data/lib/graphql/relay/connection_field.rb +54 -0
- data/lib/graphql/relay/connection_type.rb +25 -0
- data/lib/graphql/relay/edge.rb +22 -0
- data/lib/graphql/relay/edge_type.rb +14 -0
- data/lib/graphql/relay/global_id_resolve.rb +15 -0
- data/lib/graphql/relay/global_node_identification.rb +124 -0
- data/lib/graphql/relay/mutation.rb +146 -0
- data/lib/graphql/relay/page_info.rb +13 -0
- data/lib/graphql/relay/relation_connection.rb +98 -0
- data/lib/graphql/schema.rb +3 -0
- data/lib/graphql/schema/printer.rb +12 -2
- data/lib/graphql/static_validation/message.rb +9 -5
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +7 -7
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +6 -6
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +17 -9
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +17 -6
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +2 -2
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +5 -5
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +12 -11
- data/lib/graphql/static_validation/type_stack.rb +33 -2
- data/lib/graphql/static_validation/validation_context.rb +5 -0
- data/lib/graphql/version.rb +1 -1
- data/readme.md +16 -4
- data/spec/graphql/analysis/analyze_query_spec.rb +31 -2
- data/spec/graphql/analysis/query_complexity_spec.rb +24 -0
- data/spec/graphql/argument_spec.rb +1 -1
- data/spec/graphql/define/instance_definable_spec.rb +9 -0
- data/spec/graphql/field_spec.rb +1 -1
- data/spec/graphql/internal_representation/rewrite_spec.rb +3 -3
- data/spec/graphql/language/generation_spec.rb +25 -4
- data/spec/graphql/language/parser_spec.rb +116 -1
- data/spec/graphql/query_spec.rb +10 -0
- data/spec/graphql/relay/array_connection_spec.rb +164 -0
- data/spec/graphql/relay/connection_type_spec.rb +37 -0
- data/spec/graphql/relay/global_node_identification_spec.rb +149 -0
- data/spec/graphql/relay/mutation_spec.rb +55 -0
- data/spec/graphql/relay/page_info_spec.rb +106 -0
- data/spec/graphql/relay/relation_connection_spec.rb +348 -0
- data/spec/graphql/schema/printer_spec.rb +8 -0
- data/spec/graphql/schema/reduce_types_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +12 -6
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +8 -4
- data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +7 -2
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +5 -3
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +5 -2
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +10 -2
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +8 -4
- data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +8 -4
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +6 -3
- data/spec/spec_helper.rb +7 -0
- data/spec/support/dairy_app.rb +11 -10
- data/spec/support/star_wars_data.rb +65 -58
- data/spec/support/star_wars_schema.rb +192 -54
- metadata +84 -2
@@ -0,0 +1,348 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GraphQL::Relay::RelationConnection do
|
4
|
+
def get_names(result)
|
5
|
+
ships = result["data"]["empire"]["bases"]["edges"]
|
6
|
+
names = ships.map { |e| e["node"]["name"] }
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_page_info(result)
|
10
|
+
result["data"]["empire"]["bases"]["pageInfo"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_first_cursor(result)
|
14
|
+
result["data"]["empire"]["bases"]["edges"].first["cursor"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_last_cursor(result)
|
18
|
+
result["data"]["empire"]["bases"]["edges"].last["cursor"]
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "results" do
|
22
|
+
let(:query_string) {%|
|
23
|
+
query getShips($first: Int, $after: String, $last: Int, $before: String, $nameIncludes: String){
|
24
|
+
empire {
|
25
|
+
bases(first: $first, after: $after, last: $last, before: $before, nameIncludes: $nameIncludes) {
|
26
|
+
... basesConnection
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
fragment basesConnection on BasesConnectionWithTotalCount {
|
32
|
+
totalCount,
|
33
|
+
edges {
|
34
|
+
cursor
|
35
|
+
node {
|
36
|
+
name
|
37
|
+
}
|
38
|
+
},
|
39
|
+
pageInfo {
|
40
|
+
hasNextPage
|
41
|
+
hasPreviousPage
|
42
|
+
startCursor
|
43
|
+
endCursor
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|}
|
47
|
+
|
48
|
+
it 'limits the result' do
|
49
|
+
result = query(query_string, "first" => 2)
|
50
|
+
assert_equal(2, get_names(result).length)
|
51
|
+
assert_equal(true, get_page_info(result)["hasNextPage"])
|
52
|
+
assert_equal(false, get_page_info(result)["hasPreviousPage"])
|
53
|
+
assert_equal("MQ==", get_page_info(result)["startCursor"])
|
54
|
+
assert_equal("Mg==", get_page_info(result)["endCursor"])
|
55
|
+
assert_equal("MQ==", get_first_cursor(result))
|
56
|
+
assert_equal("Mg==", get_last_cursor(result))
|
57
|
+
|
58
|
+
result = query(query_string, "first" => 3)
|
59
|
+
assert_equal(3, get_names(result).length)
|
60
|
+
assert_equal(false, get_page_info(result)["hasNextPage"])
|
61
|
+
assert_equal(false, get_page_info(result)["hasPreviousPage"])
|
62
|
+
assert_equal("MQ==", get_page_info(result)["startCursor"])
|
63
|
+
assert_equal("Mw==", get_page_info(result)["endCursor"])
|
64
|
+
assert_equal("MQ==", get_first_cursor(result))
|
65
|
+
assert_equal("Mw==", get_last_cursor(result))
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'provides custom fields on the connection type' do
|
69
|
+
result = query(query_string, "first" => 2)
|
70
|
+
assert_equal(
|
71
|
+
Base.where(faction_id: 2).count,
|
72
|
+
result["data"]["empire"]["bases"]["totalCount"]
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'slices the result' do
|
77
|
+
result = query(query_string, "first" => 2)
|
78
|
+
assert_equal(["Death Star", "Shield Generator"], get_names(result))
|
79
|
+
|
80
|
+
# After the last result, find the next 2:
|
81
|
+
last_cursor = get_last_cursor(result)
|
82
|
+
|
83
|
+
result = query(query_string, "after" => last_cursor, "first" => 2)
|
84
|
+
assert_equal(["Headquarters"], get_names(result))
|
85
|
+
|
86
|
+
last_cursor = get_last_cursor(result)
|
87
|
+
|
88
|
+
result = query(query_string, "before" => last_cursor, "last" => 1)
|
89
|
+
assert_equal(["Shield Generator"], get_names(result))
|
90
|
+
|
91
|
+
result = query(query_string, "before" => last_cursor, "last" => 2)
|
92
|
+
assert_equal(["Death Star", "Shield Generator"], get_names(result))
|
93
|
+
|
94
|
+
result = query(query_string, "before" => last_cursor, "last" => 10)
|
95
|
+
assert_equal(["Death Star", "Shield Generator"], get_names(result))
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
it "applies custom arguments" do
|
100
|
+
result = query(query_string, "first" => 1, "nameIncludes" => "ea")
|
101
|
+
assert_equal(["Death Star"], get_names(result))
|
102
|
+
|
103
|
+
after = get_last_cursor(result)
|
104
|
+
|
105
|
+
result = query(query_string, "first" => 2, "nameIncludes" => "ea", "after" => after )
|
106
|
+
assert_equal(["Headquarters"], get_names(result))
|
107
|
+
before = get_last_cursor(result)
|
108
|
+
|
109
|
+
result = query(query_string, "last" => 1, "nameIncludes" => "ea", "before" => before)
|
110
|
+
assert_equal(["Death Star"], get_names(result))
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'works without first/last/after/before' do
|
114
|
+
result = query(query_string)
|
115
|
+
|
116
|
+
assert_equal(3, result["data"]["empire"]["bases"]["edges"].length)
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "applying max_page_size" do
|
120
|
+
let(:query_string) {%|
|
121
|
+
query getBases($first: Int, $after: String, $last: Int, $before: String){
|
122
|
+
empire {
|
123
|
+
bases: basesWithMaxLimitRelation(first: $first, after: $after, last: $last, before: $before) {
|
124
|
+
... basesConnection
|
125
|
+
}
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
fragment basesConnection on BaseConnection {
|
130
|
+
edges {
|
131
|
+
cursor
|
132
|
+
node {
|
133
|
+
name
|
134
|
+
}
|
135
|
+
},
|
136
|
+
pageInfo {
|
137
|
+
hasNextPage
|
138
|
+
hasPreviousPage
|
139
|
+
startCursor
|
140
|
+
endCursor
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|}
|
144
|
+
|
145
|
+
it "applies to queries by `first`" do
|
146
|
+
result = query(query_string, "first" => 100)
|
147
|
+
assert_equal(2, result["data"]["empire"]["bases"]["edges"].size)
|
148
|
+
assert_equal(true, result["data"]["empire"]["bases"]["pageInfo"]["hasNextPage"])
|
149
|
+
|
150
|
+
# Max page size is applied _without_ `first`, also
|
151
|
+
result = query(query_string)
|
152
|
+
assert_equal(2, result["data"]["empire"]["bases"]["edges"].size)
|
153
|
+
assert_equal(false, result["data"]["empire"]["bases"]["pageInfo"]["hasNextPage"], "hasNextPage is false when first is not specified")
|
154
|
+
end
|
155
|
+
|
156
|
+
it "applies to queries by `last`" do
|
157
|
+
last_cursor = "Ng=="
|
158
|
+
second_to_last_two_names = ["Death Star", "Shield Generator"]
|
159
|
+
result = query(query_string, "last" => 100, "before" => last_cursor)
|
160
|
+
assert_equal(second_to_last_two_names, get_names(result))
|
161
|
+
assert_equal(true, result["data"]["empire"]["bases"]["pageInfo"]["hasPreviousPage"])
|
162
|
+
|
163
|
+
result = query(query_string, "before" => last_cursor)
|
164
|
+
assert_equal(second_to_last_two_names, get_names(result))
|
165
|
+
assert_equal(false, result["data"]["empire"]["bases"]["pageInfo"]["hasPreviousPage"], "hasPreviousPage is false when last is not specified")
|
166
|
+
|
167
|
+
third_cursor = "Mw=="
|
168
|
+
first_and_second_names = ["Yavin", "Echo Base"]
|
169
|
+
result = query(query_string, "last" => 100, "before" => third_cursor)
|
170
|
+
assert_equal(first_and_second_names, get_names(result))
|
171
|
+
|
172
|
+
result = query(query_string, "before" => third_cursor)
|
173
|
+
assert_equal(first_and_second_names, get_names(result))
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "without a block" do
|
179
|
+
let(:query_string) {%|
|
180
|
+
{
|
181
|
+
empire {
|
182
|
+
basesClone(first: 10) {
|
183
|
+
edges {
|
184
|
+
node {
|
185
|
+
name
|
186
|
+
}
|
187
|
+
}
|
188
|
+
}
|
189
|
+
}
|
190
|
+
}|}
|
191
|
+
it "uses default resolve" do
|
192
|
+
result = query(query_string)
|
193
|
+
bases = result["data"]["empire"]["basesClone"]["edges"]
|
194
|
+
assert_equal(3, bases.length)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe "custom ordering" do
|
199
|
+
let(:query_string) {%|
|
200
|
+
query getBases {
|
201
|
+
empire {
|
202
|
+
basesByName(first: 30) { ... basesFields }
|
203
|
+
bases(first: 30) { ... basesFields2 }
|
204
|
+
}
|
205
|
+
}
|
206
|
+
fragment basesFields on BaseConnection {
|
207
|
+
edges {
|
208
|
+
node {
|
209
|
+
name
|
210
|
+
}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
fragment basesFields2 on BasesConnectionWithTotalCount {
|
214
|
+
edges {
|
215
|
+
node {
|
216
|
+
name
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|}
|
221
|
+
|
222
|
+
def get_names(result, field_name)
|
223
|
+
bases = result["data"]["empire"][field_name]["edges"]
|
224
|
+
base_names = bases.map { |b| b["node"]["name"] }
|
225
|
+
end
|
226
|
+
|
227
|
+
it "applies the default value" do
|
228
|
+
result = query(query_string)
|
229
|
+
bases_by_id = ["Death Star", "Shield Generator", "Headquarters"]
|
230
|
+
bases_by_name = ["Death Star", "Headquarters", "Shield Generator"]
|
231
|
+
|
232
|
+
assert_equal(bases_by_id, get_names(result, "bases"))
|
233
|
+
assert_equal(bases_by_name, get_names(result, "basesByName"))
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "with a Sequel::Dataset" do
|
238
|
+
def get_names(result)
|
239
|
+
ships = result["data"]["empire"]["basesAsSequelDataset"]["edges"]
|
240
|
+
names = ships.map { |e| e["node"]["name"] }
|
241
|
+
end
|
242
|
+
|
243
|
+
def get_page_info(result)
|
244
|
+
result["data"]["empire"]["basesAsSequelDataset"]["pageInfo"]
|
245
|
+
end
|
246
|
+
|
247
|
+
def get_first_cursor(result)
|
248
|
+
result["data"]["empire"]["basesAsSequelDataset"]["edges"].first["cursor"]
|
249
|
+
end
|
250
|
+
|
251
|
+
def get_last_cursor(result)
|
252
|
+
result["data"]["empire"]["basesAsSequelDataset"]["edges"].last["cursor"]
|
253
|
+
end
|
254
|
+
|
255
|
+
describe "results" do
|
256
|
+
let(:query_string) {%|
|
257
|
+
query getShips($first: Int, $after: String, $last: Int, $before: String, $nameIncludes: String){
|
258
|
+
empire {
|
259
|
+
basesAsSequelDataset(first: $first, after: $after, last: $last, before: $before, nameIncludes: $nameIncludes) {
|
260
|
+
... basesConnection
|
261
|
+
}
|
262
|
+
}
|
263
|
+
}
|
264
|
+
|
265
|
+
fragment basesConnection on BasesConnectionWithTotalCount {
|
266
|
+
totalCount,
|
267
|
+
edges {
|
268
|
+
cursor
|
269
|
+
node {
|
270
|
+
name
|
271
|
+
}
|
272
|
+
},
|
273
|
+
pageInfo {
|
274
|
+
hasNextPage
|
275
|
+
hasPreviousPage
|
276
|
+
startCursor
|
277
|
+
endCursor
|
278
|
+
}
|
279
|
+
}
|
280
|
+
|}
|
281
|
+
|
282
|
+
it 'limits the result' do
|
283
|
+
result = query(query_string, "first" => 2)
|
284
|
+
assert_equal(2, get_names(result).length)
|
285
|
+
assert_equal(true, get_page_info(result)["hasNextPage"])
|
286
|
+
assert_equal(false, get_page_info(result)["hasPreviousPage"])
|
287
|
+
assert_equal("MQ==", get_page_info(result)["startCursor"])
|
288
|
+
assert_equal("Mg==", get_page_info(result)["endCursor"])
|
289
|
+
assert_equal("MQ==", get_first_cursor(result))
|
290
|
+
assert_equal("Mg==", get_last_cursor(result))
|
291
|
+
|
292
|
+
result = query(query_string, "first" => 3)
|
293
|
+
assert_equal(3, get_names(result).length)
|
294
|
+
assert_equal(false, get_page_info(result)["hasNextPage"])
|
295
|
+
assert_equal(false, get_page_info(result)["hasPreviousPage"])
|
296
|
+
assert_equal("MQ==", get_page_info(result)["startCursor"])
|
297
|
+
assert_equal("Mw==", get_page_info(result)["endCursor"])
|
298
|
+
assert_equal("MQ==", get_first_cursor(result))
|
299
|
+
assert_equal("Mw==", get_last_cursor(result))
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'provides custom fields on the connection type' do
|
303
|
+
result = query(query_string, "first" => 2)
|
304
|
+
assert_equal(
|
305
|
+
Base.where(faction_id: 2).count,
|
306
|
+
result["data"]["empire"]["basesAsSequelDataset"]["totalCount"]
|
307
|
+
)
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'slices the result' do
|
311
|
+
result = query(query_string, "first" => 2)
|
312
|
+
assert_equal(["Death Star", "Shield Generator"], get_names(result))
|
313
|
+
|
314
|
+
# After the last result, find the next 2:
|
315
|
+
last_cursor = get_last_cursor(result)
|
316
|
+
|
317
|
+
result = query(query_string, "after" => last_cursor, "first" => 2)
|
318
|
+
assert_equal(["Headquarters"], get_names(result))
|
319
|
+
|
320
|
+
last_cursor = get_last_cursor(result)
|
321
|
+
|
322
|
+
result = query(query_string, "before" => last_cursor, "last" => 1)
|
323
|
+
assert_equal(["Shield Generator"], get_names(result))
|
324
|
+
|
325
|
+
result = query(query_string, "before" => last_cursor, "last" => 2)
|
326
|
+
assert_equal(["Death Star", "Shield Generator"], get_names(result))
|
327
|
+
|
328
|
+
result = query(query_string, "before" => last_cursor, "last" => 10)
|
329
|
+
assert_equal(["Death Star", "Shield Generator"], get_names(result))
|
330
|
+
|
331
|
+
end
|
332
|
+
|
333
|
+
it "applies custom arguments" do
|
334
|
+
result = query(query_string, "first" => 1, "nameIncludes" => "ea")
|
335
|
+
assert_equal(["Death Star"], get_names(result))
|
336
|
+
|
337
|
+
after = get_last_cursor(result)
|
338
|
+
|
339
|
+
result = query(query_string, "first" => 2, "nameIncludes" => "ea", "after" => after )
|
340
|
+
assert_equal(["Headquarters"], get_names(result))
|
341
|
+
before = get_last_cursor(result)
|
342
|
+
|
343
|
+
result = query(query_string, "last" => 1, "nameIncludes" => "ea", "before" => before)
|
344
|
+
assert_equal(["Death Star"], get_names(result))
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
@@ -66,6 +66,10 @@ describe GraphQL::Schema::Printer do
|
|
66
66
|
describe ".print_introspection_schema" do
|
67
67
|
it "returns the schema as a string for the introspection types" do
|
68
68
|
expected = <<SCHEMA
|
69
|
+
schema {
|
70
|
+
query: Query
|
71
|
+
}
|
72
|
+
|
69
73
|
type __Directive {
|
70
74
|
name: String!
|
71
75
|
description: String
|
@@ -147,6 +151,10 @@ SCHEMA
|
|
147
151
|
describe ".print_schema" do
|
148
152
|
it "returns the schema as a string for the defined types" do
|
149
153
|
expected = <<SCHEMA
|
154
|
+
schema {
|
155
|
+
query: Query
|
156
|
+
}
|
157
|
+
|
150
158
|
enum Choice {
|
151
159
|
FOO
|
152
160
|
BAR
|
@@ -26,37 +26,43 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
|
|
26
26
|
|
27
27
|
query_root_error = {
|
28
28
|
"message"=>"Argument 'id' on Field 'cheese' has an invalid value",
|
29
|
-
"locations"=>[{"line"=>3, "column"=>7}]
|
29
|
+
"locations"=>[{"line"=>3, "column"=>7}],
|
30
|
+
"path"=>["query getCheese", "cheese", "id"],
|
30
31
|
}
|
31
32
|
assert_includes(errors, query_root_error)
|
32
33
|
|
33
34
|
directive_error = {
|
34
35
|
"message"=>"Argument 'if' on Directive 'skip' has an invalid value",
|
35
|
-
"locations"=>[{"line"=>4, "column"=>30}]
|
36
|
+
"locations"=>[{"line"=>4, "column"=>30}],
|
37
|
+
"path"=>["query getCheese", "cheese", "source", "if"],
|
36
38
|
}
|
37
39
|
assert_includes(errors, directive_error)
|
38
40
|
|
39
41
|
input_object_error = {
|
40
42
|
"message"=>"Argument 'product' on Field 'badSource' has an invalid value",
|
41
|
-
"locations"=>[{"line"=>6, "column"=>7}]
|
43
|
+
"locations"=>[{"line"=>6, "column"=>7}],
|
44
|
+
"path"=>["query getCheese", "badSource", "product"],
|
42
45
|
}
|
43
46
|
assert_includes(errors, input_object_error)
|
44
47
|
|
45
48
|
input_object_field_error = {
|
46
49
|
"message"=>"Argument 'source' on InputObject 'DairyProductInput' has an invalid value",
|
47
|
-
"locations"=>[{"line"=>6, "column"=>40}]
|
50
|
+
"locations"=>[{"line"=>6, "column"=>40}],
|
51
|
+
"path"=>["query getCheese", "badSource", "product", "source"],
|
48
52
|
}
|
49
53
|
assert_includes(errors, input_object_field_error)
|
50
54
|
|
51
55
|
missing_required_field_error = {
|
52
56
|
"message"=>"Argument 'product' on Field 'missingSource' has an invalid value",
|
53
|
-
"locations"=>[{"line"=>7, "column"=>7}]
|
57
|
+
"locations"=>[{"line"=>7, "column"=>7}],
|
58
|
+
"path"=>["query getCheese", "missingSource", "product"],
|
54
59
|
}
|
55
60
|
assert_includes(errors, missing_required_field_error)
|
56
61
|
|
57
62
|
fragment_error = {
|
58
63
|
"message"=>"Argument 'source' on Field 'similarCheese' has an invalid value",
|
59
|
-
"locations"=>[{"line"=>13, "column"=>7}]
|
64
|
+
"locations"=>[{"line"=>13, "column"=>7}],
|
65
|
+
"path"=>["fragment cheeseFields", "similarCheese", "source"],
|
60
66
|
}
|
61
67
|
assert_includes(errors, fragment_error)
|
62
68
|
end
|
@@ -23,25 +23,29 @@ describe GraphQL::StaticValidation::ArgumentsAreDefined do
|
|
23
23
|
|
24
24
|
query_root_error = {
|
25
25
|
"message"=>"Field 'cheese' doesn't accept argument 'silly'",
|
26
|
-
"locations"=>[{"line"=>4, "column"=>7}]
|
26
|
+
"locations"=>[{"line"=>4, "column"=>7}],
|
27
|
+
"path"=>["query getCheese", "cheese", "silly"],
|
27
28
|
}
|
28
29
|
assert_includes(errors, query_root_error)
|
29
30
|
|
30
31
|
input_obj_record = {
|
31
32
|
"message"=>"InputObject 'DairyProductInput' doesn't accept argument 'wacky'",
|
32
|
-
"locations"=>[{"line"=>5, "column"=>29}]
|
33
|
+
"locations"=>[{"line"=>5, "column"=>29}],
|
34
|
+
"path"=>["query getCheese", "searchDairy", "product", "wacky"],
|
33
35
|
}
|
34
36
|
assert_includes(errors, input_obj_record)
|
35
37
|
|
36
38
|
fragment_error = {
|
37
39
|
"message"=>"Field 'similarCheese' doesn't accept argument 'nonsense'",
|
38
|
-
"locations"=>[{"line"=>9, "column"=>7}]
|
40
|
+
"locations"=>[{"line"=>9, "column"=>7}],
|
41
|
+
"path"=>["fragment cheeseFields", "similarCheese", "nonsense"],
|
39
42
|
}
|
40
43
|
assert_includes(errors, fragment_error)
|
41
44
|
|
42
45
|
directive_error = {
|
43
46
|
"message"=>"Directive 'skip' doesn't accept argument 'something'",
|
44
|
-
"locations"=>[{"line"=>10, "column"=>10}]
|
47
|
+
"locations"=>[{"line"=>10, "column"=>10}],
|
48
|
+
"path"=>["fragment cheeseFields", "id", "something"],
|
45
49
|
}
|
46
50
|
assert_includes(errors, directive_error)
|
47
51
|
end
|