graphql 1.6.4 → 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +47 -0
  3. data/lib/generators/graphql/install_generator.rb +15 -20
  4. data/lib/generators/graphql/mutation_generator.rb +31 -1
  5. data/lib/generators/graphql/templates/mutation.erb +2 -2
  6. data/lib/generators/graphql/templates/mutation_type.erb +5 -0
  7. data/lib/generators/graphql/templates/schema.erb +0 -1
  8. data/lib/graphql/argument.rb +6 -5
  9. data/lib/graphql/backwards_compatibility.rb +18 -4
  10. data/lib/graphql/base_type.rb +1 -1
  11. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +1 -1
  12. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +1 -1
  13. data/lib/graphql/compatibility/lazy_execution_specification.rb +9 -2
  14. data/lib/graphql/define.rb +1 -0
  15. data/lib/graphql/define/defined_object_proxy.rb +1 -1
  16. data/lib/graphql/define/no_definition_error.rb +7 -0
  17. data/lib/graphql/enum_type.rb +4 -0
  18. data/lib/graphql/execution/execute.rb +3 -3
  19. data/lib/graphql/execution/field_result.rb +1 -1
  20. data/lib/graphql/execution/lazy/resolve.rb +10 -9
  21. data/lib/graphql/execution/multiplex.rb +6 -5
  22. data/lib/graphql/input_object_type.rb +5 -1
  23. data/lib/graphql/interface_type.rb +12 -3
  24. data/lib/graphql/query.rb +21 -5
  25. data/lib/graphql/query/context.rb +11 -0
  26. data/lib/graphql/schema.rb +48 -27
  27. data/lib/graphql/schema/build_from_definition.rb +1 -1
  28. data/lib/graphql/schema/build_from_definition/resolve_map.rb +2 -2
  29. data/lib/graphql/schema/loader.rb +1 -1
  30. data/lib/graphql/schema/traversal.rb +91 -0
  31. data/lib/graphql/schema/validation.rb +1 -1
  32. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +41 -7
  33. data/lib/graphql/union_type.rb +13 -2
  34. data/lib/graphql/version.rb +1 -1
  35. data/readme.md +1 -3
  36. data/spec/generators/graphql/install_generator_spec.rb +3 -1
  37. data/spec/generators/graphql/mutation_generator_spec.rb +14 -0
  38. data/spec/graphql/analysis/max_query_complexity_spec.rb +12 -1
  39. data/spec/graphql/analysis/query_complexity_spec.rb +1 -1
  40. data/spec/graphql/argument_spec.rb +29 -0
  41. data/spec/graphql/define/assign_argument_spec.rb +4 -4
  42. data/spec/graphql/define/instance_definable_spec.rb +1 -1
  43. data/spec/graphql/enum_type_spec.rb +8 -0
  44. data/spec/graphql/execution/lazy_spec.rb +30 -3
  45. data/spec/graphql/interface_type_spec.rb +44 -0
  46. data/spec/graphql/introspection/schema_type_spec.rb +3 -0
  47. data/spec/graphql/introspection/type_type_spec.rb +1 -0
  48. data/spec/graphql/object_type_spec.rb +8 -3
  49. data/spec/graphql/query/context_spec.rb +18 -0
  50. data/spec/graphql/query/executor_spec.rb +1 -1
  51. data/spec/graphql/query/literal_input_spec.rb +31 -15
  52. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +1 -1
  53. data/spec/graphql/query/variables_spec.rb +25 -1
  54. data/spec/graphql/query_spec.rb +24 -9
  55. data/spec/graphql/relay/mutation_spec.rb +1 -1
  56. data/spec/graphql/schema/build_from_definition_spec.rb +1 -1
  57. data/spec/graphql/schema/loader_spec.rb +1 -1
  58. data/spec/graphql/schema/printer_spec.rb +1 -1
  59. data/spec/graphql/schema/{reduce_types_spec.rb → traversal_spec.rb} +21 -4
  60. data/spec/graphql/schema/warden_spec.rb +1 -1
  61. data/spec/graphql/schema_spec.rb +23 -2
  62. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +133 -0
  63. data/spec/graphql/union_type_spec.rb +53 -0
  64. data/spec/spec_helper.rb +9 -0
  65. data/spec/support/dummy/data.rb +14 -5
  66. data/spec/support/dummy/schema.rb +46 -5
  67. data/spec/support/star_wars/data.rb +10 -6
  68. data/spec/support/star_wars/schema.rb +5 -2
  69. metadata +8 -7
  70. data/lib/graphql/schema/instrumented_field_map.rb +0 -40
  71. data/lib/graphql/schema/reduce_types.rb +0 -69
  72. data/lib/graphql/schema/type_map.rb +0 -31
