graphql 1.4.5 → 1.5.3
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/generators/graphql/enum_generator.rb +33 -0
- data/lib/generators/graphql/function_generator.rb +15 -0
- data/lib/generators/graphql/install_generator.rb +118 -0
- data/lib/generators/graphql/interface_generator.rb +27 -0
- data/lib/generators/graphql/loader_generator.rb +17 -0
- data/lib/generators/graphql/mutation_generator.rb +19 -0
- data/lib/generators/graphql/object_generator.rb +34 -0
- data/lib/generators/graphql/templates/enum.erb +4 -0
- data/lib/generators/graphql/templates/function.erb +17 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +32 -0
- data/lib/generators/graphql/templates/interface.erb +4 -0
- data/lib/generators/graphql/templates/loader.erb +15 -0
- data/lib/generators/graphql/templates/mutation.erb +12 -0
- data/lib/generators/graphql/templates/object.erb +5 -0
- data/lib/generators/graphql/templates/query_type.erb +15 -0
- data/lib/generators/graphql/templates/schema.erb +34 -0
- data/lib/generators/graphql/templates/union.erb +4 -0
- data/lib/generators/graphql/type_generator.rb +78 -0
- data/lib/generators/graphql/union_generator.rb +33 -0
- data/lib/graphql.rb +10 -0
- data/lib/graphql/analysis/analyze_query.rb +1 -1
- data/lib/graphql/analysis/query_complexity.rb +6 -50
- data/lib/graphql/analysis/query_depth.rb +1 -1
- data/lib/graphql/argument.rb +21 -0
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +3 -3
- data/lib/graphql/define.rb +1 -0
- data/lib/graphql/define/assign_argument.rb +3 -19
- data/lib/graphql/define/assign_mutation_function.rb +34 -0
- data/lib/graphql/define/assign_object_field.rb +26 -14
- data/lib/graphql/define/defined_object_proxy.rb +21 -0
- data/lib/graphql/define/instance_definable.rb +61 -11
- data/lib/graphql/directive.rb +6 -1
- data/lib/graphql/execution/directive_checks.rb +1 -0
- data/lib/graphql/execution/execute.rb +14 -9
- data/lib/graphql/execution/field_result.rb +1 -0
- data/lib/graphql/execution/lazy.rb +8 -17
- data/lib/graphql/execution/lazy/lazy_method_map.rb +2 -0
- data/lib/graphql/execution/lazy/resolve.rb +1 -0
- data/lib/graphql/execution/selection_result.rb +1 -0
- data/lib/graphql/execution/typecast.rb +39 -26
- data/lib/graphql/field.rb +15 -3
- data/lib/graphql/field/resolve.rb +3 -3
- data/lib/graphql/function.rb +134 -0
- data/lib/graphql/id_type.rb +1 -1
- data/lib/graphql/input_object_type.rb +1 -1
- data/lib/graphql/internal_representation.rb +1 -1
- data/lib/graphql/internal_representation/node.rb +35 -107
- data/lib/graphql/internal_representation/rewrite.rb +189 -183
- data/lib/graphql/internal_representation/visit.rb +38 -0
- data/lib/graphql/introspection/input_value_type.rb +10 -1
- data/lib/graphql/introspection/schema_type.rb +1 -1
- data/lib/graphql/language/lexer.rb +6 -3
- data/lib/graphql/language/lexer.rl +6 -3
- data/lib/graphql/object_type.rb +53 -13
- data/lib/graphql/query.rb +30 -14
- data/lib/graphql/query/arguments.rb +2 -0
- data/lib/graphql/query/context.rb +2 -2
- data/lib/graphql/query/literal_input.rb +9 -0
- data/lib/graphql/query/serial_execution/field_resolution.rb +2 -2
- data/lib/graphql/query/serial_execution/selection_resolution.rb +1 -1
- data/lib/graphql/relay.rb +1 -0
- data/lib/graphql/relay/array_connection.rb +1 -1
- data/lib/graphql/relay/base_connection.rb +34 -15
- data/lib/graphql/relay/connection_resolve.rb +7 -2
- data/lib/graphql/relay/mutation.rb +45 -4
- data/lib/graphql/relay/node.rb +18 -6
- data/lib/graphql/relay/range_add.rb +45 -0
- data/lib/graphql/relay/relation_connection.rb +17 -2
- data/lib/graphql/runtime_type_error.rb +1 -0
- data/lib/graphql/schema.rb +40 -5
- data/lib/graphql/schema/base_64_encoder.rb +1 -0
- data/lib/graphql/schema/build_from_definition.rb +56 -21
- data/lib/graphql/schema/default_parse_error.rb +10 -0
- data/lib/graphql/schema/loader.rb +8 -1
- data/lib/graphql/schema/null_mask.rb +1 -0
- data/lib/graphql/schema/validation.rb +35 -0
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/arguments_validator.rb +7 -4
- data/lib/graphql/static_validation/definition_dependencies.rb +183 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +28 -96
- data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +23 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +8 -5
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +6 -31
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +11 -41
- data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +2 -2
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -7
- data/lib/graphql/static_validation/validation_context.rb +22 -1
- data/lib/graphql/static_validation/validator.rb +4 -1
- data/lib/graphql/string_type.rb +5 -1
- data/lib/graphql/version.rb +1 -1
- data/readme.md +12 -3
- data/spec/generators/graphql/enum_generator_spec.rb +29 -0
- data/spec/generators/graphql/function_generator_spec.rb +33 -0
- data/spec/generators/graphql/install_generator_spec.rb +185 -0
- data/spec/generators/graphql/interface_generator_spec.rb +32 -0
- data/spec/generators/graphql/loader_generator_spec.rb +31 -0
- data/spec/generators/graphql/mutation_generator_spec.rb +28 -0
- data/spec/generators/graphql/object_generator_spec.rb +42 -0
- data/spec/generators/graphql/union_generator_spec.rb +50 -0
- data/spec/graphql/analysis/query_complexity_spec.rb +2 -1
- data/spec/graphql/define/instance_definable_spec.rb +38 -0
- data/spec/graphql/directive/skip_directive_spec.rb +1 -0
- data/spec/graphql/directive_spec.rb +18 -0
- data/spec/graphql/execution/typecast_spec.rb +41 -46
- data/spec/graphql/field_spec.rb +1 -1
- data/spec/graphql/function_spec.rb +128 -0
- data/spec/graphql/internal_representation/rewrite_spec.rb +166 -129
- data/spec/graphql/introspection/type_type_spec.rb +1 -1
- data/spec/graphql/language/lexer_spec.rb +6 -0
- data/spec/graphql/object_type_spec.rb +73 -2
- data/spec/graphql/query/arguments_spec.rb +28 -0
- data/spec/graphql/query/variables_spec.rb +7 -1
- data/spec/graphql/query_spec.rb +30 -0
- data/spec/graphql/relay/base_connection_spec.rb +26 -8
- data/spec/graphql/relay/connection_resolve_spec.rb +45 -0
- data/spec/graphql/relay/connection_type_spec.rb +21 -0
- data/spec/graphql/relay/node_spec.rb +30 -2
- data/spec/graphql/relay/range_add_spec.rb +113 -0
- data/spec/graphql/schema/build_from_definition_spec.rb +114 -0
- data/spec/graphql/schema/loader_spec.rb +1 -0
- data/spec/graphql/schema/printer_spec.rb +2 -2
- data/spec/graphql/schema/validation_spec.rb +80 -11
- data/spec/graphql/schema/warden_spec.rb +10 -10
- data/spec/graphql/schema_spec.rb +18 -1
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +16 -0
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +50 -3
- data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +27 -0
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +57 -0
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +14 -0
- data/spec/graphql/string_type_spec.rb +7 -0
- data/spec/spec_helper.rb +3 -3
- data/spec/support/base_generator_test.rb +7 -0
- data/spec/support/dummy/schema.rb +32 -30
- data/spec/support/star_wars/schema.rb +81 -23
- metadata +98 -20
- data/lib/graphql/internal_representation/selection.rb +0 -85
@@ -103,6 +103,7 @@ describe GraphQL::Schema::Loader do
|
|
103
103
|
argument :id, !types.ID
|
104
104
|
argument :varied, variant_input_type, default_value: { id: "123", int: 234, float: 2.3, enum: :foo, sub: [{ string: "str" }] }
|
105
105
|
argument :variedWithNull, variant_input_type_with_nulls, default_value: { id: nil, int: nil, float: nil, enum: nil, sub: nil, bigint: nil, bool: nil }
|
106
|
+
argument :enum, choice_type, default_value: :foo
|
106
107
|
end
|
107
108
|
|
108
109
|
field :content do
|
@@ -499,7 +499,7 @@ input Varied {
|
|
499
499
|
}
|
500
500
|
SCHEMA
|
501
501
|
|
502
|
-
only_filter = ->
|
502
|
+
only_filter = ->(member, ctx) {
|
503
503
|
case member
|
504
504
|
when GraphQL::ScalarType
|
505
505
|
true
|
@@ -583,7 +583,7 @@ type Subscription {
|
|
583
583
|
}
|
584
584
|
SCHEMA
|
585
585
|
|
586
|
-
except_filter = ->
|
586
|
+
except_filter = ->(member, ctx) {
|
587
587
|
ctx[:names].include?(member.name) || (member.respond_to?(:deprecation_reason) && member.deprecation_reason)
|
588
588
|
}
|
589
589
|
|
@@ -2,11 +2,22 @@
|
|
2
2
|
require "spec_helper"
|
3
3
|
|
4
4
|
describe GraphQL::Schema::Validation do
|
5
|
+
def integer_class_name
|
6
|
+
RUBY_VERSION >= "2.4.0" ? "Integer" : "Fixnum"
|
7
|
+
end
|
8
|
+
|
5
9
|
def assert_error_includes(object, error_substring)
|
6
10
|
validation_error = GraphQL::Schema::Validation.validate(object)
|
7
11
|
assert_includes validation_error, error_substring
|
8
12
|
end
|
9
13
|
|
14
|
+
def refute_error_includes(object, *error_substrings)
|
15
|
+
validation_error = GraphQL::Schema::Validation.validate(object)
|
16
|
+
error_substrings.each do |substr|
|
17
|
+
refute_includes(validation_error, substr)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
10
21
|
def assert_validation_warns(object, warning)
|
11
22
|
assert_output("", warning + "\n") { GraphQL::Schema::Validation.validate(object) }
|
12
23
|
end
|
@@ -102,18 +113,11 @@ describe GraphQL::Schema::Validation do
|
|
102
113
|
end
|
103
114
|
|
104
115
|
it "requires String-or-nil description" do
|
105
|
-
assert_error_includes wrongly_described_type, "must return String or NilClass, not
|
116
|
+
assert_error_includes wrongly_described_type, "must return String or NilClass, not #{integer_class_name}"
|
106
117
|
end
|
107
118
|
end
|
108
119
|
|
109
120
|
describe "validating ObjectTypes" do
|
110
|
-
let(:invalid_interfaces_object) {
|
111
|
-
GraphQL::ObjectType.define do
|
112
|
-
name "InvalidInterfaces"
|
113
|
-
interfaces(55)
|
114
|
-
end
|
115
|
-
}
|
116
|
-
|
117
121
|
let(:invalid_interface_member_object) {
|
118
122
|
GraphQL::ObjectType.define do
|
119
123
|
name "InvalidInterfaceMember"
|
@@ -129,13 +133,78 @@ describe GraphQL::Schema::Validation do
|
|
129
133
|
}
|
130
134
|
|
131
135
|
it "requires an Array for interfaces" do
|
132
|
-
assert_error_includes invalid_interfaces_object, "must be an Array of GraphQL::InterfaceType, not a Fixnum"
|
133
136
|
assert_error_includes invalid_interface_member_object, "must contain GraphQL::InterfaceType, not Symbol"
|
134
137
|
end
|
135
138
|
|
136
139
|
it "validates the fields" do
|
137
140
|
assert_error_includes invalid_field_object, "must return GraphQL::BaseType, not Symbol"
|
138
141
|
end
|
142
|
+
|
143
|
+
it "requires interfaces to be implemented" do
|
144
|
+
iface_1 = GraphQL::InterfaceType.define do
|
145
|
+
name "Interface1"
|
146
|
+
field :field_1, types.String
|
147
|
+
field :field_2, types.Int
|
148
|
+
end
|
149
|
+
|
150
|
+
iface_2 = GraphQL::InterfaceType.define do
|
151
|
+
name "Interface2"
|
152
|
+
field :field_3, types.String do
|
153
|
+
argument :arg_1, types.Boolean
|
154
|
+
end
|
155
|
+
field :field_4, types.Int
|
156
|
+
end
|
157
|
+
|
158
|
+
iface_3 = GraphQL::InterfaceType.define do
|
159
|
+
name "Interface3"
|
160
|
+
field :field_5, types.String do
|
161
|
+
argument :arg_2, types.Float
|
162
|
+
end
|
163
|
+
field :field_6, types.Int do
|
164
|
+
argument :arg_3, types.Float
|
165
|
+
end
|
166
|
+
field :field_7, types.ID
|
167
|
+
field :field_8, !types[iface_2]
|
168
|
+
field :field_9, !types[iface_2]
|
169
|
+
end
|
170
|
+
|
171
|
+
obj_type = GraphQL::ObjectType.define do
|
172
|
+
name "Object1"
|
173
|
+
implements iface_1, inherit: true
|
174
|
+
implements iface_2, iface_3
|
175
|
+
field :field_2, types.Int do
|
176
|
+
# Acceptable extra optional argument:
|
177
|
+
argument :arg_0_extra, types.String
|
178
|
+
# Unacceptable extra required argument:
|
179
|
+
argument :arg_0_extra_2, !types.String
|
180
|
+
end
|
181
|
+
# Correct:
|
182
|
+
field :field_3, types.String do
|
183
|
+
argument :arg_1, types.Boolean
|
184
|
+
end
|
185
|
+
# Wrong return type:
|
186
|
+
field :field_4, types.Float
|
187
|
+
# Wrong argument type:
|
188
|
+
field :field_5, types.String do
|
189
|
+
argument :arg_2, types.Int
|
190
|
+
end
|
191
|
+
# Missing argument
|
192
|
+
field :field_6, types.Int
|
193
|
+
# Missing altogether:
|
194
|
+
# field :field_7
|
195
|
+
# Valid subtype:
|
196
|
+
field :field_8, !types[!iface_2]
|
197
|
+
# Invalid subtype:
|
198
|
+
field :field_9, types[iface_2]
|
199
|
+
end
|
200
|
+
|
201
|
+
assert_error_includes(obj_type, '"arg_0_extra_2" is not accepted by Interface1.field_2 but required by Object1.field_2')
|
202
|
+
assert_error_includes(obj_type, '"field_4" is required by Interface2 to return Int but Object1.field_4 returns Float')
|
203
|
+
assert_error_includes(obj_type, '"arg_2" is required by Interface3.field_5 to accept Float but Object1.field_5 accepts Int for "arg_2"')
|
204
|
+
assert_error_includes(obj_type, '"field_7" is required by Interface3 but not implemented by Object1')
|
205
|
+
assert_error_includes(obj_type, '"field_9" is required by Interface3 to return [Interface2]! but Object1.field_9 returns [Interface2]')
|
206
|
+
refute_error_includes(obj_type, "field_1", "field_3", "field_8")
|
207
|
+
end
|
139
208
|
end
|
140
209
|
|
141
210
|
describe "validating UnionTypes" do
|
@@ -163,7 +232,7 @@ describe GraphQL::Schema::Validation do
|
|
163
232
|
}
|
164
233
|
|
165
234
|
it "requires an array of ObjectTypes for possible_types" do
|
166
|
-
assert_error_includes non_array_union, "must be an Array of GraphQL::ObjectType, not a
|
235
|
+
assert_error_includes non_array_union, "must be an Array of GraphQL::ObjectType, not a #{integer_class_name}"
|
167
236
|
|
168
237
|
assert_error_includes non_object_type_union, "must contain GraphQL::ObjectType, not GraphQL::InterfaceType"
|
169
238
|
end
|
@@ -193,7 +262,7 @@ describe GraphQL::Schema::Validation do
|
|
193
262
|
}
|
194
263
|
|
195
264
|
it "requires {String => Argument} arguments" do
|
196
|
-
assert_error_includes invalid_arguments_input, "map String => GraphQL::Argument, not
|
265
|
+
assert_error_includes invalid_arguments_input, "map String => GraphQL::Argument, not #{integer_class_name} => Symbol"
|
197
266
|
end
|
198
267
|
|
199
268
|
it "applies validation to its member Arguments" do
|
@@ -107,7 +107,7 @@ module MaskHelpers
|
|
107
107
|
query QueryType
|
108
108
|
mutation MutationType
|
109
109
|
subscription MutationType
|
110
|
-
resolve_type ->
|
110
|
+
resolve_type ->(obj, ctx) { PhonemeType }
|
111
111
|
end
|
112
112
|
|
113
113
|
module Data
|
@@ -208,7 +208,7 @@ describe GraphQL::Schema::Warden do
|
|
208
208
|
|
209
209
|
describe "hiding fields" do
|
210
210
|
let(:mask) {
|
211
|
-
->
|
211
|
+
->(member, ctx) { member.metadata[:hidden_field] || member.metadata[:hidden_type] }
|
212
212
|
}
|
213
213
|
|
214
214
|
it "causes validation errors" do
|
@@ -254,7 +254,7 @@ describe GraphQL::Schema::Warden do
|
|
254
254
|
|
255
255
|
describe "hiding types" do
|
256
256
|
let(:whitelist) {
|
257
|
-
->
|
257
|
+
->(member, ctx) { !member.metadata[:hidden_type] }
|
258
258
|
}
|
259
259
|
|
260
260
|
it "hides types from introspection" do
|
@@ -340,7 +340,7 @@ describe GraphQL::Schema::Warden do
|
|
340
340
|
|
341
341
|
describe "hiding an abstract type" do
|
342
342
|
let(:mask) {
|
343
|
-
->
|
343
|
+
->(member, ctx) { member.metadata[:hidden_abstract_type] }
|
344
344
|
}
|
345
345
|
|
346
346
|
it "isn't present in a type's interfaces" do
|
@@ -362,7 +362,7 @@ describe GraphQL::Schema::Warden do
|
|
362
362
|
|
363
363
|
describe "hiding arguments" do
|
364
364
|
let(:mask) {
|
365
|
-
->
|
365
|
+
->(member, ctx) { member.metadata[:hidden_argument] || member.metadata[:hidden_input_type] }
|
366
366
|
}
|
367
367
|
|
368
368
|
it "isn't present in introspection" do
|
@@ -398,7 +398,7 @@ describe GraphQL::Schema::Warden do
|
|
398
398
|
|
399
399
|
describe "hidding input type arguments" do
|
400
400
|
let(:mask) {
|
401
|
-
->
|
401
|
+
->(member, ctx) { member.metadata[:hidden_input_field] }
|
402
402
|
}
|
403
403
|
|
404
404
|
it "isn't present in introspection" do
|
@@ -447,7 +447,7 @@ describe GraphQL::Schema::Warden do
|
|
447
447
|
|
448
448
|
describe "hidding input types" do
|
449
449
|
let(:mask) {
|
450
|
-
->
|
450
|
+
->(member, ctx) { member.metadata[:hidden_input_object_type] }
|
451
451
|
}
|
452
452
|
|
453
453
|
it "isn't present in introspection" do
|
@@ -492,7 +492,7 @@ describe GraphQL::Schema::Warden do
|
|
492
492
|
|
493
493
|
describe "hiding enum values" do
|
494
494
|
let(:mask) {
|
495
|
-
->
|
495
|
+
->(member, ctx) { member.metadata[:hidden_enum_value] }
|
496
496
|
}
|
497
497
|
|
498
498
|
it "isn't present in introspection" do
|
@@ -570,7 +570,7 @@ describe GraphQL::Schema::Warden do
|
|
570
570
|
|
571
571
|
describe "default_mask" do
|
572
572
|
let(:default_mask) {
|
573
|
-
->
|
573
|
+
->(member, ctx) { member.metadata[:hidden_enum_value] }
|
574
574
|
}
|
575
575
|
let(:schema) {
|
576
576
|
MaskHelpers::Schema.redefine(default_mask: default_mask)
|
@@ -584,7 +584,7 @@ describe GraphQL::Schema::Warden do
|
|
584
584
|
}
|
585
585
|
|
586
586
|
it "is additive with query filters" do
|
587
|
-
query_except = ->
|
587
|
+
query_except = ->(member, ctx) { member.metadata[:hidden_input_object_type] }
|
588
588
|
res = schema.execute(query_str, except: query_except)
|
589
589
|
assert_equal nil, res["data"]["input"]
|
590
590
|
enum_values = res["data"]["enum"]["enumValues"].map { |v| v["name"] }
|
data/spec/graphql/schema_spec.rb
CHANGED
@@ -236,7 +236,7 @@ type Query {
|
|
236
236
|
name "Query"
|
237
237
|
field :int, types.Int do
|
238
238
|
argument :value, types.Int
|
239
|
-
resolve ->
|
239
|
+
resolve ->(obj, args, ctx) { args[:value] == 13 ? raise("13 is unlucky") : args[:value] }
|
240
240
|
end
|
241
241
|
end
|
242
242
|
}
|
@@ -319,4 +319,21 @@ type Query {
|
|
319
319
|
refute_equal schema_2.middleware, schema.middleware
|
320
320
|
end
|
321
321
|
end
|
322
|
+
|
323
|
+
describe "#validate" do
|
324
|
+
it "returns errors on the query string" do
|
325
|
+
errors = schema.validate("{ cheese(id: 1) { flavor flavor: id } }")
|
326
|
+
assert_equal 1, errors.length
|
327
|
+
assert_equal "Field 'flavor' has a field conflict: flavor or id?", errors.first.message
|
328
|
+
|
329
|
+
errors = schema.validate("{ cheese(id: 1) { flavor id } }")
|
330
|
+
assert_equal [], errors
|
331
|
+
end
|
332
|
+
|
333
|
+
it "accepts a list of custom rules" do
|
334
|
+
custom_rules = GraphQL::StaticValidation::ALL_RULES - [GraphQL::StaticValidation::FragmentsAreNamed]
|
335
|
+
errors = schema.validate("fragment on Cheese { id }", rules: custom_rules)
|
336
|
+
assert_equal([], errors)
|
337
|
+
end
|
338
|
+
end
|
322
339
|
end
|
@@ -67,6 +67,22 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
|
|
67
67
|
assert_includes(errors, fragment_error)
|
68
68
|
end
|
69
69
|
|
70
|
+
describe "using input objects for enums" do
|
71
|
+
let(:query_string) { <<-GRAPHQL
|
72
|
+
{
|
73
|
+
yakSource: searchDairy(product: [{source: {a: 1, b: 2}, fatContent: 1.1}]) { __typename }
|
74
|
+
}
|
75
|
+
GRAPHQL
|
76
|
+
}
|
77
|
+
|
78
|
+
it "adds an error" do
|
79
|
+
# TODO:
|
80
|
+
# It's annoying that this error cascades up, there should only be one:
|
81
|
+
assert_equal 2, errors.length
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
70
86
|
describe "null value" do
|
71
87
|
describe "nullable arg" do
|
72
88
|
let(:schema) {
|
@@ -231,7 +231,7 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
|
|
231
231
|
|}
|
232
232
|
|
233
233
|
it "fails rule" do
|
234
|
-
assert_equal ["Field 'name' has a field conflict:
|
234
|
+
assert_equal ["Field 'name' has a field conflict: name or nickname?"], error_messages
|
235
235
|
end
|
236
236
|
end
|
237
237
|
|
@@ -317,8 +317,8 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
|
|
317
317
|
|
318
318
|
it "fails rule" do
|
319
319
|
assert_equal [
|
320
|
+
"Field 'name' has a field conflict: name or nickname?",
|
320
321
|
"Field 'x' has a field conflict: name or nickname?",
|
321
|
-
"Field 'name' has a field conflict: nickname or name?",
|
322
322
|
], error_messages
|
323
323
|
end
|
324
324
|
end
|
@@ -337,7 +337,17 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
|
|
337
337
|
|}
|
338
338
|
|
339
339
|
it "fails rule" do
|
340
|
-
|
340
|
+
expected_errors = [
|
341
|
+
{
|
342
|
+
"message"=>"Field 'x' has a field conflict: name or nickname?",
|
343
|
+
"locations"=>[
|
344
|
+
{"line"=>4, "column"=>11},
|
345
|
+
{"line"=>8, "column"=>11}
|
346
|
+
],
|
347
|
+
"fields"=>[]
|
348
|
+
}
|
349
|
+
]
|
350
|
+
assert_equal expected_errors, errors
|
341
351
|
end
|
342
352
|
end
|
343
353
|
|
@@ -388,6 +398,43 @@ describe GraphQL::StaticValidation::FieldsWillMerge do
|
|
388
398
|
end
|
389
399
|
end
|
390
400
|
|
401
|
+
describe "same aliases allowed on non-overlapping fields" do
|
402
|
+
let(:query_string) {%|
|
403
|
+
{
|
404
|
+
pet {
|
405
|
+
... on Dog {
|
406
|
+
name
|
407
|
+
}
|
408
|
+
... on Cat {
|
409
|
+
name: nickname
|
410
|
+
}
|
411
|
+
}
|
412
|
+
}
|
413
|
+
|}
|
414
|
+
|
415
|
+
it "passes rule" do
|
416
|
+
assert_equal [], errors
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
describe "allows different args where no conflict is possible" do
|
421
|
+
let(:query_string) {%|
|
422
|
+
{
|
423
|
+
pet {
|
424
|
+
... on Dog {
|
425
|
+
name(surname: true)
|
426
|
+
}
|
427
|
+
... on Cat {
|
428
|
+
name
|
429
|
+
}
|
430
|
+
}
|
431
|
+
}
|
432
|
+
|}
|
433
|
+
|
434
|
+
it "passes rule" do
|
435
|
+
assert_equal [], errors
|
436
|
+
end
|
437
|
+
end
|
391
438
|
describe "return types must be unambiguous" do
|
392
439
|
let(:schema) {
|
393
440
|
GraphQL::Schema.from_definition(%|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe GraphQL::StaticValidation::FragmentNamesAreUnique do
|
5
|
+
include StaticValidationHelpers
|
6
|
+
|
7
|
+
let(:query_string) {"
|
8
|
+
query {
|
9
|
+
cheese(id: 1) {
|
10
|
+
... frag1
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
fragment frag1 on Cheese { id }
|
15
|
+
fragment frag1 on Cheese { id }
|
16
|
+
"}
|
17
|
+
|
18
|
+
it "requires unique fragment names" do
|
19
|
+
assert_equal(1, errors.length)
|
20
|
+
fragment_def_error = {
|
21
|
+
"message"=>"Fragment name \"frag1\" must be unique",
|
22
|
+
"locations"=>[{"line"=>8, "column"=>5}, {"line"=>9, "column"=>5}],
|
23
|
+
"fields"=>[],
|
24
|
+
}
|
25
|
+
assert_includes(errors, fragment_def_error)
|
26
|
+
end
|
27
|
+
end
|
@@ -61,4 +61,61 @@ describe GraphQL::StaticValidation::FragmentsAreFinite do
|
|
61
61
|
assert_equal("Fragment frag2 was used, but not defined", errors.first["message"])
|
62
62
|
end
|
63
63
|
end
|
64
|
+
|
65
|
+
describe "a duplicate fragment name with a loop" do
|
66
|
+
let(:query_string) {%|
|
67
|
+
{
|
68
|
+
cheese(id: 1) { ... frag1 }
|
69
|
+
}
|
70
|
+
fragment frag1 on Cheese { id }
|
71
|
+
fragment frag1 on Cheese { ...frag1 }
|
72
|
+
|}
|
73
|
+
|
74
|
+
it "detects the loop" do
|
75
|
+
assert_equal 2, errors.length
|
76
|
+
assert_equal("Fragment frag1 contains an infinite loop", errors[0]["message"])
|
77
|
+
assert_equal("Fragment name \"frag1\" must be unique", errors[1]["message"])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "a duplicate operation name with a loop" do
|
82
|
+
let(:query_string) {%|
|
83
|
+
fragment frag1 on Cheese { ...frag1 }
|
84
|
+
|
85
|
+
query frag1 {
|
86
|
+
cheese(id: 1) {
|
87
|
+
... frag1
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|}
|
91
|
+
|
92
|
+
it "detects the loop" do
|
93
|
+
assert_equal 1, errors.length
|
94
|
+
assert_equal("Fragment frag1 contains an infinite loop", errors[0]["message"])
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "several duplicate operation names with a loop" do
|
99
|
+
let(:query_string) {%|
|
100
|
+
query frag1 {
|
101
|
+
cheese(id: 1) {
|
102
|
+
id
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
fragment frag1 on Cheese { ...frag1 }
|
107
|
+
|
108
|
+
query frag1 {
|
109
|
+
cheese(id: 1) {
|
110
|
+
... frag1
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|}
|
114
|
+
|
115
|
+
it "detects the loop" do
|
116
|
+
assert_equal 2, errors.length
|
117
|
+
assert_equal("Fragment frag1 contains an infinite loop", errors[0]["message"])
|
118
|
+
assert_equal("Operation name \"frag1\" must be unique", errors[1]["message"])
|
119
|
+
end
|
120
|
+
end
|
64
121
|
end
|