graphql 1.0.0 → 1.1.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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +10 -0
  3. data/lib/graphql/base_type.rb +8 -5
  4. data/lib/graphql/compatibility.rb +3 -0
  5. data/lib/graphql/compatibility/execution_specification.rb +414 -0
  6. data/lib/graphql/compatibility/query_parser_specification.rb +117 -0
  7. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +81 -0
  8. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +78 -0
  9. data/lib/graphql/compatibility/schema_parser_specification.rb +239 -0
  10. data/lib/graphql/define/instance_definable.rb +53 -21
  11. data/lib/graphql/directive.rb +1 -1
  12. data/lib/graphql/enum_type.rb +31 -8
  13. data/lib/graphql/execution/directive_checks.rb +0 -6
  14. data/lib/graphql/input_object_type.rb +6 -4
  15. data/lib/graphql/introspection/arguments_field.rb +3 -1
  16. data/lib/graphql/introspection/enum_values_field.rb +10 -5
  17. data/lib/graphql/introspection/fields_field.rb +1 -1
  18. data/lib/graphql/introspection/input_fields_field.rb +2 -2
  19. data/lib/graphql/introspection/interfaces_field.rb +7 -1
  20. data/lib/graphql/introspection/possible_types_field.rb +1 -1
  21. data/lib/graphql/introspection/schema_type.rb +1 -1
  22. data/lib/graphql/introspection/type_by_name_field.rb +4 -2
  23. data/lib/graphql/introspection/type_type.rb +7 -6
  24. data/lib/graphql/language/lexer.rl +0 -4
  25. data/lib/graphql/language/parser.rb +1 -1
  26. data/lib/graphql/language/parser.y +1 -1
  27. data/lib/graphql/list_type.rb +3 -4
  28. data/lib/graphql/non_null_type.rb +4 -8
  29. data/lib/graphql/object_type.rb +5 -3
  30. data/lib/graphql/query.rb +48 -12
  31. data/lib/graphql/query/context.rb +7 -1
  32. data/lib/graphql/query/serial_execution/execution_context.rb +8 -3
  33. data/lib/graphql/query/serial_execution/field_resolution.rb +8 -5
  34. data/lib/graphql/query/serial_execution/operation_resolution.rb +2 -2
  35. data/lib/graphql/query/serial_execution/selection_resolution.rb +4 -21
  36. data/lib/graphql/query/serial_execution/value_resolution.rb +59 -99
  37. data/lib/graphql/query/variables.rb +7 -2
  38. data/lib/graphql/scalar_type.rb +1 -1
  39. data/lib/graphql/schema.rb +49 -18
  40. data/lib/graphql/schema/build_from_definition.rb +248 -0
  41. data/lib/graphql/schema/instrumented_field_map.rb +23 -0
  42. data/lib/graphql/schema/loader.rb +4 -11
  43. data/lib/graphql/schema/possible_types.rb +4 -2
  44. data/lib/graphql/schema/printer.rb +1 -1
  45. data/lib/graphql/schema/type_expression.rb +4 -4
  46. data/lib/graphql/schema/type_map.rb +1 -1
  47. data/lib/graphql/schema/validation.rb +4 -0
  48. data/lib/graphql/schema/warden.rb +114 -0
  49. data/lib/graphql/static_validation/literal_validator.rb +10 -7
  50. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -3
  51. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  52. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
  53. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -14
  54. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
  55. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  56. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +3 -4
  57. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +2 -1
  58. data/lib/graphql/static_validation/validation_context.rb +7 -1
  59. data/lib/graphql/union_type.rb +6 -3
  60. data/lib/graphql/unresolved_type_error.rb +1 -2
  61. data/lib/graphql/version.rb +1 -1
  62. data/readme.md +1 -5
  63. data/spec/graphql/compatibility/execution_specification_spec.rb +3 -0
  64. data/spec/graphql/compatibility/query_parser_specification_spec.rb +5 -0
  65. data/spec/graphql/compatibility/schema_parser_specification_spec.rb +5 -0
  66. data/spec/graphql/define/instance_definable_spec.rb +20 -0
  67. data/spec/graphql/directive_spec.rb +11 -0
  68. data/spec/graphql/enum_type_spec.rb +20 -1
  69. data/spec/graphql/input_object_type_spec.rb +9 -9
  70. data/spec/graphql/introspection/directive_type_spec.rb +4 -4
  71. data/spec/graphql/introspection/input_value_type_spec.rb +6 -6
  72. data/spec/graphql/introspection/type_type_spec.rb +28 -26
  73. data/spec/graphql/language/parser_spec.rb +27 -17
  74. data/spec/graphql/list_type_spec.rb +2 -2
  75. data/spec/graphql/query/variables_spec.rb +1 -0
  76. data/spec/graphql/scalar_type_spec.rb +3 -3
  77. data/spec/graphql/schema/build_from_definition_spec.rb +693 -0
  78. data/spec/graphql/schema/type_expression_spec.rb +3 -3
  79. data/spec/graphql/schema/validation_spec.rb +7 -3
  80. data/spec/graphql/schema/warden_spec.rb +510 -0
  81. data/spec/graphql/schema_spec.rb +129 -0
  82. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +1 -1
  83. data/spec/graphql/static_validation/type_stack_spec.rb +3 -3
  84. data/spec/spec_helper.rb +27 -1
  85. data/spec/support/dairy_app.rb +8 -5
  86. metadata +21 -3
  87. data/lib/graphql/language/parser_tests.rb +0 -809
@@ -124,4 +124,133 @@ describe GraphQL::Schema do
124
124
  end
125
125
  end
126
126
  end