@@ -24,6 +24,13 @@ describe GraphQL::Query::Context do
24
24
  field :pushContext, types.Int do
25
25
  resolve ->(t,a,c) { CTX << c; 1 }
26
26
  end
27
+
28
+ field :pushQueryError, types.Int do
29
+ resolve ->(t,a,c) {
30
+ c.query.context.add_error(GraphQL::ExecutionError.new("Query-level error"))
31
+ 1
32
+ }
33
+ end
27
34
  }}
28
35
  let(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)}
29
36
  let(:result) { schema.execute(query_string, context: {"some_key" => "some value"})}
@@ -118,4 +125,15 @@ describe GraphQL::Query::Context do
118
125
  assert_equal [2, 9], [err.ast_node.line, err.ast_node.col]
119
126
  end
120
127
  end
128
+
129
+ describe "query-level errors" do
130
+ let(:query_string) { %|
131
+ { pushQueryError }
132
+ |}
133
+
134
+ it "allows query-level errors" do
135
+ expected_err = { "message" => "Query-level error" }
136
+ assert_equal [expected_err], result["errors"]
137
+ end
138
+ end
121
139
  end
@@ -119,7 +119,7 @@ describe GraphQL::Query::Executor do
119
119
  end
120
120
  end
121
121
 
122
- GraphQL::Schema.define(query: DummyQueryType, mutation: Dummy::DairyAppMutationType, resolve_type: :pass, id_from_object: :pass)
122
+ GraphQL::Schema.define(query: DummyQueryType, mutation: Dummy::DairyAppMutationType, resolve_type: ->(a,b,c) { :pass }, id_from_object: :pass)
123
123
  }
124
124
  let(:variables) { nil }
