···
1
+
// See: https://github.com/graphql/graphql-js/blob/976d64b/src/language/__tests__/parser-test.ts
2
+
// Note: Tests regarding reserved keywords have been removed.
4
+
import { Kind } from 'graphql';
5
+
import { parse, parseValue, parseType } from '../parser';
7
+
describe('Parser', () => {
8
+
it('parse provides errors', () => {
9
+
expect(() => parse('{')).toThrow();
12
+
it('parses variable inline values', () => {
14
+
return parse('{ field(complex: { a: { b: [ $var ] } }) }');
18
+
it('parses constant default values', () => {
20
+
return parse('query Foo($x: Complex = { a: { b: [ $var ] } }) { field }');
24
+
it('parses variable definition directives', () => {
26
+
return parse('query Foo($x: Boolean = false @bar) { field }');
30
+
it('does not accept fragments spread of "on"', () => {
32
+
return parse('{ ...on }');
36
+
it('parses multi-byte characters', () => {
37
+
// Note: \u0A0A could be naively interpreted as two line-feed chars.
39
+
# This comment has a \u0A0A multi-byte character.
40
+
{ field(arg: "Has a \u0A0A multi-byte character.") }
43
+
expect(ast).toHaveProperty(
44
+
'definitions.0.selectionSet.selections.0.arguments.0.value.value',
45
+
'Has a \u0A0A multi-byte character.'
49
+
it('parses kitchen sink', () => {
50
+
expect(() => parse(kitchenSinkQuery)).not.toThrow();
53
+
it('parses anonymous mutation operations', () => {
63
+
it('parses anonymous subscription operations', () => {
73
+
it('parses named mutation operations', () => {
83
+
it('parses named subscription operations', () => {
93
+
it('creates ast', () => {
94
+
const result = parse(`
103
+
expect(result).toMatchObject({
104
+
kind: Kind.DOCUMENT,
107
+
kind: Kind.OPERATION_DEFINITION,
108
+
operation: 'query',
110
+
variableDefinitions: [],
113
+
kind: Kind.SELECTION_SET,
124
+
kind: Kind.ARGUMENT,
137
+
kind: Kind.SELECTION_SET,
148
+
selectionSet: undefined,
159
+
selectionSet: undefined,
171
+
it('creates ast from nameless query without variables', () => {
172
+
const result = parse(`
180
+
expect(result).toMatchObject({
181
+
kind: Kind.DOCUMENT,
184
+
kind: Kind.OPERATION_DEFINITION,
185
+
operation: 'query',
187
+
variableDefinitions: [],
190
+
kind: Kind.SELECTION_SET,
202
+
kind: Kind.SELECTION_SET,
213
+
selectionSet: undefined,
225
+
it('allows parsing without source location information', () => {
226
+
const result = parse('{ id }', { noLocation: true });
227
+
expect('loc' in result).toBe(false);
230
+
describe('parseValue', () => {
231
+
it('parses null value', () => {
232
+
const result = parseValue('null');
233
+
expect(result).toEqual({ kind: Kind.NULL });
236
+
it('parses list values', () => {
237
+
const result = parseValue('[123 "abc"]');
238
+
expect(result).toEqual({
253
+
it('parses block strings', () => {
254
+
const result = parseValue('["""long""" "short"]');
255
+
expect(result).toEqual({
270
+
it('allows variables', () => {
271
+
const result = parseValue('{ field: $var }');
272
+
expect(result).toEqual({
276
+
kind: Kind.OBJECT_FIELD,
282
+
kind: Kind.VARIABLE,
293
+
it('correct message for incomplete variable', () => {
295
+
return parseValue('$');
299
+
it('correct message for unexpected token', () => {
301
+
return parseValue(':');
306
+
describe('parseType', () => {
307
+
it('parses well known types', () => {
308
+
const result = parseType('String');
309
+
expect(result).toEqual({
310
+
kind: Kind.NAMED_TYPE,
318
+
it('parses custom types', () => {
319
+
const result = parseType('MyType');
320
+
expect(result).toEqual({
321
+
kind: Kind.NAMED_TYPE,
329
+
it('parses list types', () => {
330
+
const result = parseType('[MyType]');
331
+
expect(result).toEqual({
332
+
kind: Kind.LIST_TYPE,
334
+
kind: Kind.NAMED_TYPE,
343
+
it('parses non-null types', () => {
344
+
const result = parseType('MyType!');
345
+
expect(result).toEqual({
346
+
kind: Kind.NON_NULL_TYPE,
348
+
kind: Kind.NAMED_TYPE,
357
+
it('parses nested types', () => {
358
+
const result = parseType('[MyType!]');
359
+
expect(result).toEqual({
360
+
kind: Kind.LIST_TYPE,
362
+
kind: Kind.NON_NULL_TYPE,
364
+
kind: Kind.NAMED_TYPE,
376
+
const kitchenSinkQuery: string = String.raw`
377
+
query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery {
378
+
whoever123is: node(id: [123, 456]) {
380
+
... on User @onInlineFragment {
383
+
alias: field1(first: 10, after: $foo) @include(if: $foo) {
385
+
...frag @onFragmentSpread
389
+
... @skip(unless: $foo) {
397
+
mutation likeStory @onMutation {
398
+
like(story: 123) @onField {
404
+
subscription StoryLikeSubscription(
405
+
$input: StoryLikeSubscribeInput @onVariableDefinition
408
+
storyLikeSubscribe(input: $input) {
419
+
fragment frag on Friend @onFragmentDefinition {
426
+
block string uses \"""
432
+
unnamed(truthy: true, falsy: false, nullish: null)