127
+
128
+ describe "directives" do
129
+ describe "when directives are not overwritten" do
130
+ it "contains built-in directives" do
131
+ schema = GraphQL::Schema.define
132
+
133
+ assert_equal ['deprecated', 'include', 'skip'], schema.directives.keys.sort
134
+
135
+ assert_equal GraphQL::Directive::DeprecatedDirective, schema.directives['deprecated']
136
+ assert_equal GraphQL::Directive::IncludeDirective, schema.directives['include']
137
+ assert_equal GraphQL::Directive::SkipDirective, schema.directives['skip']
138
+ end
139
+ end
140
+
141
+ describe "when directives are overwritten" do
142
+ it "contains only specified directives" do
143
+ schema = GraphQL::Schema.define do
144
+ directives [GraphQL::Directive::DeprecatedDirective]
145
+ end
146
+
147
+ assert_equal ['deprecated'], schema.directives.keys.sort
148
+ assert_equal GraphQL::Directive::DeprecatedDirective, schema.directives['deprecated']
149
+ end
150
+ end
151
+ end
152
+
153
+ describe ".from_definition" do
154
+ it "uses BuildFromSchema to build a schema from a definition string" do
155
+ schema = <<-SCHEMA
156
+ type Query {
157
+ str: String
158
+ }
159
+ SCHEMA
160
+
161
+ built_schema = GraphQL::Schema.from_definition(schema)
162
+ assert_equal schema.chop, GraphQL::Schema::Printer.print_schema(built_schema)
163
+ end
164
+ end
165
+
166
+ describe ".from_introspection" do
167
+ let(:schema) {
168
+ query_root = GraphQL::ObjectType.define do
169
+ name 'Query'
170
+ field :str, types.String
171
+ end
172
+
173
+ GraphQL::Schema.define do
174
+ query query_root
175
+ end
176
+ }
177
+ let(:schema_json) {
178
+ schema.execute(GraphQL::Introspection::INTROSPECTION_QUERY)
179
+ }
180
+ it "uses Schema::Loader to build a schema from an introspection result" do
181
+ built_schema = GraphQL::Schema.from_introspection(schema_json)
182
+ assert_equal GraphQL::Schema::Printer.print_schema(schema), GraphQL::Schema::Printer.print_schema(built_schema)
183
+ end
184
+ end
185
+
186
+ describe "#instrument" do
187
+ class MultiplyInstrumenter
188
+ def initialize(multiplier)
189
+ @multiplier = multiplier
190
+ end
191
+
192
+ def instrument(type_defn, field_defn)
193
+ if type_defn.name == "Query" && field_defn.name == "int"
194
+ prev_proc = field_defn.resolve_proc
195
+ new_resolve_proc = ->(obj, args, ctx) {
196
+ inner_value = prev_proc.call(obj, args, ctx)
197
+ inner_value * @multiplier
198
+ }
199
+
200
+ field_defn.redefine do
201
+ resolve(new_resolve_proc)
202
+ end
203
+ else
204
+ field_defn
205
+ end
206
+ end
207
+ end
208
+
209
+ class VariableCountInstrumenter
210
+ attr_reader :counts
211
+ def initialize
212
+ @counts = []
213
+ end
214
+
215
+ def before_query(query)
216
+ @counts << query.variables.length
217
+ end
218
+
219
+ def after_query(query)
220
+ end
221
+ end
222
+
223
+ let(:variable_counter) {
224
+ VariableCountInstrumenter.new
225
+ }
226
+ let(:query_type) {
227
+ GraphQL::ObjectType.define do
228
+ name "Query"
229
+ field :int, types.Int do
230
+ argument :value, types.Int
231
+ resolve -> (obj, args, ctx) { args[:value] }
232
+ end
233
+ end
234
+ }
235
+
236
+ let(:schema) {
237
+ spec = self
238
+ GraphQL::Schema.define do
239
+ query(spec.query_type)
240
+ instrument(:field, MultiplyInstrumenter.new(3))
241
+ instrument(:query, spec.variable_counter)
242
+ end
243
+ }
244
+
245
+ it "can modify field definitions" do
246
+ res = schema.execute(" { int(value: 2) } ")
247
+ assert_equal 6, res["data"]["int"]
248
+ end
249
+
250
+ it "can wrap query execution" do
251
+ schema.execute("query getInt($val: Int = 5){ int(value: $val) } ")
252
+ schema.execute("query getInt($val: Int = 5, $val2: Int = 3){ int(value: $val) int2: int(value: $val2) } ")
253
+ assert_equal [1, 2], variable_counter.counts
254
+ end
255
+ end
127
256
  end
@@ -21,7 +21,7 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
21
21
 
22
22
  it "finds undefined or missing-required arguments to fields and directives" do
23
23
  # `wacky` above is handled by ArgumentsAreDefined, so only 6 are tested below
24
- assert_equal(7, errors.length)
24
+ assert_equal(8, errors.length)
25
25
 