125
125
  let(:query_string) { %|
@@ -5,8 +5,8 @@ describe GraphQL::Query::LiteralInput do
5
5
  describe ".from_arguments" do
6
6
  describe "arguments are prepared" do
7
7
  let(:schema) {
8
- query = GraphQL::ObjectType.define do
9
- name "Query"
8
+ type = GraphQL::ObjectType.define do
9
+ name "SomeType"
10
10
 
11
11
  field :addToArgumentValue do
12
12
  type !types.Int
@@ -35,40 +35,56 @@ describe GraphQL::Query::LiteralInput do
35
35
  end
36
36
  end
37
37
 
38
+ query = GraphQL::ObjectType.define do
39
+ name "Query"
40
+
41
+ field :top, type, resolve: ->(_, _, _) { true }
42
+ end
43
+
38
44
  GraphQL::Schema.define(query: query)
39
45
  }
40
46
 
41
47
  it "prepares values from query literals" do
42
- result = schema.execute("{ addToArgumentValue(value: 1) }", context: { val: 1 })
43
- assert_equal(result["data"]["addToArgumentValue"], 2)
48
+ result = schema.execute("{ top { addToArgumentValue(value: 1) } }", context: { val: 1 })
49
+ assert_equal(result["data"]["top"]["addToArgumentValue"], 2)
44
50
  end
45
51
 
46
52
  it "prepares default values" do
47
- result = schema.execute("{ addToArgumentValue }", context: { val: 4 })
48
- assert_equal(7, result["data"]["addToArgumentValue"])
53
+ result = schema.execute("{ top { addToArgumentValue } }", context: { val: 4 })
54
+ assert_equal(7, result["data"]["top"]["addToArgumentValue"])
49
55
  end
50
56
 
51
57
  it "raises an execution error if the default value is bad" do
52
- result = schema.execute("{ fieldWithArgumentThatIsBadByDefault }", context: { })
53
- assert_equal(result["errors"], [{"message" => "Always bad"}])
58
+ result = schema.execute("{ top { fieldWithArgumentThatIsBadByDefault } }", context: { })
59
+ assert_equal(result["data"], {
60
+ "top"=>{
61
+ "fieldWithArgumentThatIsBadByDefault"=>nil}
62
+ })
63
+ assert_equal(result["errors"], [
64
+ {"message"=>"Always bad",
65
+ "locations"=>[{"line"=>1, "column"=>9}],
66
+ "path"=>["top", "fieldWithArgumentThatIsBadByDefault"]}
67
+ ])
54
68
  end
55
69
 
56
70
  it "prepares values from variables" do
57
- result = schema.execute("query ($value: Int!) { addToArgumentValue(value: $value) }", variables: { "value" => 1}, context: { val: 2 } )
58
- assert_equal(result["data"]["addToArgumentValue"], 3)
71
+ result = schema.execute("query ($value: Int!) { top { addToArgumentValue(value: $value) } }", variables: { "value" => 1}, context: { val: 2 } )
72
+ assert_equal(result["data"]["top"]["addToArgumentValue"], 3)
59
73
  end
60
74
 
61
75
  it "prepares values correctly if called multiple times with different arguments" do
62
- result = schema.execute("{ first: addToArgumentValue(value: 1) second: addToArgumentValue(value: 2) }", context: { val: 3 })
63
- assert_equal(result["data"]["first"], 4)
64
- assert_equal(result["data"]["second"], 5)
76
+ result = schema.execute("{ top { first: addToArgumentValue(value: 1) second: addToArgumentValue(value: 2) } }", context: { val: 3 })
77
+ assert_equal(result["data"]["top"]["first"], 4)
78
+ assert_equal(result["data"]["top"]["second"], 5)
65
79
  end
66
80
 
67
81
  it "adds message to errors key if an ExecutionError is returned from the prepare function" do
68
- result = schema.execute("{ addToArgumentValue(value: 999) }")
82
+ result = schema.execute("{ top { addToArgumentValue(value: 999) } }")
83
+ assert_equal(result["data"]["top"], nil)
69
84
  assert_equal(result["errors"][0]["message"], "Can't return more than 3 digits")
70
85
  assert_equal(result["errors"][0]["locations"][0]["line"], 1)
71
- assert_equal(result["errors"][0]["locations"][0]["column"], 22)
86
+ assert_equal(result["errors"][0]["locations"][0]["column"], 28)
87
+ assert_equal(result["errors"][0]["path"], ["top", "addToArgumentValue"])
72
88
  end
73
89
  end
74
90
  end
@@ -45,7 +45,7 @@ describe GraphQL::Query::SerialExecution::ValueResolution do
45
45
  GraphQL::Schema.define do
46
46
  query(query_root)
47
47
  orphan_types [some_object]
48
- resolve_type ->(obj, ctx) do
48
+ resolve_type ->(type, obj, ctx) do
49
49
  if obj.is_a?(Symbol)
50
50
  other_object
51
51
  else
@@ -16,7 +16,8 @@ describe GraphQL::Query::Variables do
16
16
  |}
17
17
  let(:ast_variables) { GraphQL.parse(query_string).definitions.first.variables }
18
18
  let(:schema) { Dummy::Schema }
