graphql 0.12.1 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql.rb +31 -41
- data/lib/graphql/argument.rb +23 -21
- data/lib/graphql/base_type.rb +5 -8
- data/lib/graphql/define/assign_argument.rb +5 -2
- data/lib/graphql/define/type_definer.rb +2 -1
- data/lib/graphql/directive.rb +34 -36
- data/lib/graphql/directive/include_directive.rb +3 -7
- data/lib/graphql/directive/skip_directive.rb +3 -7
- data/lib/graphql/enum_type.rb +78 -76
- data/lib/graphql/execution_error.rb +1 -3
- data/lib/graphql/field.rb +99 -95
- data/lib/graphql/input_object_type.rb +49 -47
- data/lib/graphql/interface_type.rb +31 -34
- data/lib/graphql/introspection.rb +19 -18
- data/lib/graphql/introspection/directive_location_enum.rb +8 -0
- data/lib/graphql/introspection/directive_type.rb +1 -3
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/fields_field.rb +1 -1
- data/lib/graphql/introspection/introspection_query.rb +1 -3
- data/lib/graphql/introspection/possible_types_field.rb +7 -1
- data/lib/graphql/introspection/schema_field.rb +13 -9
- data/lib/graphql/introspection/type_by_name_field.rb +13 -17
- data/lib/graphql/introspection/typename_field.rb +12 -8
- data/lib/graphql/language.rb +5 -9
- data/lib/graphql/language/lexer.rb +668 -0
- data/lib/graphql/language/lexer.rl +149 -0
- data/lib/graphql/language/parser.rb +842 -116
- data/lib/graphql/language/parser.y +264 -0
- data/lib/graphql/language/token.rb +21 -0
- data/lib/graphql/list_type.rb +33 -31
- data/lib/graphql/non_null_type.rb +33 -31
- data/lib/graphql/object_type.rb +52 -55
- data/lib/graphql/query.rb +83 -80
- data/lib/graphql/query/context.rb +5 -1
- data/lib/graphql/query/directive_resolution.rb +16 -0
- data/lib/graphql/query/executor.rb +3 -3
- data/lib/graphql/query/input_validation_result.rb +17 -15
- data/lib/graphql/query/serial_execution.rb +5 -5
- data/lib/graphql/query/serial_execution/execution_context.rb +4 -3
- data/lib/graphql/query/serial_execution/selection_resolution.rb +19 -21
- data/lib/graphql/query/serial_execution/value_resolution.rb +1 -1
- data/lib/graphql/query/type_resolver.rb +22 -18
- data/lib/graphql/query/variable_validation_error.rb +14 -12
- data/lib/graphql/schema.rb +87 -77
- data/lib/graphql/schema/each_item_validator.rb +16 -12
- data/lib/graphql/schema/field_validator.rb +14 -10
- data/lib/graphql/schema/implementation_validator.rb +26 -22
- data/lib/graphql/schema/middleware_chain.rb +2 -1
- data/lib/graphql/schema/possible_types.rb +34 -0
- data/lib/graphql/schema/printer.rb +122 -120
- data/lib/graphql/schema/type_expression.rb +1 -0
- data/lib/graphql/schema/type_map.rb +3 -10
- data/lib/graphql/schema/type_reducer.rb +65 -81
- data/lib/graphql/schema/type_validator.rb +45 -41
- data/lib/graphql/static_validation.rb +7 -9
- data/lib/graphql/static_validation/all_rules.rb +29 -24
- data/lib/graphql/static_validation/arguments_validator.rb +39 -35
- data/lib/graphql/static_validation/literal_validator.rb +44 -40
- data/lib/graphql/static_validation/message.rb +30 -26
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +15 -11
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +14 -10
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +16 -12
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +59 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +25 -21
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +28 -24
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +84 -80
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +49 -43
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +22 -17
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +19 -15
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +25 -20
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +36 -23
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +29 -25
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +21 -17
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +79 -70
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +24 -20
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +122 -119
- data/lib/graphql/static_validation/type_stack.rb +138 -129
- data/lib/graphql/static_validation/validator.rb +29 -25
- data/lib/graphql/type_kinds.rb +42 -40
- data/lib/graphql/union_type.rb +22 -16
- data/lib/graphql/version.rb +1 -1
- data/readme.md +12 -27
- data/spec/graphql/base_type_spec.rb +3 -3
- data/spec/graphql/directive_spec.rb +10 -18
- data/spec/graphql/enum_type_spec.rb +7 -7
- data/spec/graphql/execution_error_spec.rb +1 -1
- data/spec/graphql/field_spec.rb +14 -13
- data/spec/graphql/id_type_spec.rb +6 -6
- data/spec/graphql/input_object_type_spec.rb +39 -39
- data/spec/graphql/interface_type_spec.rb +16 -32
- data/spec/graphql/introspection/directive_type_spec.rb +5 -9
- data/spec/graphql/introspection/input_value_type_spec.rb +10 -4
- data/spec/graphql/introspection/introspection_query_spec.rb +2 -2
- data/spec/graphql/introspection/schema_type_spec.rb +2 -2
- data/spec/graphql/introspection/type_type_spec.rb +34 -6
- data/spec/graphql/language/parser_spec.rb +299 -105
- data/spec/graphql/language/visitor_spec.rb +4 -4
- data/spec/graphql/list_type_spec.rb +11 -11
- data/spec/graphql/object_type_spec.rb +10 -10
- data/spec/graphql/query/arguments_spec.rb +7 -7
- data/spec/graphql/query/context_spec.rb +11 -3
- data/spec/graphql/query/executor_spec.rb +26 -19
- data/spec/graphql/query/serial_execution/execution_context_spec.rb +6 -6
- data/spec/graphql/query/serial_execution/value_resolution_spec.rb +2 -2
- data/spec/graphql/query/type_resolver_spec.rb +3 -3
- data/spec/graphql/query_spec.rb +6 -38
- data/spec/graphql/scalar_type_spec.rb +28 -19
- data/spec/graphql/schema/field_validator_spec.rb +1 -1
- data/spec/graphql/schema/middleware_chain_spec.rb +12 -1
- data/spec/graphql/schema/printer_spec.rb +12 -4
- data/spec/graphql/schema/rescue_middleware_spec.rb +1 -1
- data/spec/graphql/schema/type_expression_spec.rb +2 -2
- data/spec/graphql/schema/type_reducer_spec.rb +21 -36
- data/spec/graphql/schema/type_validator_spec.rb +9 -9
- data/spec/graphql/schema_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +5 -5
- data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +39 -0
- data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +5 -5
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +5 -5
- data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +3 -1
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +3 -3
- data/spec/graphql/static_validation/type_stack_spec.rb +3 -2
- data/spec/graphql/static_validation/validator_spec.rb +26 -6
- data/spec/graphql/union_type_spec.rb +5 -4
- data/spec/spec_helper.rb +2 -5
- data/spec/support/dairy_app.rb +30 -9
- data/spec/support/dairy_data.rb +1 -1
- data/spec/support/star_wars_data.rb +26 -26
- data/spec/support/star_wars_schema.rb +1 -1
- metadata +40 -21
- data/lib/graphql/language/transform.rb +0 -113
- data/lib/graphql/query/directive_chain.rb +0 -44
- data/lib/graphql/repl.rb +0 -27
- data/spec/graphql/language/transform_spec.rb +0 -156
@@ -1,138 +1,332 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe GraphQL::Language::Parser do
|
4
|
-
let(:
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
mutation changeStuff(
|
13
|
-
$override: Boolean = true,
|
14
|
-
$cucumbers: [Vegetable]!,
|
15
|
-
$input: SomeInputType = {key: "value"},
|
16
|
-
) @veggie, @healthy(vitamins: true) {
|
17
|
-
# change the cucumber
|
18
|
-
changeStuff(
|
19
|
-
thing: $cucumbers
|
20
|
-
) {
|
21
|
-
id,
|
22
|
-
name,
|
23
|
-
... on Species { color },
|
24
|
-
... family # background info, of course
|
4
|
+
let(:document) { GraphQL::Language::Parser.parse(query_string) }
|
5
|
+
let(:query_string) {%|
|
6
|
+
query getStuff($someVar: Int = 1, $anotherVar: [String!] ) @skip(if: false) {
|
7
|
+
myField: someField(someArg: $someVar, ok: 1.4) @skip(if: $anotherVar) @thing(or: "Whatever")
|
8
|
+
|
9
|
+
anotherField(someArg: [1,2,3]) {
|
10
|
+
nestedField
|
11
|
+
... moreNestedFields @skip(if: true)
|
25
12
|
}
|
26
|
-
}
|
27
|
-
subscription watchStuff {
|
28
|
-
field(emptyObj: {}), otherField
|
29
|
-
}
|
30
13
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
14
|
+
... on OtherType @include(unless: false){
|
15
|
+
field(arg: [{key: "value", anotherKey: 0.9, anotherAnotherKey: WHATEVER}])
|
16
|
+
anotherField
|
17
|
+
}
|
18
|
+
|
19
|
+
... {
|
20
|
+
id
|
36
21
|
}
|
37
22
|
}
|
38
23
|
|
39
|
-
fragment
|
40
|
-
|
24
|
+
fragment moreNestedFields on NestedType @or(something: "ok") {
|
25
|
+
anotherNestedField
|
26
|
+
}
|
27
|
+
|}
|
41
28
|
|
42
|
-
|
43
|
-
|
29
|
+
describe ".parse" do
|
30
|
+
let(:_query_string) { '
|
31
|
+
query getStuff($fragment: Int!, $false: String = "h\"😸i") @skip(ok: 1) {
|
32
|
+
myField(
|
33
|
+
arg1: 4.5,
|
34
|
+
arg2: -3,
|
35
|
+
arg3: "hello ☀︎ \uD83C\uDF40",
|
36
|
+
arg4: 4.5e-12,
|
37
|
+
arg5: true
|
38
|
+
arg6: $false
|
39
|
+
arg7: [true, false],
|
40
|
+
arg8: {key: "val", ok: true, whatever: $fragment}
|
41
|
+
arg9: ENUM_VALUE
|
42
|
+
) {
|
43
|
+
aliasName: childField @skip(on: true)
|
44
|
+
... description
|
45
|
+
},
|
46
|
+
# Comment!
|
47
|
+
#
|
48
|
+
otherField
|
49
|
+
}
|
44
50
|
|
51
|
+
fragment thingStuff on Thing {
|
52
|
+
whatever
|
53
|
+
}
|
54
|
+
'}
|
45
55
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
assert(parser.operation_definition.parse_with_debug(%|subscription personStuff @flagDirective {id, name, ...people}|), "with a directive")
|
50
|
-
assert(parser.operation_definition.parse_with_debug(%|mutation changeStuff($stuff: Int = 1 $things: [SomeType]! = [{something: 1}, {something: 2}], $another: Sometype = {something: 3}) { id }|), "mutation with arguments")
|
51
|
-
assert(parser.operation_definition.parse_with_debug(%|mutation { id }|), "unnamed")
|
52
|
-
end
|
56
|
+
it "parses queries" do
|
57
|
+
assert document
|
58
|
+
end
|
53
59
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
60
|
+
describe "visited nodes" do
|
61
|
+
let(:query) { document.definitions.first }
|
62
|
+
let(:fragment_def) { document.definitions.last }
|
58
63
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
assert(parser.selections.parse_with_debug(%|{id @skip(if: true), ... myFragment @include(if: $something)}|), 'gets directives')
|
64
|
-
end
|
64
|
+
it "creates a valid document" do
|
65
|
+
assert document.is_a?(GraphQL::Language::Nodes::Document)
|
66
|
+
assert_equal 2, document.definitions.length
|
67
|
+
end
|
65
68
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
69
|
+
it "creates a valid operation" do
|
70
|
+
assert query.is_a?(GraphQL::Language::Nodes::OperationDefinition)
|
71
|
+
assert_equal "getStuff", query.name
|
72
|
+
assert_equal "query", query.operation_type
|
73
|
+
assert_equal 2, query.variables.length
|
74
|
+
assert_equal 4, query.selections.length
|
75
|
+
assert_equal 1, query.directives.length
|
76
|
+
assert_equal [2, 5], [query.line, query.col]
|
77
|
+
end
|
71
78
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
+
it "creates a valid fragment definition" do
|
80
|
+
assert fragment_def.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
|
81
|
+
assert_equal "moreNestedFields", fragment_def.name
|
82
|
+
assert_equal 1, fragment_def.selections.length
|
83
|
+
assert_equal "NestedType", fragment_def.type
|
84
|
+
assert_equal 1, fragment_def.directives.length
|
85
|
+
assert_equal [20, 5], fragment_def.position
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "variable definitions" do
|
89
|
+
let(:optional_var) { query.variables.first }
|
90
|
+
it "gets name and type" do
|
91
|
+
assert_equal "someVar", optional_var.name
|
92
|
+
assert_equal "Int", optional_var.type.name
|
93
|
+
end
|
94
|
+
|
95
|
+
it "gets default value" do
|
96
|
+
assert_equal 1, optional_var.default_value
|
97
|
+
end
|
98
|
+
|
99
|
+
it "gets position info" do
|
100
|
+
assert_equal [2, 20], optional_var.position
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "fields" do
|
105
|
+
let(:leaf_field) { query.selections.first }
|
106
|
+
let(:parent_field) { query.selections[1] }
|
107
|
+
|
108
|
+
it "gets name, alias, arguments and directives" do
|
109
|
+
assert_equal "someField", leaf_field.name
|
110
|
+
assert_equal "myField", leaf_field.alias
|
111
|
+
assert_equal 2, leaf_field.directives.length
|
112
|
+
assert_equal 2, leaf_field.arguments.length
|
113
|
+
end
|
114
|
+
|
115
|
+
it "gets nested fields" do
|
116
|
+
assert_equal 2, parent_field.selections.length
|
117
|
+
end
|
118
|
+
|
119
|
+
it "gets location info" do
|
120
|
+
assert_equal [3 ,7], leaf_field.position
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "when the arguments list is empty" do
|
124
|
+
let(:query_string) { "{ field() }"}
|
125
|
+
let(:field) { query.selections.first }
|
126
|
+
it "has zero arguments" do
|
127
|
+
assert_equal 0, field.arguments.length
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "when selections are empty" do
|
132
|
+
let(:query_string) { "{ field { } }"}
|
133
|
+
let(:field) { query.selections.first }
|
134
|
+
it "has zero selections" do
|
135
|
+
assert_equal 0, field.selections.length
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "arguments" do
|
141
|
+
let(:literal_argument) { query.selections.first.arguments.last }
|
142
|
+
let(:variable_argument) { query.selections.first.arguments.first }
|
143
|
+
|
144
|
+
it "gets name and literal value" do
|
145
|
+
assert_equal "ok", literal_argument.name
|
146
|
+
assert_equal 1.4, literal_argument.value
|
147
|
+
end
|
148
|
+
|
149
|
+
it "gets name and variable value" do
|
150
|
+
assert_equal "someArg", variable_argument.name
|
151
|
+
assert_equal "someVar", variable_argument.value.name
|
152
|
+
end
|
79
153
|
|
80
|
-
it 'parses variable definitions' do
|
81
|
-
assert(parser.operation_variable_definition.parse_with_debug("$myVar: Boolean = true"), "it gets variables with defaults")
|
82
|
-
assert(parser.operation_variable_definition.parse_with_debug("$myVar: [Int]"), "it gets list variables")
|
83
|
-
assert(parser.operation_variable_definition.parse_with_debug("$myVar: Elephant!"), "it gets non-null variables")
|
84
|
-
assert(parser.operation_variable_definition.parse_with_debug("$myVar: [Food]!"), "it gets non-null list variables")
|
85
|
-
assert(parser.operation_variable_definitions.parse_with_debug(%|($myVar: Elephant!, $myList: [Float], $myString: String = "Cheese")|), "it gets a list of defns")
|
86
|
-
end
|
87
154
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
155
|
+
it "gets position info" do
|
156
|
+
assert_equal [3, 26], variable_argument.position
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "fragment spreads" do
|
161
|
+
let(:fragment_spread) { query.selections[1].selections.last }
|
162
|
+
it "gets the name and directives" do
|
163
|
+
assert_equal "moreNestedFields", fragment_spread.name
|
164
|
+
assert_equal 1, fragment_spread.directives.length
|
165
|
+
end
|
166
|
+
|
167
|
+
it "gets position info" do
|
168
|
+
assert_equal [7, 9], fragment_spread.position
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "directives" do
|
173
|
+
let(:variable_directive) { query.selections.first.directives.first }
|
174
|
+
|
175
|
+
it "gets the name and arguments" do
|
176
|
+
assert_equal "skip", variable_directive.name
|
177
|
+
assert_equal "if", variable_directive.arguments.first.name
|
178
|
+
assert_equal 1, variable_directive.arguments.length
|
179
|
+
end
|
180
|
+
|
181
|
+
it "gets position info" do
|
182
|
+
assert_equal [3, 54], variable_directive.position
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "inline fragments" do
|
187
|
+
let(:inline_fragment) { query.selections[2] }
|
188
|
+
let(:typeless_inline_fragment) { query.selections[3] }
|
189
|
+
|
190
|
+
it "gets the type and directives" do
|
191
|
+
assert_equal "OtherType", inline_fragment.type
|
192
|
+
assert_equal 2, inline_fragment.selections.length
|
193
|
+
assert_equal 1, inline_fragment.directives.length
|
194
|
+
end
|
195
|
+
|
196
|
+
it "gets inline fragments without type conditions" do
|
197
|
+
assert_equal nil, typeless_inline_fragment.type
|
198
|
+
assert_equal 1, typeless_inline_fragment.selections.length
|
199
|
+
assert_equal 0, typeless_inline_fragment.directives.length
|
200
|
+
end
|
201
|
+
|
202
|
+
it "gets position info" do
|
203
|
+
assert_equal [10, 7], inline_fragment.position
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe "inputs" do
|
208
|
+
let(:query_string) {%|
|
209
|
+
{
|
210
|
+
field(
|
211
|
+
int: 3,
|
212
|
+
float: 4.7e-24,
|
213
|
+
bool: false,
|
214
|
+
string: "☀︎🏆\\n escaped \\" unicode \\u00b6 /",
|
215
|
+
enum: ENUM_NAME,
|
216
|
+
array: [7, 8, 9]
|
217
|
+
object: {a: [1,2,3], b: {c: "4"}}
|
218
|
+
)
|
219
|
+
}
|
220
|
+
|}
|
221
|
+
|
222
|
+
let(:inputs) { document.definitions.first.selections.first.arguments }
|
223
|
+
|
224
|
+
it "parses ints" do
|
225
|
+
assert_equal 3, inputs[0].value
|
226
|
+
end
|
227
|
+
|
228
|
+
it "parses floats" do
|
229
|
+
assert_equal 0.47e-23, inputs[1].value
|
230
|
+
end
|
231
|
+
|
232
|
+
it "parses booleans" do
|
233
|
+
assert_equal false, inputs[2].value
|
234
|
+
end
|
235
|
+
|
236
|
+
it "parses UTF-8 strings" do
|
237
|
+
assert_equal %|☀︎🏆\n escaped " unicode ¶ /|, inputs[3].value
|
238
|
+
end
|
239
|
+
|
240
|
+
it "parses enums" do
|
241
|
+
assert_instance_of GraphQL::Language::Nodes::Enum, inputs[4].value
|
242
|
+
assert_equal "ENUM_NAME", inputs[4].value.name
|
243
|
+
end
|
244
|
+
|
245
|
+
it "parses arrays" do
|
246
|
+
assert_equal [7,8,9], inputs[5].value
|
247
|
+
end
|
248
|
+
|
249
|
+
it "parses objects" do
|
250
|
+
obj = inputs[6].value
|
251
|
+
assert_equal "a", obj.arguments[0].name
|
252
|
+
assert_equal [1,2,3], obj.arguments[0].value
|
253
|
+
assert_equal "b", obj.arguments[1].name
|
254
|
+
assert_equal "c", obj.arguments[1].value.arguments[0].name
|
255
|
+
assert_equal "4", obj.arguments[1].value.arguments[0].value
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
describe "unnamed queries" do
|
261
|
+
let(:query_string) {%|
|
262
|
+
{ name, age, height }
|
263
|
+
|}
|
264
|
+
let(:operation) { document.definitions.first }
|
265
|
+
|
266
|
+
it "parses unnamed queries" do
|
267
|
+
assert_equal 1, document.definitions.length
|
268
|
+
assert_equal "query", operation.operation_type
|
269
|
+
assert_equal nil, operation.name
|
270
|
+
assert_equal 3, operation.selections.length
|
271
|
+
end
|
93
272
|
end
|
94
273
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
274
|
+
describe "introspection query" do
|
275
|
+
let(:query_string) { GraphQL::Introspection::INTROSPECTION_QUERY }
|
276
|
+
|
277
|
+
it "parses a big ol' query" do
|
278
|
+
assert(document)
|
279
|
+
end
|
101
280
|
end
|
281
|
+
end
|
102
282
|
|
103
|
-
|
104
|
-
|
105
|
-
|
283
|
+
describe "errors" do
|
284
|
+
let(:query_string) {%| query doSomething { bogus { } |}
|
285
|
+
it "raises a parse error" do
|
286
|
+
err = assert_raises(GraphQL::ParseError) { document }
|
106
287
|
end
|
107
288
|
|
108
|
-
it
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
289
|
+
it "correctly identifies parse error location and content" do
|
290
|
+
e = assert_raises(GraphQL::ParseError) do
|
291
|
+
GraphQL.parse("
|
292
|
+
query getCoupons {
|
293
|
+
allCoupons: {data{id}}
|
294
|
+
}
|
295
|
+
")
|
296
|
+
end
|
297
|
+
assert_includes(e.message, '"{"')
|
298
|
+
assert_includes(e.message, "RCURLY")
|
299
|
+
assert_equal(3, e.line)
|
300
|
+
assert_equal(25, e.col)
|
113
301
|
end
|
114
302
|
|
115
|
-
it
|
116
|
-
|
117
|
-
|
118
|
-
assert(parser.value.parse_with_debug('[]'), 'empty array')
|
119
|
-
assert(parser.value.parse_with_debug('[[true, 1], ["my string", -5.123e56]]'), 'array of arrays')
|
303
|
+
it "handles unexpected ends" do
|
304
|
+
err = assert_raises { GraphQL.parse("{ ") }
|
305
|
+
assert_equal "Unexpected end of document", err.message
|
120
306
|
end
|
307
|
+
end
|
308
|
+
|
121
309
|
|
122
|
-
|
123
|
-
|
310
|
+
describe "whitespace" do
|
311
|
+
describe "whitespace-only queries" do
|
312
|
+
let(:query_string) { " " }
|
313
|
+
it "doesn't blow up" do
|
314
|
+
assert_equal [], document.definitions
|
315
|
+
end
|
124
316
|
end
|
125
317
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
assert(parser.value.parse_with_debug('{ }'), 'gets empty')
|
318
|
+
describe "empty string queries" do
|
319
|
+
let(:query_string) { "" }
|
320
|
+
it "doesn't blow up" do
|
321
|
+
assert_equal [], document.definitions
|
322
|
+
end
|
132
323
|
end
|
133
324
|
|
134
|
-
|
135
|
-
|
325
|
+
describe "using tabs as whitespace" do
|
326
|
+
let(:query_string) { "\t{\t\tid, \tname}"}
|
327
|
+
it "parses the query" do
|
328
|
+
assert_equal 1, document.definitions.length
|
329
|
+
end
|
136
330
|
end
|
137
331
|
end
|
138
332
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe GraphQL::Language::Visitor do
|
4
4
|
let(:document) { GraphQL.parse("
|
@@ -19,7 +19,7 @@ describe GraphQL::Language::Visitor do
|
|
19
19
|
v
|
20
20
|
end
|
21
21
|
|
22
|
-
it
|
22
|
+
it "calls hooks during a depth-first tree traversal" do
|
23
23
|
assert_equal(2, visitor[GraphQL::Language::Nodes::Argument].enter.length)
|
24
24
|
visitor.visit(document)
|
25
25
|
assert_equal(6, counts[:fields_entered])
|
@@ -29,8 +29,8 @@ describe GraphQL::Language::Visitor do
|
|
29
29
|
assert(counts[:finished])
|
30
30
|
end
|
31
31
|
|
32
|
-
describe
|
33
|
-
it
|
32
|
+
describe "Visitor::SKIP" do
|
33
|
+
it "skips the rest of the node" do
|
34
34
|
visitor[GraphQL::Language::Nodes::Document] << -> (node, parent) { GraphQL::Language::Visitor::SKIP }
|
35
35
|
visitor.visit(document)
|
36
36
|
assert_equal(0, counts[:fields_entered])
|