26
26
  query_root_error = {
27
27
  "message"=>"Argument 'id' on Field 'stringCheese' has an invalid value. Expected type 'Int!'.",
@@ -8,7 +8,7 @@ class TypeCheckValidator
8
8
  def validate(context)
9
9
  self.class.checks.clear
10
10
  context.visitor[GraphQL::Language::Nodes::Field] << ->(node, parent) {
11
- self.class.checks << context.object_types.map(&:name)
11
+ self.class.checks << context.object_types.map {|t| t.name || t.kind.name }
12
12
  }
13
13
  end
14
14
  end
@@ -29,8 +29,8 @@ describe GraphQL::StaticValidation::TypeStack do
29
29
  validator.validate(query)
30
30
  expected = [
31
31
  ["Query", "Cheese"],
32
- ["Query", "Cheese", "Non-Null"],
33
- ["Edible", "Non-Null"]
32
+ ["Query", "Cheese", "NON_NULL"],
33
+ ["Edible", "NON_NULL"]
34
34
  ]
35
35
  assert_equal(expected, TypeCheckValidator.checks)
36
36
  end
@@ -16,7 +16,33 @@ Minitest::Spec.make_my_diffs_pretty!
16
16
  # to be shown.
17
17
  Minitest.backtrace_filter = Minitest::BacktraceFilter.new
18
18
 
19
- # # Load support files
19
+
20
+ # This is for convenient access to metadata in test definitions
21
+ assign_metadata_key = -> (target, key, value) { target.metadata[key] = value }
22
+ GraphQL::BaseType.accepts_definitions(metadata: assign_metadata_key)
23
+ GraphQL::Field.accepts_definitions(metadata: assign_metadata_key)
24
+ GraphQL::Argument.accepts_definitions(metadata: assign_metadata_key)
25
+ GraphQL::EnumType::EnumValue.accepts_definitions(metadata: assign_metadata_key)
26
+
27
+ # Can be used as a GraphQL::Schema::Warden for some purposes, but allows anything
28
+ module PermissiveWarden
29
+ def self.input_fields(input_obj)
30
+ input_obj.arguments.values
31
+ end
32
+
33
+ def self.enum_values(enum_type)
34
+ enum_type.values.values
35
+ end
36
+ end
37
+
38
+ # Can be used as a GraphQL::Schema::Warden for some purposes, but allows nothing
39
+ module NothingWarden
40
+ def self.enum_values(enum_type)
41
+ []
42
+ end
43
+ end
44
+
45
+ # Load support files
20
46
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
21
47
 
22
48
  def star_wars_query(string, variables={})
@@ -33,10 +33,12 @@ end
33
33
  DairyAnimalEnum = GraphQL::EnumType.define do
34
34
  name "DairyAnimal"
35
35
  description "An animal which can yield milk"
36
- value("COW", "Animal with black and white spots", value: 1)
37
- value("GOAT", "Animal with horns")
38
- value("SHEEP", "Animal with wool")
39
- value("YAK", "Animal with long hair", deprecation_reason: "Out of fashion")
36
+ value("COW", "Animal with black and white spots", value: 1)
37
+ value("DONKEY", "Animal with fur", value: :donkey)
38
+ value("GOAT", "Animal with horns")
39
+ value("REINDEER", "Animal with horns", value: 'reindeer')
40
+ value("SHEEP", "Animal with wool")
41
+ value("YAK", "Animal with long hair", deprecation_reason: "Out of fashion")
40
42
  end
41
43
 
42
44
  CheeseType = GraphQL::ObjectType.define do
@@ -57,7 +59,8 @@ CheeseType = GraphQL::ObjectType.define do
57
59
  field :similarCheese, CheeseType, "Cheeses like this one", property: :this_should_be_overriden do
58
60
  # metadata test
59
61
  joins [:cheeses, :milks]
60
- argument :source, !types[!DairyAnimalEnum], default_value: [1]
62
+ argument :source, !types[!DairyAnimalEnum]
63
+ argument :nullableSource, types[!DairyAnimalEnum], default_value: [1]
61
64
  resolve ->(t, a, c) {
62
65
  # get the strings out:
63
66
  sources = a["source"]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-25 00:00:00.000000000 Z
11
+ date: 2016-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: codeclimate-test-reporter
@@ -271,6 +271,12 @@ files:
271
271
  - lib/graphql/argument.rb
272
272
  - lib/graphql/base_type.rb
273
273
  - lib/graphql/boolean_type.rb
274
+ - lib/graphql/compatibility.rb
275
+ - lib/graphql/compatibility/execution_specification.rb
276
+ - lib/graphql/compatibility/query_parser_specification.rb
277
+ - lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb
278
+ - lib/graphql/compatibility/query_parser_specification/query_assertions.rb
279
+ - lib/graphql/compatibility/schema_parser_specification.rb
274
280
  - lib/graphql/define.rb
275
281
  - lib/graphql/define/assign_argument.rb
276
282
  - lib/graphql/define/assign_connection.rb
@@ -330,7 +336,6 @@ files:
330
336
  - lib/graphql/language/nodes.rb
331
337
  - lib/graphql/language/parser.rb
332
338
  - lib/graphql/language/parser.y
333
- - lib/graphql/language/parser_tests.rb
334
339
  - lib/graphql/language/token.rb
335
340
  - lib/graphql/language/visitor.rb
336
341
  - lib/graphql/list_type.rb
@@ -365,7 +370,9 @@ files:
365
370
  - lib/graphql/relay/relation_connection.rb
366
371
  - lib/graphql/scalar_type.rb
367
372
  - lib/graphql/schema.rb
373
+ - lib/graphql/schema/build_from_definition.rb
368
374
  - lib/graphql/schema/catchall_middleware.rb
375
+ - lib/graphql/schema/instrumented_field_map.rb
369
376
  - lib/graphql/schema/invalid_type_error.rb
370
377
  - lib/graphql/schema/loader.rb
371
378
  - lib/graphql/schema/middleware_chain.rb
@@ -378,6 +385,7 @@ files:
378
385
  - lib/graphql/schema/type_map.rb
379
386
  - lib/graphql/schema/unique_within_type.rb
380
387
  - lib/graphql/schema/validation.rb
388
+ - lib/graphql/schema/warden.rb
381
389
  - lib/graphql/static_validation.rb
382
390
  - lib/graphql/static_validation/all_rules.rb
383
391
  - lib/graphql/static_validation/arguments_validator.rb
@@ -421,6 +429,9 @@ files:
421
429
  - spec/graphql/argument_spec.rb
422
430
  - spec/graphql/base_type_spec.rb
423
431
  - spec/graphql/boolean_type_spec.rb
432
+ - spec/graphql/compatibility/execution_specification_spec.rb
433
+ - spec/graphql/compatibility/query_parser_specification_spec.rb
434
+ - spec/graphql/compatibility/schema_parser_specification_spec.rb
424
435
  - spec/graphql/define/instance_definable_spec.rb
425
436
  - spec/graphql/directive_spec.rb
426
437
  - spec/graphql/enum_type_spec.rb
@@ -464,6 +475,7 @@ files:
464
475
  - spec/graphql/relay/page_info_spec.rb
465
476
  - spec/graphql/relay/relation_connection_spec.rb
466
477
  - spec/graphql/scalar_type_spec.rb
478
+ - spec/graphql/schema/build_from_definition_spec.rb
467
479
  - spec/graphql/schema/catchall_middleware_spec.rb
468
480
  - spec/graphql/schema/loader_spec.rb
469
481
  - spec/graphql/schema/middleware_chain_spec.rb
@@ -474,6 +486,7 @@ files:
474
486
  - spec/graphql/schema/type_expression_spec.rb
475
487
  - spec/graphql/schema/unique_within_type_spec.rb
476
488
  - spec/graphql/schema/validation_spec.rb
489
+ - spec/graphql/schema/warden_spec.rb
477
490
  - spec/graphql/schema_spec.rb
478
491
  - spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb
479
492
  - spec/graphql/static_validation/rules/arguments_are_defined_spec.rb
@@ -540,6 +553,9 @@ test_files:
540
553
  - spec/graphql/argument_spec.rb
541
554
  - spec/graphql/base_type_spec.rb
542
555
  - spec/graphql/boolean_type_spec.rb
556
+ - spec/graphql/compatibility/execution_specification_spec.rb
557
+ - spec/graphql/compatibility/query_parser_specification_spec.rb
558
+ - spec/graphql/compatibility/schema_parser_specification_spec.rb
543
559
  - spec/graphql/define/instance_definable_spec.rb
544
560
  - spec/graphql/directive_spec.rb
545
561
  - spec/graphql/enum_type_spec.rb
@@ -583,6 +599,7 @@ test_files:
583
599
  - spec/graphql/relay/page_info_spec.rb
584
600
  - spec/graphql/relay/relation_connection_spec.rb
585
601
  - spec/graphql/scalar_type_spec.rb
602
+ - spec/graphql/schema/build_from_definition_spec.rb
586
603
  - spec/graphql/schema/catchall_middleware_spec.rb
587
604
  - spec/graphql/schema/loader_spec.rb
588
605
  - spec/graphql/schema/middleware_chain_spec.rb
@@ -593,6 +610,7 @@ test_files:
593
610
  - spec/graphql/schema/type_expression_spec.rb
594
611
  - spec/graphql/schema/unique_within_type_spec.rb
595
612
  - spec/graphql/schema/validation_spec.rb
613
+ - spec/graphql/schema/warden_spec.rb
596
614
  - spec/graphql/schema_spec.rb
597
615
  - spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb
598
616
  - spec/graphql/static_validation/rules/arguments_are_defined_spec.rb
@@ -1,809 +0,0 @@
1
- module GraphQL
2
- module Language
3
- # If you create your own GraphQL parser, can verify it using these tests.
4
- #
5
- # @example Include these tests in a Minitest suite
6
- # require 'graphql/language/parser_tests'
7
- #
8
- # describe MyParser do
9
- # include GraphQL::Language::ParserTests
10
- # subject { MyParser }
11
- # end
12
- module ParserTests
13
- def self.included(test)
14
- test.send(:describe, "Parser Tests") do
15
- let(:document) { subject.parse(query_string) }
16
- let(:query_string) {%|
17
- query getStuff($someVar: Int = 1, $anotherVar: [String!] ) @skip(if: false) {
18
- myField: someField(someArg: $someVar, ok: 1.4) @skip(if: $anotherVar) @thing(or: "Whatever")
19
-
20
- anotherField(someArg: [1,2,3]) {
21
- nestedField
22
- ... moreNestedFields @skip(if: true)
23
- }
24
-
25
- ... on OtherType @include(unless: false){
26
- field(arg: [{key: "value", anotherKey: 0.9, anotherAnotherKey: WHATEVER}])
27
- anotherField
28
- }
29
-
30
- ... {
31
- id
32
- }
33
- }
34
-
35
- fragment moreNestedFields on NestedType @or(something: "ok") {
36
- anotherNestedField @enum(directive: true)
37
- }
38
- |}
39
-
40
- describe ".parse" do
41
- it "parses queries" do
42
- assert document
43
- end
44
-
45
- describe "visited nodes" do
46
- let(:query) { document.definitions.first }
47
- let(:fragment_def) { document.definitions.last }
48
-
49
- it "creates a valid document" do
50
- assert document.is_a?(GraphQL::Language::Nodes::Document)
51
- assert_equal 2, document.definitions.length
52
- end
53
-
54
- it "creates a valid operation" do
55
- assert query.is_a?(GraphQL::Language::Nodes::OperationDefinition)
56
- assert_equal "getStuff", query.name
57
- assert_equal "query", query.operation_type
58
- assert_equal 2, query.variables.length
59
- assert_equal 4, query.selections.length
60
- assert_equal 1, query.directives.length
61
- assert_equal [2, 13], [query.line, query.col]
62
- end
63
-
64
- it "creates a valid fragment definition" do
65
- assert fragment_def.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
66
- assert_equal "moreNestedFields", fragment_def.name
67
- assert_equal 1, fragment_def.selections.length
68
- assert_equal "NestedType", fragment_def.type.name
69
- assert_equal 1, fragment_def.directives.length
70
- assert_equal [20, 13], fragment_def.position
71
- end
72
-
73
- describe "variable definitions" do
74
- let(:optional_var) { query.variables.first }
75
- it "gets name and type" do
76
- assert_equal "someVar", optional_var.name
77
- assert_equal "Int", optional_var.type.name
78
- end
79
-
80
- it "gets default value" do
81
- assert_equal 1, optional_var.default_value
82
- end
83
-
84
- it "gets position info" do
85
- assert_equal [2, 28], optional_var.position
86
- end
87
- end
88
-
89
- describe "fields" do
90
- let(:leaf_field) { query.selections.first }
91
- let(:parent_field) { query.selections[1] }
92
-
93
- it "gets name, alias, arguments and directives" do
94
- assert_equal "someField", leaf_field.name
95
- assert_equal "myField", leaf_field.alias
96
- assert_equal 2, leaf_field.directives.length
97
- assert_equal 2, leaf_field.arguments.length
98
- end
99
-
100
- it "gets nested fields" do
101
- assert_equal 2, parent_field.selections.length
102
- end
103
-
104
- it "gets location info" do
105
- assert_equal [3 ,15], leaf_field.position
106
- end
107
-
108
- describe "when the arguments list is empty" do
109
- let(:query_string) { "{ field() }"}
110
- let(:field) { query.selections.first }
111
- it "has zero arguments" do
112
- assert_equal 0, field.arguments.length
113
- end
114
- end
115
-
116
- describe "when selections are empty" do
117
- let(:query_string) { "{ field { } }"}
118
- let(:field) { query.selections.first }
119
- it "has zero selections" do
120
- assert_equal 0, field.selections.length
121
- end
122
- end
123
- end
124
-
125
- describe "arguments" do
126
- let(:literal_argument) { query.selections.first.arguments.last }
127
- let(:variable_argument) { query.selections.first.arguments.first }
128
-
129
- it "gets name and literal value" do
130
- assert_equal "ok", literal_argument.name
131
- assert_equal 1.4, literal_argument.value
132
- end
133
-
134
- it "gets name and variable value" do
135
- assert_equal "someArg", variable_argument.name
136
- assert_equal "someVar", variable_argument.value.name
137
- end
138
-
139
-
140
- it "gets position info" do
141
- assert_equal [3, 34], variable_argument.position
142
- end
143
- end
144
-
145
- describe "fragment spreads" do
146
- let(:fragment_spread) { query.selections[1].selections.last }
147
- it "gets the name and directives" do
148
- assert_equal "moreNestedFields", fragment_spread.name
149
- assert_equal 1, fragment_spread.directives.length
150
- end
151
-
152
- it "gets position info" do
153
- assert_equal [7, 17], fragment_spread.position
154
- end
155
- end
156
-
157
- describe "directives" do
158
- let(:variable_directive) { query.selections.first.directives.first }
159
-
160
- it "gets the name and arguments" do
161
- assert_equal "skip", variable_directive.name
162
- assert_equal "if", variable_directive.arguments.first.name
163
- assert_equal 1, variable_directive.arguments.length
164
- end
165
-
166
- it "gets position info" do
167
- assert_equal [3, 62], variable_directive.position
168
- end
169
- end
170
-
171
- describe "inline fragments" do
172
- let(:inline_fragment) { query.selections[2] }
173
- let(:typeless_inline_fragment) { query.selections[3] }
174
-
175
- it "gets the type and directives" do
176
- assert_equal "OtherType", inline_fragment.type.name
177
- assert_equal 2, inline_fragment.selections.length
178
- assert_equal 1, inline_fragment.directives.length
179
- end
180
-
181
- it "gets inline fragments without type conditions" do
182
- assert_equal nil, typeless_inline_fragment.type
183
- assert_equal 1, typeless_inline_fragment.selections.length
184
- assert_equal 0, typeless_inline_fragment.directives.length
185
- end
186
-
187
- it "gets position info" do
188
- assert_equal [10, 15], inline_fragment.position
189
- end
190
- end
191
-
192
- describe "inputs" do
193
- let(:query_string) {%|
194
- {
195
- field(
196
- int: 3,
197
- float: 4.7e-24,
198
- bool: false,
199
- string: "☀︎🏆\\n escaped \\" unicode \\u00b6 /",
200
- enum: ENUM_NAME,
201
- array: [7, 8, 9]
202
- object: {a: [1,2,3], b: {c: "4"}}
203
- unicode_bom: "\xef\xbb\xbfquery"
204
- keywordEnum: on
205
- )
206
- }
207
- |}
208
-
209
- let(:inputs) { document.definitions.first.selections.first.arguments }
210
-
211
- it "parses ints" do
212
- assert_equal 3, inputs[0].value
213
- end
214
-
215
- it "parses floats" do
216
- assert_equal 0.47e-23, inputs[1].value
217
- end
218
-
219
- it "parses booleans" do
220
- assert_equal false, inputs[2].value
221
- end
222
-
223
- it "parses UTF-8 strings" do
224
- assert_equal %|☀︎🏆\n escaped " unicode ¶ /|, inputs[3].value
225
- end
226
-
227
- it "parses enums" do
228
- assert_instance_of GraphQL::Language::Nodes::Enum, inputs[4].value
229
- assert_equal "ENUM_NAME", inputs[4].value.name
230
- end
231
-
232
- it "parses arrays" do
233
- assert_equal [7,8,9], inputs[5].value
234
- end
235
-
236
- it "parses objects" do
237
- obj = inputs[6].value
238
- assert_equal "a", obj.arguments[0].name
239
- assert_equal [1,2,3], obj.arguments[0].value
240
- assert_equal "b", obj.arguments[1].name
241
- assert_equal "c", obj.arguments[1].value.arguments[0].name
242
- assert_equal "4", obj.arguments[1].value.arguments[0].value
243
- end
244
-
245
- it "parses unicode bom" do
246
- obj = inputs[7].value
247
- assert_equal %|\xef\xbb\xbfquery|, inputs[7].value
248
- end
249
-
250
- it "parses enum 'on''" do
251
- assert_equal "on", inputs[8].value.name
252
- end
253
- end
254
- end
255
-
256
- describe "unnamed queries" do
257
- let(:query_string) {%|
258
- { name, age, height }
259
- |}
260
- let(:operation) { document.definitions.first }
261
-
262
- it "parses unnamed queries" do
263
- assert_equal 1, document.definitions.length
264
- assert_equal "query", operation.operation_type
265
- assert_equal nil, operation.name
266
- assert_equal 3, operation.selections.length
267
- end
268
- end
269
-
270
- describe "introspection query" do
271
- let(:query_string) { GraphQL::Introspection::INTROSPECTION_QUERY }
272
-
273
- it "parses a big ol' query" do
274
- assert(document)
275
- end
276
- end
277
-
278
- describe "schema with comments" do
279
- let(:query_string) {%|
280
- # Schema at beginning of file
281
-
282
- schema {
283
- query: Hello
284
- }
285
-
286
- # Comment between two definitions are omitted
287
-
288
- # This is a directive
289
- directive @foo(
290
- # It has an argument
291
- arg: Int
292
- ) on FIELD
293
-
294
- # Multiline comment
295
- #
296
- # With an enum
297
- enum Color {
298
- RED
299
-
300
- # Not a creative color
301
- GREEN
302
- BLUE
303
- }
304
-
305
- #Comment without preceding space
306
- type Hello {
307
- # And a field to boot
308
- str: String
309
- }
310
-
311
- # Comment for input object types
312
- input Car {
313
- # Color of the car
314
- color: String!
315
- }
316
-
317
- # Comment for interface definitions
318
- interface Vehicle {
319
- # Amount of wheels
320
- wheels: Int!
321
- }
322
-
323
- # Comment at the end of schema
324
- |}
325
-
326
- it "parses successfully" do
327
- document = subject.parse(query_string)
328
-
329
- assert_equal 6, document.definitions.size
330
-
331
- schema_definition = document.definitions.shift
332
- assert_equal GraphQL::Language::Nodes::SchemaDefinition, schema_definition.class
333
-
334
- directive_definition = document.definitions.shift
335
- assert_equal GraphQL::Language::Nodes::DirectiveDefinition, directive_definition.class
336
- assert_equal 'This is a directive', directive_definition.description
337
-
338
- enum_type_definition = document.definitions.shift
339
- assert_equal GraphQL::Language::Nodes::EnumTypeDefinition, enum_type_definition.class
340
- assert_equal "Multiline comment\n\nWith an enum", enum_type_definition.description
341
-
342
- assert_nil enum_type_definition.values[0].description
343
- assert_equal 'Not a creative color', enum_type_definition.values[1].description
344
-
345
- object_type_definition = document.definitions.shift
346
- assert_equal GraphQL::Language::Nodes::ObjectTypeDefinition, object_type_definition.class
347
- assert_equal 'Comment without preceding space', object_type_definition.description
348
- assert_equal 'And a field to boot', object_type_definition.fields[0].description
349
-
350
- input_object_type_definition = document.definitions.shift
351
- assert_equal GraphQL::Language::Nodes::InputObjectTypeDefinition, input_object_type_definition.class
352
- assert_equal 'Comment for input object types', input_object_type_definition.description
353
- assert_equal 'Color of the car', input_object_type_definition.fields[0].description
354
-
355
- interface_type_definition = document.definitions.shift
356
- assert_equal GraphQL::Language::Nodes::InterfaceTypeDefinition, interface_type_definition.class
357
- assert_equal 'Comment for interface definitions', interface_type_definition.description
358
- assert_equal 'Amount of wheels', interface_type_definition.fields[0].description
359
- end
360
- end
361
-
362
- describe "schema" do
363
- it "parses the test schema" do
364
- schema = DummySchema
365
- schema_string = GraphQL::Schema::Printer.print_schema(schema)
366
-
367
- document = subject.parse(schema_string)
368
-
369
- assert_equal schema_string, document.to_query_string
370
- end
371
-
372
- it "parses mimal schema definition" do
373
- document = subject.parse('schema { query: QueryRoot }')
374
-
375
- schema = document.definitions.first
376
- assert_equal 'QueryRoot', schema.query
377
- assert_equal nil, schema.mutation
378
- assert_equal nil, schema.subscription
379
- end
380
-
381
- it "parses full schema definitions" do
382
- document = subject.parse('
383
- schema {
384
- query: QueryRoot
385
- mutation: MutationRoot
386
- subscription: SubscriptionRoot
387
- }
388
- ')
389
-
390
- schema = document.definitions.first
391
- assert_equal 'QueryRoot', schema.query
392
- assert_equal 'MutationRoot', schema.mutation
393
- assert_equal 'SubscriptionRoot', schema.subscription
394
- end
395
-
396
- it "parses object types" do
397
- document = subject.parse('
398
- type Comment implements Node {
399
- id: ID!
400
- }
401
- ')
402
-
403
- type = document.definitions.first
404
- assert_equal GraphQL::Language::Nodes::ObjectTypeDefinition, type.class
405
- assert_equal 'Comment', type.name
406
- assert_equal ['Node'], type.interfaces.map(&:name)
407
- assert_equal ['id'], type.fields.map(&:name)
408
- assert_equal [], type.fields[0].arguments
409
- assert_equal 'ID', type.fields[0].type.of_type.name
410
- end
411
-
412
- it "parses object types with directives" do
413
- document = subject.parse('
414
- type Comment implements Node @deprecated(reason: "No longer supported") {
415
- id: ID!
416
- }
417
- ')
418
-
419
- type = document.definitions.first
420
- assert_equal GraphQL::Language::Nodes::ObjectTypeDefinition, type.class
421
- assert_equal 'Comment', type.name
422
- assert_equal ['Node'], type.interfaces.map(&:name)
423
- assert_equal ['id'], type.fields.map(&:name)
424
- assert_equal [], type.fields[0].arguments
425
- assert_equal 'ID', type.fields[0].type.of_type.name
426
- assert_equal 1, type.directives.length
427
-
428
- deprecated_directive = type.directives[0]
429
- assert_equal 'deprecated', deprecated_directive.name
430
- assert_equal 'reason', deprecated_directive.arguments[0].name
431
- assert_equal 'No longer supported', deprecated_directive.arguments[0].value
432
- end
433
-
434
- it "parses field arguments" do
435
- document = subject.parse('
436
- type Mutation {
437
- post(id: ID!, data: PostData = { message: "First!1!", type: BLOG, tags: ["Test", "Annoying"] }): Post
438
- }
439
- ')
440
-
441
- field = document.definitions.first.fields.first
442
- assert_equal ['id', 'data'], field.arguments.map(&:name)
443
- data_arg = field.arguments[1]
444
- assert_equal 'PostData', data_arg.type.name
445
- assert_equal ['message', 'type', 'tags'], data_arg.default_value.arguments.map(&:name)
446
- tags_arg = data_arg.default_value.arguments[2]
447
- assert_equal ['Test', 'Annoying'], tags_arg.value
448
- end
449
-
450
- it "parses field arguments with directives" do
451
- document = subject.parse('
452
- type Mutation {
453
- post(id: ID! @deprecated(reason: "No longer supported"), data: String): Post
454
- }
455
- ')
456
-
457
- field = document.definitions.first.fields.first
458
- assert_equal ['id', 'data'], field.arguments.map(&:name)
459
- id_arg = field.arguments[0]
460
-
461
- deprecated_directive = id_arg.directives[0]
462
- assert_equal 'deprecated', deprecated_directive.name
463
- assert_equal 'reason', deprecated_directive.arguments[0].name
464
- assert_equal 'No longer supported', deprecated_directive.arguments[0].value
465
- end
466
-
467
- it "parses directive definition" do
468
- document = subject.parse('
469
- directive @include(if: Boolean!)
470
- on FIELD
471
- | FRAGMENT_SPREAD
472
- | INLINE_FRAGMENT
473
- ')
474
-
475
- type = document.definitions.first
476
- assert_equal GraphQL::Language::Nodes::DirectiveDefinition, type.class
477
- assert_equal 'include', type.name
478
-
479
- assert_equal 1, type.arguments.length
480
- assert_equal 'if', type.arguments[0].name
481
- assert_equal 'Boolean', type.arguments[0].type.of_type.name
482
-
483
- assert_equal ['FIELD', 'FRAGMENT_SPREAD', 'INLINE_FRAGMENT'], type.locations
484
- end
485
-
486
- it "parses scalar types" do
487
- document = subject.parse('scalar DateTime')
488
-
489
- type = document.definitions.first
490
- assert_equal GraphQL::Language::Nodes::ScalarTypeDefinition, type.class
491
- assert_equal 'DateTime', type.name
492
- end
493
-
494
- it "parses scalar types with directives" do
495
- document = subject.parse('scalar DateTime @deprecated(reason: "No longer supported")')
496
-
497
- type = document.definitions.first
498
- assert_equal GraphQL::Language::Nodes::ScalarTypeDefinition, type.class
499
- assert_equal 'DateTime', type.name
500
- assert_equal 1, type.directives.length
501
-
502
- deprecated_directive = type.directives[0]
503
- assert_equal 'deprecated', deprecated_directive.name
504
- assert_equal 'reason', deprecated_directive.arguments[0].name
505
- assert_equal 'No longer supported', deprecated_directive.arguments[0].value
506
- end
507
-
508
- it "parses interface types" do
509
- document = subject.parse('
510
- interface Node {
511
- id: ID!
512
- }
513
- ')
514
-
515
- type = document.definitions.first
516
- assert_equal GraphQL::Language::Nodes::InterfaceTypeDefinition, type.class
517
- assert_equal 'Node', type.name
518
- assert_equal ['id'], type.fields.map(&:name)
519
- assert_equal [], type.fields[0].arguments
520
- assert_equal 'ID', type.fields[0].type.of_type.name
521
- end
522
-
523
- it "parses interface types with directives" do
524
- document = subject.parse('
525
- interface Node @deprecated(reason: "No longer supported") {
526
- id: ID!
527
- }
528
- ')
529
-
530
- type = document.definitions.first
531
- assert_equal GraphQL::Language::Nodes::InterfaceTypeDefinition, type.class
532
- assert_equal 'Node', type.name
533
- assert_equal 1, type.directives.length
534
-
535
- deprecated_directive = type.directives[0]
536
- assert_equal 'deprecated', deprecated_directive.name
537
- assert_equal 'reason', deprecated_directive.arguments[0].name
538
- assert_equal 'No longer supported', deprecated_directive.arguments[0].value
539
- end
540
-
541
- it "parses enum types" do
542
- document = subject.parse('
543
- enum DogCommand {
544
- SIT
545
- DOWN @deprecated(reason: "No longer supported")
546
- HEEL
547
- }
548
- ')
549
-
550
- type = document.definitions.first
551
- assert_equal GraphQL::Language::Nodes::EnumTypeDefinition, type.class
552
- assert_equal 'DogCommand', type.name
553
- assert_equal 3, type.values.length
554
-
555
- assert_equal 'SIT', type.values[0].name
556
- assert_equal [], type.values[0].directives
557
-
558
- assert_equal 'DOWN', type.values[1].name
559
- assert_equal 1, type.values[1].directives.length
560
- deprecated_directive = type.values[1].directives[0]
561
- assert_equal 'deprecated', deprecated_directive.name
562
- assert_equal 'reason', deprecated_directive.arguments[0].name
563
- assert_equal 'No longer supported', deprecated_directive.arguments[0].value
564
-
565
- assert_equal 'HEEL', type.values[2].name
566
- assert_equal [], type.values[2].directives
567
- end
568
-
569
- it "parses enum types with directives" do
570
- document = subject.parse('
571
- enum DogCommand @deprecated(reason: "No longer supported") {
572
- SIT
573
- }
574
- ')
575
-
576
- type = document.definitions.first
577
- assert_equal GraphQL::Language::Nodes::EnumTypeDefinition, type.class
578
- assert_equal 'DogCommand', type.name
579
- assert_equal 1, type.directives.length
580
-
581
- deprecated_directive = type.directives[0]
582
- assert_equal 'deprecated', deprecated_directive.name
583
- assert_equal 'reason', deprecated_directive.arguments[0].name
584
- assert_equal 'No longer supported', deprecated_directive.arguments[0].value
585
- end
586
-
587
- it "parses input object types" do
588
- document = subject.parse('
589
- input EmptyMutationInput {
590
- clientMutationId: String
591
- }
592
- ')
593
-
594
- type = document.definitions.first
595
- assert_equal GraphQL::Language::Nodes::InputObjectTypeDefinition, type.class
596
- assert_equal 'EmptyMutationInput', type.name
597
- assert_equal ['clientMutationId'], type.fields.map(&:name)
598
- assert_equal 'String', type.fields[0].type.name
599
- assert_equal nil, type.fields[0].default_value
600
- end
601
-
602
- it "parses input object types with directives" do
603
- document = subject.parse('
604
- input EmptyMutationInput @deprecated(reason: "No longer supported") {
605
- clientMutationId: String
606
- }
607
- ')
608
-
609
- type = document.definitions.first
610
- assert_equal GraphQL::Language::Nodes::InputObjectTypeDefinition, type.class
611
- assert_equal 'EmptyMutationInput', type.name
612
- assert_equal ['clientMutationId'], type.fields.map(&:name)
613
- assert_equal 'String', type.fields[0].type.name
614
- assert_equal nil, type.fields[0].default_value
615
- assert_equal 1, type.directives.length
616
-
617
- deprecated_directive = type.directives[0]
618
- assert_equal 'deprecated', deprecated_directive.name
619
- assert_equal 'reason', deprecated_directive.arguments[0].name
620
- assert_equal 'No longer supported', deprecated_directive.arguments[0].value
621
-
622
- end
623
- end
624
- end
625
-
626
- describe "errors" do
627
- let(:query_string) {%| query doSomething { bogus { } |}
628
- it "raises a parse error" do
629
- err = assert_raises(GraphQL::ParseError) { document }
630
- end
631
-
632
- it "correctly identifies parse error location and content" do
633
- e = assert_raises(GraphQL::ParseError) do
634
- GraphQL.parse("
635
- query getCoupons {
636
- allCoupons: {data{id}}
637
- }
638
- ")
639
- end
640
- assert_includes(e.message, '"{"')
641
- assert_includes(e.message, "LCURLY")
642
- assert_equal(3, e.line)
643
- assert_equal(33, e.col)
644
- end
645
-
646
- it "handles unexpected ends" do
647
- err = assert_raises(GraphQL::ParseError) { GraphQL.parse("{ ") }
648
- assert_equal "Unexpected end of document", err.message
649
- end
650
-
651
- it "rejects unsupported characters" do
652
- e = assert_raises(GraphQL::ParseError) do
653
- GraphQL.parse("{ field; }")
654
- end
655
-
656
- assert_includes(e.message, "Parse error on \";\"")
657
- end
658
-
659
- it "rejects control characters" do
660
- e = assert_raises(GraphQL::ParseError) do
661
- GraphQL.parse("{ \afield }")
662
- end
663
-
664
- assert_includes(e.message, "Parse error on \"\\a\"")
665
- end
666
-
667
- it "rejects partial BOM" do
668
- e = assert_raises(GraphQL::ParseError) do
669
- GraphQL.parse("{ \xeffield }")
670
- end
671
-
672
- assert_includes(e.message, "Parse error on \"\\xEF\"")
673
- end
674
-
675
- it "rejects vertical tabs" do
676
- e = assert_raises(GraphQL::ParseError) do
677
- GraphQL.parse("{ \vfield }")
678
- end
679
-
680
- assert_includes(e.message, "Parse error on \"\\v\"")
681
- end
682
-
683
- it "rejects form feed" do
684
- e = assert_raises(GraphQL::ParseError) do
685
- GraphQL.parse("{ \ffield }")
686
- end
687
-
688
- assert_includes(e.message, "Parse error on \"\\f\"")
689
- end
690
-
691
- it "rejects no break space" do
692
- e = assert_raises(GraphQL::ParseError) do
693
- GraphQL.parse("{ \xa0field }")
694
- end
695
-
696
- assert_includes(e.message, "Parse error on \"\\xA0\"")
697
- end
698
-
699
- it "rejects unterminated strings" do
700
- e = assert_raises(GraphQL::ParseError) do
701
- GraphQL.parse("\"")
702
- end
703
-
704
- assert_includes(e.message, "Parse error on \"\\\"\"")
705
-
706
- e = assert_raises(GraphQL::ParseError) do
707
- GraphQL.parse("\"\n\"")
708
- end
709
-
710
- assert_includes(e.message, "Parse error on \"\\n\"")
711
- end
712
-
713
- it "rejects bad escape sequence in strings" do
714
- e = assert_raises(GraphQL::ParseError) do
715
- GraphQL.parse("{ field(arg:\"\\x\") }")
716
- end
717
-
718
- assert_includes(e.message, "Parse error on bad Unicode escape sequence")
719
- end
720
-
721
- it "rejects incomplete escape sequence in strings" do
722
- e = assert_raises(GraphQL::ParseError) do
723
- GraphQL.parse("{ field(arg:\"\\u1\") }")
724
- end
725
-
726
- assert_includes(e.message, "bad Unicode escape sequence")
727
- end
728
-
729
- it "rejects unicode escape with bad chars" do
730
- e = assert_raises(GraphQL::ParseError) do
731
- GraphQL.parse("{ field(arg:\"\\u0XX1\") }")
732
- end
733
-
734
- assert_includes(e.message, "bad Unicode escape sequence")
735
-
736
- e = assert_raises(GraphQL::ParseError) do
737
- GraphQL.parse("{ field(arg:\"\\uXXXX\") }")
738
- end
739
-
740
- assert_includes(e.message, "bad Unicode escape sequence")
741
-
742
-
743
- e = assert_raises(GraphQL::ParseError) do
744
- GraphQL.parse("{ field(arg:\"\\uFXXX\") }")
745
- end
746
-
747
- assert_includes(e.message, "bad Unicode escape sequence")
748
-
749
-
750
- e = assert_raises(GraphQL::ParseError) do
751
- GraphQL.parse("{ field(arg:\"\\uXXXF\") }")
752
- end
753
-
754
- assert_includes(e.message, "bad Unicode escape sequence")
755
- end
756
-
757
- it "rejects fragments named 'on'" do
758
- e = assert_raises(GraphQL::ParseError) do
759
- GraphQL.parse("fragment on on on { on }")
760
- end
761
-
762
- assert_includes(e.message, "Parse error on \"on\"")
763
- end
764
-
765
- it "rejects fragment spread of 'on'" do
766
- e = assert_raises(GraphQL::ParseError) do
767
- GraphQL.parse("{ ...on }")
768
- end
769
-
770
- assert_includes(e.message, "Parse error on \"}\"")
771
- end
772
-
773
- it "rejects null value" do
774
- e = assert_raises(GraphQL::ParseError) do
775
- GraphQL.parse("{ fieldWithNullableStringInput(input: null) }")
776
- end
777
-
778
- assert_includes(e.message, "Parse error on \"null\"")
779
- end
780
- end
781
-
782
-
783
- describe "whitespace" do
784
- describe "whitespace-only queries" do
785
- let(:query_string) { " " }
786
- it "doesn't blow up" do
787
- assert_equal [], document.definitions
788
- end
789
- end
790
-
791
- describe "empty string queries" do
792
- let(:query_string) { "" }
793
- it "doesn't blow up" do
794
- assert_equal [], document.definitions
795
- end
796
- end
797
-
798
- describe "using tabs as whitespace" do
799
- let(:query_string) { "\t{\t\tid, \tname}"}
800
- it "parses the query" do
801
- assert_equal 1, document.definitions.length
802
- end
803
- end
804
- end
805
- end
806
- end
807
- end
808
- end
809
- end