19
- let(:variables) { GraphQL::Query::Variables.new(
19
+ let(:variables) {
20
+ GraphQL::Query::Variables.new(
20
21
  OpenStruct.new({
21
22
  schema: schema,
22
23
  warden: GraphQL::Schema::Warden.new(schema.default_filter, schema: schema, context: nil),
@@ -34,6 +35,29 @@ describe GraphQL::Query::Variables do
34
35
  end
35
36
  end
36
37
 
38
+ describe "validating input objects" do
39
+ let(:query_string) {%|
40
+ query searchMyDairy (
41
+ $product: DairyProductInput
42
+ ) {
43
+ searchDairy(product: $product) {
44
+ ... on Cheese {
45
+ flavor
46
+ }
47
+ }
48
+ }
49
+ |}
50
+
51
+ describe "when provided input is an array" do
52
+ let(:provided_variables) { { "product" => [] } }
53
+
54
+ it "validates invalid input objects" do
55
+ expected = "Variable product of type DairyProductInput was provided invalid value"
56
+ assert_equal expected, variables.errors.first.message
57
+ end
58
+ end
59
+ end
60
+
37
61
  describe "nullable variables" do
38
62
  module ObjectWithThingsCount
39
63
  def self.thingsCount(args, ctx) # rubocop:disable Style/MethodName
@@ -45,15 +45,15 @@ describe GraphQL::Query do
45
45
  let(:result) { query.result }
46
46
 
47
47
  describe "when passed no query string or document" do
48
- it 'fails with an ArgumentError' do
49
- assert_raises(ArgumentError) {
50
- GraphQL::Query.new(
51
- schema,
52
- variables: query_variables,
53
- operation_name: operation_name,
54
- max_depth: max_depth,
55
- ).result
56
- }
48
+ it 'returns an error to the client' do
49
+ res = GraphQL::Query.new(
50
+ schema,
51
+ variables: query_variables,
52
+ operation_name: operation_name,
53
+ max_depth: max_depth,
54
+ ).result
55
+ assert_equal 1, res["errors"].length
56
+ assert_equal "No query string was present", res["errors"][0]["message"]
57
57
  end
58
58
 
59
59
  it 'can be assigned later' do
@@ -94,6 +94,21 @@ describe GraphQL::Query do
94
94
  assert_equal "q3", query.selected_operation_name
95
95
  end
96
96
  end
97
+
98
+ describe "assigning operation_name=" do
99
+ let(:query_string) { <<-GRAPHQL
100
+ query q3 { manchego: cheese(id: 3) { flavor } }
101
+ query q2 { gouda: cheese(id: 2) { flavor } }
102
+ GRAPHQL
103
+ }
104
+
105
+ it "runs the assigned name" do
106
+ query = GraphQL::Query.new(Dummy::Schema, query_string, operation_name: "q3")
107
+ query.operation_name = "q2"
108
+ res = query.result
109
+ assert_equal "Gouda", res["data"]["gouda"]["flavor"]
110
+ end
111
+ end
97
112
  end
98
113
 
99
114
  describe "when passed a document instance" do
@@ -258,7 +258,7 @@ describe GraphQL::Relay::Mutation do
258
258
 
259
259
  GraphQL::Schema.define do
260
260
  mutation(mutation_root)
261
- resolve_type ->(obj, ctx) { "not really used" }
261
+ resolve_type NO_OP_RESOLVE_TYPE
262
262
  end
263
263
  }
264
264
 
@@ -735,7 +735,7 @@ SCHEMA
735
735
  val.to_f
736
736
  }
737
737
  },
738
- resolve_type: ->(obj, ctx) {
738
+ resolve_type: ->(type, obj, ctx) {
739
739
  return ctx.schema.types['A']
740
740
  },
741
741
  Query: {
@@ -125,7 +125,7 @@ describe GraphQL::Schema::Loader do
125
125
  query: query_root,
126
126
  mutation: mutation_root,
127
127
  orphan_types: [audio_type, video_type],
128
- resolve_type: :pass,
128
+ resolve_type: ->(a,b,c) { :pass },
129
129
  )
130
130
  }
131
131
 
@@ -123,7 +123,7 @@ describe GraphQL::Schema::Printer do
123
123
  query: query_root,
124
124
  mutation: mutation_root,
125
125
  subscription: subscription_root,
126
- resolve_type: :pass,
126
+ resolve_type: ->(a,b,c) { :pass },
127
127
  orphan_types: [media_union_type]
128
128
  )
129
129
  }
@@ -1,9 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
  require "spec_helper"
3
3
 
4
- describe GraphQL::Schema::ReduceTypes do
4
+ describe GraphQL::Schema::Traversal do
5
5
  def reduce_types(types)
6
- GraphQL::Schema::ReduceTypes.reduce(types)
6
+ schema = GraphQL::Schema.define(orphan_types: types, resolve_type: :dummy)
7
+ traversal = GraphQL::Schema::Traversal.new(schema, introspection: false)
8
+ traversal.type_map
7
9
  end
8
10
 
9
11
  it "finds types from a single type and its fields" do
@@ -12,13 +14,14 @@ describe GraphQL::Schema::ReduceTypes do
12
14
  "Float" => GraphQL::FLOAT_TYPE,
13
15
  "String" => GraphQL::STRING_TYPE,
14
16
  "Edible" => Dummy::EdibleInterface,
17
+ "EdibleAsMilk" => Dummy::EdibleAsMilkInterface,
15
18
  "DairyAnimal" => Dummy::DairyAnimalEnum,
16
19
  "Int" => GraphQL::INT_TYPE,
17
20
  "AnimalProduct" => Dummy::AnimalProductInterface,
18
21
  "LocalProduct" => Dummy::LocalProductInterface,
19
22
  }
