/
parser_spec.rb
240 lines (201 loc) · 7.09 KB
/
parser_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# frozen_string_literal: true
require "spec_helper"
describe GraphQL::Language::Parser do
subject { GraphQL::Language::Parser }
describe "when there are no selections" do
it 'raises a ParseError' do
assert_raises(GraphQL::ParseError) {
GraphQL.parse('# comment')
}
end
end
it "raises an error when unicode is used as names" do
err = assert_raises(GraphQL::ParseError) {
GraphQL.parse('query 😘 { a b }')
}
assert_equal "Parse error on \"\\xF0\" (error) at [1, 7]", err.message
end
describe "anonymous fragment extension" do
let(:document) { GraphQL.parse(query_string) }
let(:query_string) {%|
fragment on NestedType @or(something: "ok") {
anotherNestedField
}
|}
let(:fragment) { document.definitions.first }
it "creates an anonymous fragment definition" do
assert fragment.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
assert_nil fragment.name
assert_equal 1, fragment.selections.length
assert_equal "NestedType", fragment.type.name
assert_equal 1, fragment.directives.length
assert_equal [2, 7], fragment.position
end
end
describe "string description" do
it "is parsed for scalar definitions" do
document = subject.parse <<-GRAPHQL
"Thing description"
scalar Thing
GRAPHQL
thing_defn = document.definitions[0]
assert_equal "Thing", thing_defn.name
assert_equal "Thing description", thing_defn.description
end
it "is parsed for object definitions, field definitions, and input value definitions" do
document = subject.parse <<-GRAPHQL
"Thing description"
type Thing {
"field description"
field("arg description" arg: Stuff): Stuff
}
GRAPHQL
thing_defn = document.definitions[0]
assert_equal "Thing", thing_defn.name
assert_equal "Thing description", thing_defn.description
field_defn = thing_defn.fields[0]
assert_equal "field", field_defn.name
assert_equal "field description", field_defn.description
arg_defn = field_defn.arguments[0]
assert_equal "arg", arg_defn.name
assert_equal "arg description", arg_defn.description
end
it "is parsed for interface definitions" do
document = subject.parse <<-GRAPHQL
"Thing description"
interface Thing {}
GRAPHQL
thing_defn = document.definitions[0]
assert_equal "Thing", thing_defn.name
assert_equal "Thing description", thing_defn.description
end
it "is parsed for union definitions" do
document = subject.parse <<-GRAPHQL
"Thing description"
union Thing = Int | String
GRAPHQL
thing_defn = document.definitions[0]
assert_equal "Thing", thing_defn.name
assert_equal "Thing description", thing_defn.description
end
it "is parsed for enum definitions and enum value definitions" do
document = subject.parse <<-GRAPHQL
"Thing description"
enum Thing {
"VALUE description"
VALUE
}
GRAPHQL
thing_defn = document.definitions[0]
assert_equal "Thing", thing_defn.name
assert_equal "Thing description", thing_defn.description
value_defn = thing_defn.values[0]
assert_equal "VALUE", value_defn.name
assert_equal "VALUE description", value_defn.description
end
it "is parsed for directive definitions" do
document = subject.parse <<-GRAPHQL
"thing description" directive @thing repeatable on FIELD
GRAPHQL
thing_defn = document.definitions[0]
assert_equal "thing", thing_defn.name
assert_equal true, thing_defn.repeatable
assert_equal "thing description", thing_defn.description
end
end
it "parses query without arguments" do
strings = [
"{ field { inner } }"
]
strings.each do |query_str|
doc = subject.parse(query_str)
field = doc.definitions.first.selections.first
assert_equal 0, field.arguments.length
assert_equal 1, field.selections.length
end
end
it "parses backslashes in arguments" do
document = subject.parse <<-GRAPHQL
query {
item(text: "a", otherText: "b\\\\") {
text
otherText
}
}
GRAPHQL
assert_equal "b\\", document.definitions[0].selections[0].arguments[1].value
end
it "parses backslases in non-last arguments" do
document = subject.parse <<-GRAPHQL
query {
item(text: "b\\\\", otherText: "a") {
text
otherText
}
}
GRAPHQL
assert_equal "b\\", document.definitions[0].selections[0].arguments[0].value
end
it "parses the test schema" do
schema = Dummy::Schema
schema_string = GraphQL::Schema::Printer.print_schema(schema)
document = subject.parse(schema_string)
assert_equal schema_string.chomp, document.to_query_string
end
describe "parse errors" do
it "raises parse errors for nil" do
assert_raises(GraphQL::ParseError) {
GraphQL.parse(nil)
}
end
it 'raises parse errors for empty argument sets' do
# Regression spec from https://github.com/rmosolgo/graphql-ruby/pull/2344
query_with_empty_arguments = '{ node() { id } }'
assert_raises(GraphQL::ParseError) {
subject.parse(query_with_empty_arguments)
}
end
it 'raises parse errors for argument sets without value' do
# Regression spec from https://github.com/rmosolgo/graphql-ruby/pull/2344
query_with_malformed_argument_value = '{ node(id:) { name } }'
assert_raises(GraphQL::ParseError) {
subject.parse(query_with_malformed_argument_value)
}
end
end
describe ".parse_file" do
it "assigns filename to all nodes" do
example_filename = "spec/support/parser/filename_example.graphql"
doc = GraphQL.parse_file(example_filename)
assert_equal example_filename, doc.filename
field = doc.definitions[0].selections[0].selections[0]
assert_equal example_filename, field.filename
end
it "raises errors with filename" do
error_filename = "spec/support/parser/filename_example_error_1.graphql"
err = assert_raises(GraphQL::ParseError) {
GraphQL.parse_file(error_filename)
}
assert_includes err.message, error_filename
error_filename_2 = "spec/support/parser/filename_example_error_2.graphql"
err_2 = assert_raises(GraphQL::ParseError) {
GraphQL.parse_file(error_filename_2)
}
assert_includes err_2.message, error_filename_2
assert_includes err_2.message, "3, 11"
end
end
it "serves traces" do
TestTracing.clear
GraphQL.parse("{ t: __typename }", tracer: TestTracing)
traces = TestTracing.traces
assert_equal 2, traces.length
lex_trace, parse_trace = traces
assert_equal "{ t: __typename }", lex_trace[:query_string]
assert_equal "lex", lex_trace[:key]
assert_instance_of Array, lex_trace[:result]
assert_equal "{ t: __typename }", parse_trace[:query_string]
assert_equal "parse", parse_trace[:key]
assert_instance_of GraphQL::Language::Nodes::Document, parse_trace[:result]
end
end