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
|