20
23
  result = reduce_types([Dummy::CheeseType])
21
- assert_equal(expected.keys, result.keys)
24
+ assert_equal(expected.keys.sort, result.keys.sort)
22
25
  assert_equal(expected, result.to_h)
23
26
  end
24
27
 
@@ -27,6 +30,20 @@ describe GraphQL::Schema::ReduceTypes do
27
30
  assert_equal(Dummy::DairyProductInputType, result["DairyProductInput"])
28
31
  end
29
32
 
33
+ it "finds types from field instrumentation" do
34
+ type = GraphQL::ObjectType.define do
35
+ name "ArgTypeTest"
36
+ connection :t, type.connection_type
37
+ end
38
+
39
+ result = reduce_types([type])
40
+ expected_types = [
41
+ "ArgTypeTest", "ArgTypeTestConnection", "ArgTypeTestEdge",
42
+ "Boolean", "Int", "PageInfo", "String"
43
+ ]
44
+ assert_equal expected_types, result.keys.sort
45
+ end
46
+
30
47
  it "finds types from nested InputObjectTypes" do
31
48
  type_child = GraphQL::InputObjectType.define do
32
49
  name "InputTypeChild"
@@ -92,7 +109,7 @@ describe GraphQL::Schema::ReduceTypes do
92
109
  describe "when getting a type which doesnt exist" do
93
110
  it "raises an error" do
94
111
  type_map = reduce_types([])
95
- assert_raises(RuntimeError) { type_map["SomeType"] }
112
+ assert_raises(KeyError) { type_map.fetch("SomeType") }
96
113
  end
97
114
  end
98
115
 
@@ -120,7 +120,7 @@ module MaskHelpers
120
120
  query QueryType
121
121
  mutation MutationType
122
122
  subscription MutationType
123
- resolve_type ->(obj, ctx) { PhonemeType }
123
+ resolve_type ->(type, obj, ctx) { PhonemeType }
124
124
  instrument :query, FilterInstrumentation
125
125
  end
126
126
 
@@ -99,7 +99,7 @@ describe GraphQL::Schema do
99
99
  assert_raises(NotImplementedError) {
100
100
  GraphQL::Schema.define do
101
101
  query(query_type)
102
- resolve_type ->(obj, ctx) { :whatever }
102
+ resolve_type NO_OP_RESOLVE_TYPE
103
103
  end
104
104
  }
105
105
  end
@@ -125,7 +125,7 @@ describe GraphQL::Schema do
125
125
  assert_raises(NotImplementedError) {
126
126
  GraphQL::Schema.define do
127
127
  query(query_type)
128
- resolve_type ->(obj, ctx) { :whatever }
128
+ resolve_type NO_OP_RESOLVE_TYPE
129
129
  end
130
130
  }
131
131
  end
@@ -293,6 +293,27 @@ type Query {
293
293
  res = schema.execute("query { int(value: 2) } ")
294
294
  assert_equal 24, res["data"]["int"]
295
295
  end
296
+
297
+ class CyclicalDependencyInstrumentation
298
+ def initialize(schema)
299
+ @schema = schema
300
+ end
301
+
302
+ def instrument(type, field)
303
+ @schema.types # infinite loop
304
+ field
305
+ end
306
+ end
307
+
308
+ describe "field instrumenters which cause loops" do
309
+ it "has a nice error message" do
310
+ assert_raises(GraphQL::Schema::CyclicalDefinitionError) do
311
+ schema.redefine {
312
+ instrument(:field, CyclicalDependencyInstrumentation.new(self.target))
313
+ }
314
+ end
315
+ end
316
+ end
296
317
  end
297
318
 
298
319
  describe "#lazy? / #lazy_method_name" do
@@ -80,4 +80,137 @@ describe GraphQL::StaticValidation::VariableUsagesAreAllowed do
80
80
  assert_equal "Argument 'id' on Field 'cheese' has an invalid value. Expected type 'Int!'.", errors[0]["message"]
81
81
  end
82
82
  end
83
+
84
+ describe "list-type variables" do
85
+ let(:schema) {
86
+ GraphQL::Schema.from_definition <<-GRAPHQL
87
+ input ImageSize {
88
+ height: Int
89
+ width: Int
90
+ scale: Int
91
+ }
92
+
93
+ type Query {
94
+ imageUrl(height: Int, width: Int, size: ImageSize, sizes: [ImageSize!]): String!
95
+ }
96
+ GRAPHQL
97
+ }
98
+
99
+ describe "nullability mismatch" do
100
+ let(:query_string) {
101
+ <<-GRAPHQL
102
+ # This variable _should_ be [ImageSize!]
103
+ query ($sizes: [ImageSize]) {
104
+ imageUrl(sizes: $sizes)
105
+ }
106
+ GRAPHQL
107
+ }
108
+
109
+ it "finds invalid inner definitions" do
110
+ assert_equal 1, errors.size
111
+ expected_message = "Nullability mismatch on variable $sizes and argument sizes ([ImageSize] / [ImageSize!])"
112
+ assert_equal [expected_message], errors.map { |e| e["message"] }
113
+ end
114
+ end
115
+
116
+ describe "list dimension mismatch" do
117
+ let(:query_string) {
118
+ <<-GRAPHQL
119
+ query ($sizes: [ImageSize]) {
120
+ imageUrl(sizes: [$sizes])
121
+ }
122
+ GRAPHQL
123
+ }
124
+
125
+ it "finds invalid inner definitions" do
126
+ assert_equal 1, errors.size
127
+ expected_message = "List dimension mismatch on variable $sizes and argument sizes ([[ImageSize]] / [ImageSize!])"
128
+ assert_equal [expected_message], errors.map { |e| e["message"] }
129
+ end
130
+ end
131
+
132
+ describe 'list is in the argument' do
133
+ let(:query_string) {
134
+ <<-GRAPHQL
135
+ query ($size: ImageSize!) {
136
+ imageUrl(sizes: [$size])
137
+ }
138
+ GRAPHQL
139
+ }
140
+
141
+ it "is a valid query" do
142
+ assert_equal 0, errors.size
143
+ end
144
+
145
+ describe "mixed with invalid literals" do
146
+ let(:query_string) {
147
+ <<-GRAPHQL
148
+ query ($size: ImageSize!) {
149
+ imageUrl(sizes: [$size, 1, true])
150
+ }
151
+ GRAPHQL
152
+ }
153
+
154
+ it "is an invalid query" do
155
+ assert_equal 1, errors.size
156
+ end
157
+ end
158
+
159
+ describe "mixed with invalid variables" do
160
+ let(:query_string) {
161
+ <<-GRAPHQL
162
+ query ($size: ImageSize!, $wrongSize: Boolean!) {
163
+ imageUrl(sizes: [$size, $wrongSize])
164
+ }
165
+ GRAPHQL
166
+ }
167
+
168
+ it "is an invalid query" do
169
+ assert_equal 1, errors.size
170
+ end
171
+ end
172
+
173
+ describe "mixed with valid literals and invalid variables" do
174
+ let(:query_string) {
175
+ <<-GRAPHQL
176
+ query ($size: ImageSize!, $wrongSize: Boolean!) {
177
+ imageUrl(sizes: [$size, {height: 100} $wrongSize])
178
+ }
179
+ GRAPHQL
180
+ }
181
+
182
+ it "is an invalid query" do
183
+ assert_equal 1, errors.size
184
+ end
185
+ end
186
+ end
187
+
188
+ describe 'argument contains a list with literal values' do
189
+ let(:query_string) {
190
+ <<-GRAPHQL
191
+ query {
192
+ imageUrl(sizes: [{height: 100, width: 100, scale: 1}])
193
+ }
194
+ GRAPHQL
195
+ }
196
+
197
+ it "is a valid query" do
198
+ assert_equal 0, errors.size
199
+ end
200
+ end
201
+
202
+ describe 'argument contains a list with both literal and variable values' do
203
+ let(:query_string) {
204
+ <<-GRAPHQL
205
+ query($size1: ImageSize!, $size2: ImageSize!) {
206
+ imageUrl(sizes: [{height: 100, width: 100, scale: 1}, $size1, {height: 1920, width: 1080, scale: 2}, $size2])
207
+ }
208
+ GRAPHQL
209
+ }
210
+
211
+ it "is a valid query" do
212
+ assert_equal 0, errors.size
213
+ end
214
+ end
215
+ end
83
216
  end