graphql-language-service
Version:
The official, runtime independent Language Service for GraphQL
1,376 lines (1,100 loc) • 38.3 kB
text/typescript
/* eslint-disable jest/expect-expect */
import OnlineParser from '../onlineParser';
import {
getUtils,
performForEachType,
expectVarsDef,
expectArgs,
expectDirective,
} from './OnlineParserUtils';
describe('onlineParser', () => {
describe('.startState', () => {
it('initializes state correctly', () => {
const parser = OnlineParser();
expect(parser.startState()).toEqual({
level: 0,
step: 0,
name: null,
kind: 'Document',
type: null,
rule: [
{
isList: true,
ofRule: 'Definition',
separator: undefined,
},
],
needsSeparator: false,
prevState: {
level: 0,
step: 0,
name: null,
kind: null,
type: null,
rule: null,
needsSeparator: false,
prevState: null,
},
});
});
});
describe('.token', () => {
it('detects invalid char', () => {
const { token } = getUtils('^');
expect(token()).toEqual('invalidchar');
});
it('parses schema def', () => {
const { t } = getUtils(`
schema {
query: SomeType
}
`);
t.keyword('schema', { kind: 'SchemaDef' });
t.punctuation('{');
t.keyword('query', { kind: 'OperationTypeDef' });
t.punctuation(':');
t.name('SomeType');
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses short query', () => {
const { t } = getUtils(`
{
someField
}
`);
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someField', { kind: 'Field' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses query', () => {
const { t } = getUtils(`
query SomeQuery {
someField
}
`);
t.keyword('query', { kind: 'Query' });
t.def('SomeQuery');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someField', { kind: 'Field' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses query with variables', () => {
const { t, stream } = getUtils(`
query SomeQuery ($someVariable: SomeInputType) {
someField(someArg: $someVariable)
}
`);
t.keyword('query', { kind: 'Query' });
t.def('SomeQuery');
expectVarsDef(
{ t, stream },
{
onKind: 'Query',
vars: [{ name: 'someVariable', type: 'SomeInputType' }],
},
);
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someField', { kind: 'Field' });
expectArgs(
{ t, stream },
{
onKind: 'Field',
args: [{ name: 'someArg', isVariable: true, value: 'someVariable' }],
},
);
t.punctuation('}', { kind: 'Document' });
t.eol();
});
performForEachType(
`
query SomeQuery {
someField(someArg: __VALUE__)
}
`,
({ t, stream }, fill) => {
it(`parses query field having argument of type ${fill.type}`, () => {
t.keyword('query', { kind: 'Query' });
t.def('SomeQuery');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someField', { kind: 'Field' });
expectArgs(
{ t, stream },
{ onKind: 'Field', args: [{ name: 'someArg', ...fill }] },
);
t.punctuation('}', { kind: 'Document' });
t.eol();
});
},
);
performForEachType(
`
query SomeQuery {
someField(someArg: [__VALUE__])
}
`,
({ t, stream }, fill) => {
it(`parses query field having argument as list of type ${fill.type}`, () => {
t.keyword('query', { kind: 'Query' });
t.def('SomeQuery');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someField', { kind: 'Field' });
expectArgs(
{ t, stream },
{
onKind: 'Field',
args: [{ name: 'someArg', isList: true, ...fill }],
},
);
t.punctuation('}', { kind: 'Document' });
t.eol();
});
},
);
it('parses query field having argument of type object', () => {
const { t } = getUtils(`
query SomeQuery {
someField(someArg: { anotherField: $someVariable })
}
`);
t.keyword('query', { kind: 'Query' });
t.def('SomeQuery');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someField', { kind: 'Field' });
t.punctuation(/\(/, { kind: 'Arguments' });
t.attribute('someArg', { kind: 'Argument' });
t.punctuation(':');
t.punctuation('{', { kind: 'ObjectValue' });
t.attribute('anotherField', { kind: 'ObjectField' });
t.punctuation(':');
t.variable('$', { kind: 'Variable' });
t.variable('someVariable');
t.punctuation('}', { kind: 'Arguments' });
t.punctuation(/\)/, { kind: 'Field' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
performForEachType(
`
query SomeQuery {
someField @someDirective(anotherArg: __VALUE__)
}
`,
({ t, stream }, fill) => {
it(`parses query field with directive having argument of type ${fill.type}`, () => {
t.keyword('query', { kind: 'Query' });
t.def('SomeQuery');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someField', { kind: 'Field' });
expectDirective(
{ t, stream },
{
name: 'someDirective',
onKind: 'Field',
args: [{ name: 'anotherArg', ...fill }],
},
);
t.punctuation('}', { kind: 'Document' });
t.eol();
});
},
);
it('parses query field with a directive and selection set', () => {
const { t } = getUtils(`
query SomeQuery {
someField @someDirective {
anotherField
}
}
`);
t.keyword('query', { kind: 'Query' });
t.def('SomeQuery');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someField', { kind: 'Field' });
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('{', { kind: 'SelectionSet' });
t.property('anotherField', { kind: 'Field' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses query field with an alias', () => {
const { t } = getUtils(`
query SomeQuery {
someAlias : someField @someDirective {
anotherField
}
}
`);
t.keyword('query', { kind: 'Query' });
t.def('SomeQuery');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someAlias', { kind: 'AliasedField' });
t.punctuation(':');
t.qualifier('someField');
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('{', { kind: 'SelectionSet' });
t.property('anotherField', { kind: 'Field' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses invalid query', () => {
const { t, token } = getUtils(`
{}garbage
`);
t.punctuation('{', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
expect(token()).toEqual('invalidchar');
t.eol();
});
it('parses a fragment definition', () => {
const { t } = getUtils(`
fragment SomeFragment on SomeType {
someField
}
`);
t.keyword('fragment', { kind: 'FragmentDefinition' });
t.def('SomeFragment');
t.keyword('on', { kind: 'TypeCondition' });
t.name('SomeType', { kind: 'NamedType' });
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someField', { kind: 'Field' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses a fragment definition with a directive', () => {
const { t } = getUtils(`
fragment SomeFragment on SomeType @someDirective {
someField
}
`);
t.keyword('fragment', { kind: 'FragmentDefinition' });
t.def('SomeFragment');
t.keyword('on', { kind: 'TypeCondition' });
t.name('SomeType', { kind: 'NamedType' });
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someField', { kind: 'Field' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses query with inline fragment', () => {
const { t } = getUtils(`
query SomeQuery {
someField {
... on SomeType {
anotherField
}
}
}
`);
t.keyword('query', { kind: 'Query' });
t.def('SomeQuery');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someField', { kind: 'Field' });
t.punctuation('{', { kind: 'SelectionSet' });
t.punctuation('...', { kind: 'InlineFragment' });
t.keyword('on', { kind: 'TypeCondition' });
t.name('SomeType', { kind: 'NamedType' });
t.punctuation('{', { kind: 'SelectionSet' });
t.property('anotherField', { kind: 'Field' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses query with fragment spread', () => {
const { t } = getUtils(`
query SomeQuery {
someField {
...SomeFragment @someDirective
}
}
`);
t.keyword('query', { kind: 'Query' });
t.def('SomeQuery');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someField', { kind: 'Field' });
t.punctuation('{', { kind: 'SelectionSet' });
t.punctuation('...', { kind: 'FragmentSpread' });
t.def('SomeFragment');
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses mutation', () => {
const { t } = getUtils(`
mutation SomeMutation {
someMutation
}
`);
t.keyword('mutation', { kind: 'Mutation' });
t.def('SomeMutation');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someMutation', { kind: 'Field' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses mutation with variables', () => {
const { t, stream } = getUtils(`
mutation SomeMutation ($someVariable: SomeInputType) {
someMutation(someArg: $someVariable)
}
`);
t.keyword('mutation', { kind: 'Mutation' });
t.def('SomeMutation');
expectVarsDef(
{ t, stream },
{
onKind: 'Mutation',
vars: [{ name: 'someVariable', type: 'SomeInputType' }],
},
);
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someMutation', { kind: 'Field' });
expectArgs(
{ t, stream },
{
onKind: 'Field',
args: [{ name: 'someArg', isVariable: true, value: 'someVariable' }],
},
);
t.punctuation('}', { kind: 'Document' });
t.eol();
});
performForEachType(
`
mutation SomeMutation {
someMutation(someArg: __VALUE__)
}
`,
({ t, stream }, fill) => {
it(`parses mutation field having argument of type ${fill.type}`, () => {
t.keyword('mutation', { kind: 'Mutation' });
t.def('SomeMutation');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someMutation', { kind: 'Field' });
expectArgs(
{ t, stream },
{ onKind: 'Field', args: [{ name: 'someArg', ...fill }] },
);
t.punctuation('}', { kind: 'Document' });
t.eol();
});
},
);
it('parses mutation field having argument of type object', () => {
const { t } = getUtils(`
mutation SomeMutation {
someMutation(someArg: { anotherField: $someVariable })
}
`);
t.keyword('mutation', { kind: 'Mutation' });
t.def('SomeMutation');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someMutation', { kind: 'Field' });
t.punctuation(/\(/, { kind: 'Arguments' });
t.attribute('someArg', { kind: 'Argument' });
t.punctuation(':');
t.punctuation('{', { kind: 'ObjectValue' });
t.attribute('anotherField', { kind: 'ObjectField' });
t.punctuation(':');
t.variable('$', { kind: 'Variable' });
t.variable('someVariable');
t.punctuation('}', { kind: 'Arguments' });
t.punctuation(/\)/, { kind: 'Field' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
performForEachType(
`
mutation SomeMutation {
someMutation @someDirective(anotherArg: __VALUE__)
}
`,
({ t, stream }, fill) => {
it(`parses mutation field with directive having argument of type ${fill.type}`, () => {
t.keyword('mutation', { kind: 'Mutation' });
t.def('SomeMutation');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someMutation', { kind: 'Field' });
expectDirective(
{ t, stream },
{
name: 'someDirective',
onKind: 'Field',
args: [{ name: 'anotherArg', ...fill }],
},
);
t.punctuation('}', { kind: 'Document' });
t.eol();
});
},
);
it('parses mutation field with a directive and selection set', () => {
const { t } = getUtils(`
mutation SomeMutation {
someMutation @someDirective {
anotherField
}
}
`);
t.keyword('mutation', { kind: 'Mutation' });
t.def('SomeMutation');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someMutation', { kind: 'Field' });
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('{', { kind: 'SelectionSet' });
t.property('anotherField', { kind: 'Field' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses mutation field with an alias', () => {
const { t } = getUtils(`
mutation SomeMutation {
someAlias : someMutation @someDirective {
anotherField
}
}
`);
t.keyword('mutation', { kind: 'Mutation' });
t.def('SomeMutation');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someAlias', { kind: 'AliasedField' });
t.punctuation(':');
t.qualifier('someMutation');
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('{', { kind: 'SelectionSet' });
t.property('anotherField', { kind: 'Field' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses mutation with inline fragment', () => {
const { t } = getUtils(`
mutation SomeMutation {
someMutation {
... on SomeType {
anotherField
}
}
}
`);
t.keyword('mutation', { kind: 'Mutation' });
t.def('SomeMutation');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someMutation', { kind: 'Field' });
t.punctuation('{', { kind: 'SelectionSet' });
t.punctuation('...', { kind: 'InlineFragment' });
t.keyword('on', { kind: 'TypeCondition' });
t.name('SomeType', { kind: 'NamedType' });
t.punctuation('{', { kind: 'SelectionSet' });
t.property('anotherField', { kind: 'Field' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses mutation with fragment spread', () => {
const { t } = getUtils(`
mutation SomeMutation {
someMutation {
...SomeFragment @someDirective
}
}
`);
t.keyword('mutation', { kind: 'Mutation' });
t.def('SomeMutation');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someMutation', { kind: 'Field' });
t.punctuation('{', { kind: 'SelectionSet' });
t.punctuation('...', { kind: 'FragmentSpread' });
t.def('SomeFragment');
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses subscription', () => {
const { t } = getUtils(`
subscription SomeSubscription {
someSubscription
}
`);
t.keyword('subscription', { kind: 'Subscription' });
t.def('SomeSubscription');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someSubscription', { kind: 'Field' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses subscription with variables', () => {
const { t, stream } = getUtils(`
subscription SomeSubscription ($someVariable: SomeInputType) {
someSubscription(someArg: $someVariable)
}
`);
t.keyword('subscription', { kind: 'Subscription' });
t.def('SomeSubscription');
expectVarsDef(
{ t, stream },
{
onKind: 'Subscription',
vars: [{ name: 'someVariable', type: 'SomeInputType' }],
},
);
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someSubscription', { kind: 'Field' });
expectArgs(
{ t, stream },
{
onKind: 'Field',
args: [{ name: 'someArg', isVariable: true, value: 'someVariable' }],
},
);
t.punctuation('}', { kind: 'Document' });
t.eol();
});
performForEachType(
`
subscription SomeSubscription {
someSubscription(someArg: __VALUE__)
}
`,
({ t, stream }, fill) => {
it(`parses subscription field having argument of type ${fill.type}`, () => {
t.keyword('subscription', { kind: 'Subscription' });
t.def('SomeSubscription');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someSubscription', { kind: 'Field' });
expectArgs(
{ t, stream },
{ onKind: 'Field', args: [{ name: 'someArg', ...fill }] },
);
t.punctuation('}', { kind: 'Document' });
t.eol();
});
},
);
it('parses subscription field having argument of type object', () => {
const { t } = getUtils(`
subscription SomeSubscription {
someSubscription(someArg: { anotherField: $someVariable })
}
`);
t.keyword('subscription', { kind: 'Subscription' });
t.def('SomeSubscription');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someSubscription', { kind: 'Field' });
t.punctuation(/\(/, { kind: 'Arguments' });
t.attribute('someArg', { kind: 'Argument' });
t.punctuation(':');
t.punctuation('{', { kind: 'ObjectValue' });
t.attribute('anotherField', { kind: 'ObjectField' });
t.punctuation(':');
t.variable('$', { kind: 'Variable' });
t.variable('someVariable');
t.punctuation('}', { kind: 'Arguments' });
t.punctuation(/\)/, { kind: 'Field' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
performForEachType(
`
subscription SomeSubscription {
someSubscription @someDirective(anotherArg: __VALUE__)
}
`,
({ t, stream }, fill) => {
it(`parses subscription field with directive having argument of type ${fill.type}`, () => {
t.keyword('subscription', { kind: 'Subscription' });
t.def('SomeSubscription');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someSubscription', { kind: 'Field' });
expectDirective(
{ t, stream },
{
name: 'someDirective',
onKind: 'Field',
args: [{ name: 'anotherArg', ...fill }],
},
);
t.punctuation('}', { kind: 'Document' });
t.eol();
});
},
);
it('parses subscription field with a directive and selection set', () => {
const { t } = getUtils(`
subscription SomeSubscription {
someSubscription @someDirective {
anotherField
}
}
`);
t.keyword('subscription', { kind: 'Subscription' });
t.def('SomeSubscription');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someSubscription', { kind: 'Field' });
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('{', { kind: 'SelectionSet' });
t.property('anotherField', { kind: 'Field' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses subscription field with an alias', () => {
const { t } = getUtils(`
subscription SomeSubscription {
someAlias : someSubscription @someDirective {
anotherField
}
}
`);
t.keyword('subscription', { kind: 'Subscription' });
t.def('SomeSubscription');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someAlias', { kind: 'AliasedField' });
t.punctuation(':');
t.qualifier('someSubscription');
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('{', { kind: 'SelectionSet' });
t.property('anotherField', { kind: 'Field' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses subscription with inline fragment', () => {
const { t } = getUtils(/* GraphQL */ `
subscription SomeSubscription {
someSubscription {
... on SomeType {
anotherField
}
}
}
`);
t.keyword('subscription', { kind: 'Subscription' });
t.def('SomeSubscription');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someSubscription', { kind: 'Field' });
t.punctuation('{', { kind: 'SelectionSet' });
t.punctuation('...', { kind: 'InlineFragment' });
t.keyword('on', { kind: 'TypeCondition' });
t.name('SomeType', { kind: 'NamedType' });
t.punctuation('{', { kind: 'SelectionSet' });
t.property('anotherField', { kind: 'Field' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('parses subscription with fragment spread', () => {
const { t } = getUtils(/* GraphQL */ `
subscription SomeSubscription {
someSubscription {
...SomeFragment @someDirective
}
}
`);
t.keyword('subscription', { kind: 'Subscription' });
t.def('SomeSubscription');
t.punctuation('{', { kind: 'SelectionSet' });
t.property('someSubscription', { kind: 'Field' });
t.punctuation('{', { kind: 'SelectionSet' });
t.punctuation('...', { kind: 'FragmentSpread' });
t.def('SomeFragment');
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('}', { kind: 'SelectionSet' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
describe('parses object type def', () => {
it('correctly', () => {
const { t } = getUtils(`
type SomeType {
someField: AnotherType!
}
`);
t.keyword('type', { kind: 'ObjectTypeDef' });
t.name('SomeType');
t.punctuation('{');
t.property('someField', { kind: 'FieldDef' });
t.punctuation(':');
t.name('AnotherType', { kind: 'NamedType' });
t.punctuation('!', { kind: 'FieldDef' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('with an object implementing an interface', () => {
const { t } = getUtils('type SomeType implements SomeInterface');
t.keyword('type', { kind: 'ObjectTypeDef' });
t.name('SomeType');
t.keyword('implements', { kind: 'Implements' });
t.name('SomeInterface', { kind: 'NamedType' });
t.eol();
});
it('with an object type implementing multiple interfaces', () => {
const { t } = getUtils(
'type SomeType implements SomeInterface & AnotherInterface & YetAnotherInterface',
);
t.keyword('type', { kind: 'ObjectTypeDef' });
t.name('SomeType');
t.keyword('implements', { kind: 'Implements' });
t.name('SomeInterface', { kind: 'NamedType' });
t.punctuation('&', { kind: 'Implements' });
t.name('AnotherInterface', { kind: 'NamedType' });
t.punctuation('&', { kind: 'Implements' });
t.name('YetAnotherInterface', { kind: 'NamedType' });
t.eol();
});
it('with a directive', () => {
const { t } = getUtils('type SomeType @someDirective');
t.keyword('type', { kind: 'ObjectTypeDef' });
t.name('SomeType');
expectDirective({ t }, { name: 'someDirective' });
t.eol();
});
performForEachType(
'type SomeType @someDirective(someArg: __VALUE__)',
({ t, stream }, fill) => {
it(`with a directive having argument of type ${fill.type}`, () => {
t.keyword('type', { kind: 'ObjectTypeDef' });
t.name('SomeType');
expectDirective(
{ t, stream },
{
name: 'someDirective',
onKind: 'ObjectTypeDef',
args: [{ name: 'someArg', ...fill }],
},
);
t.eol();
});
},
);
});
describe('parses interface def', () => {
it('correctly', () => {
const { t } = getUtils(`
interface SomeInterface {
someField: SomeType!
}
`);
t.keyword('interface', { kind: 'InterfaceDef' });
t.name('SomeInterface');
t.punctuation('{');
t.property('someField', { kind: 'FieldDef' });
t.punctuation(':');
t.name('SomeType', { kind: 'NamedType' });
t.punctuation('!', { kind: 'FieldDef' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('with a directive', () => {
const { t } = getUtils('interface SomeInterface @someDirective');
t.keyword('interface', { kind: 'InterfaceDef' });
t.name('SomeInterface');
expectDirective({ t }, { name: 'someDirective' });
t.eol();
});
it('implementing multiple interfaces', () => {
const { t } = getUtils(
'interface AnInterface implements SomeInterface & AnotherInterface & YetAnotherInterface',
);
t.keyword('interface', { kind: 'InterfaceDef' });
t.name('AnInterface');
t.keyword('implements', { kind: 'Implements' });
t.name('SomeInterface', { kind: 'NamedType' });
t.punctuation('&', { kind: 'Implements' });
t.name('AnotherInterface', { kind: 'NamedType' });
t.punctuation('&', { kind: 'Implements' });
t.name('YetAnotherInterface', { kind: 'NamedType' });
t.eol();
});
performForEachType(
'interface SomeInterface @someDirective(someArg: __VALUE__)',
({ t, stream }, fill) => {
it(`with a directive having argument of type ${fill.type}`, () => {
t.keyword('interface', { kind: 'InterfaceDef' });
t.name('SomeInterface');
expectDirective(
{ t, stream },
{
name: 'someDirective',
onKind: 'InterfaceDef',
args: [{ name: 'someArg', ...fill }],
},
);
t.eol();
});
},
);
});
describe('parses field defs', () => {
it('correctly', () => {
const { t } = getUtils(`
type SomeType {
someField: AnotherType!
}
`);
t.keyword('type', { kind: 'ObjectTypeDef' });
t.name('SomeType');
t.punctuation('{');
t.property('someField', { kind: 'FieldDef' });
t.punctuation(':');
t.name('AnotherType', { kind: 'NamedType' });
t.punctuation('!', { kind: 'FieldDef' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('with an argument', () => {
const { t } = getUtils(`
type SomeType {
someField(someArg: AnotherType): [SomeAnotherType!]!
}
`);
t.keyword('type', { kind: 'ObjectTypeDef' });
t.name('SomeType');
t.punctuation('{');
t.property('someField', { kind: 'FieldDef' });
t.punctuation(/\(/, { kind: 'ArgumentsDef' });
t.attribute('someArg', { kind: 'InputValueDef' });
t.punctuation(':');
t.name('AnotherType', { kind: 'NamedType' });
t.punctuation(/\)/, { kind: 'FieldDef' });
t.punctuation(':');
t.punctuation(/\[/, { kind: 'ListType' });
t.name('SomeAnotherType', { kind: 'NamedType' });
t.punctuation('!', { kind: 'ListType' });
t.punctuation(/\]/);
t.punctuation('!', { kind: 'FieldDef' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('with a directive', () => {
const { t } = getUtils(`
type SomeType {
someField: AnotherType @someDirective
}
`);
t.keyword('type', { kind: 'ObjectTypeDef' });
t.name('SomeType');
t.punctuation('{');
t.property('someField', { kind: 'FieldDef' });
t.punctuation(':');
t.name('AnotherType', { kind: 'NamedType' });
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('with multiple directives', () => {
const { t } = getUtils(`
type SomeType {
someField: AnotherType @someDirective @anotherDirective
}
`);
t.keyword('type', { kind: 'ObjectTypeDef' });
t.name('SomeType');
t.punctuation('{');
t.property('someField', { kind: 'FieldDef' });
t.punctuation(':');
t.name('AnotherType', { kind: 'NamedType' });
expectDirective({ t }, { name: 'someDirective' });
expectDirective({ t }, { name: 'anotherDirective' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
performForEachType(
`
type SomeType {
someField: AnotherType @someDirective(someArg: __VALUE__)
}
`,
({ t, stream }, fill) => {
it(`with a directive having arguments of type ${fill.type}`, () => {
t.keyword('type', { kind: 'ObjectTypeDef' });
t.name('SomeType');
t.punctuation('{');
t.property('someField', { kind: 'FieldDef' });
t.punctuation(':');
t.name('AnotherType', { kind: 'NamedType' });
expectDirective(
{ t, stream },
{
name: 'someDirective',
onKind: 'FieldDef',
args: [{ name: 'someArg', ...fill }],
},
);
t.punctuation('}', { kind: 'Document' });
t.eol();
});
},
);
});
describe('parses extend type def', () => {
it('correctly', () => {
const { t } = getUtils(`
extend type SomeType {
someField: AnotherType
}
`);
t.keyword('extend', { kind: 'ExtendDef' });
t.keyword('type', { kind: 'ObjectTypeDef' });
t.name('SomeType');
t.punctuation('{');
t.property('someField', { kind: 'FieldDef' });
t.punctuation(':');
t.name('AnotherType', { kind: 'NamedType' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('with multiple directives', () => {
const { t } = getUtils(`
extend type SomeType {
someField: AnotherType @someDirective @anotherDirective
}
`);
t.keyword('extend', { kind: 'ExtendDef' });
t.keyword('type', { kind: 'ObjectTypeDef' });
t.name('SomeType');
t.punctuation('{');
t.property('someField', { kind: 'FieldDef' });
t.punctuation(':');
t.name('AnotherType', { kind: 'NamedType' });
expectDirective({ t }, { name: 'someDirective' });
expectDirective({ t }, { name: 'anotherDirective' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
});
describe('parses input type def', () => {
it('correctly', () => {
const { t } = getUtils(`
input SomeInputType {
someField: AnotherType
}
`);
t.keyword('input', { kind: 'InputDef' });
t.name('SomeInputType');
t.punctuation('{');
t.attribute('someField', { kind: 'InputValueDef' });
t.punctuation(':');
t.name('AnotherType', { kind: 'NamedType' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('with multiple directives', () => {
const { t } = getUtils(`
input SomeInputType {
someField: AnotherType @someDirective @anotherDirective
}
`);
t.keyword('input', { kind: 'InputDef' });
t.name('SomeInputType');
t.punctuation('{');
t.attribute('someField', { kind: 'InputValueDef' });
t.punctuation(':');
t.name('AnotherType', { kind: 'NamedType' });
expectDirective({ t }, { name: 'someDirective' });
expectDirective({ t }, { name: 'anotherDirective' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
});
describe('parses enum type def', () => {
it('correctly', () => {
const { t } = getUtils(`
enum SomeEnum {
SOME_ENUM_VALUE
ANOTHER_ENUM_VALUE
}
`);
t.keyword('enum', { kind: 'EnumDef' });
t.name('SomeEnum');
t.punctuation('{');
t.value('Enum', 'SOME_ENUM_VALUE', { kind: 'EnumValueDef' });
t.value('Enum', 'ANOTHER_ENUM_VALUE', { kind: 'EnumValueDef' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
it('with a directive', () => {
const { t } = getUtils(`
enum SomeEnum @someDirective {
SOME_ENUM_VALUE
ANOTHER_ENUM_VALUE
}
`);
t.keyword('enum', { kind: 'EnumDef' });
t.name('SomeEnum');
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('{', { kind: 'EnumDef' });
t.value('Enum', 'SOME_ENUM_VALUE', { kind: 'EnumValueDef' });
t.value('Enum', 'ANOTHER_ENUM_VALUE', { kind: 'EnumValueDef' });
t.punctuation('}', { kind: 'Document' });
t.eol();
});
});
describe('parses scalar type def', () => {
it('correctly', () => {
const { t } = getUtils('scalar SomeScalar');
t.keyword('scalar', { kind: 'ScalarDef' });
t.name('SomeScalar');
t.eol();
});
it('with a directive', () => {
const { t } = getUtils('scalar SomeScalar @someDirective');
t.keyword('scalar', { kind: 'ScalarDef' });
t.name('SomeScalar');
expectDirective({ t }, { name: 'someDirective' });
t.eol();
});
});
describe('parses union type def', () => {
it('correctly', () => {
const { t } = getUtils('union SomeUnionType = SomeType | AnotherType');
t.keyword('union', { kind: 'UnionDef' });
t.name('SomeUnionType');
t.punctuation('=');
t.name('SomeType', { kind: 'NamedType' });
t.punctuation('|', { kind: 'UnionDef' });
t.name('AnotherType', { kind: 'NamedType' });
t.eol();
});
it('with a directive', () => {
const { t } = getUtils(
'union SomeUnionType @someDirective = SomeType | AnotherType',
);
t.keyword('union', { kind: 'UnionDef' });
t.name('SomeUnionType');
expectDirective({ t }, { name: 'someDirective' });
t.punctuation('=', { kind: 'UnionDef' });
t.name('SomeType', { kind: 'NamedType' });
t.punctuation('|', { kind: 'UnionDef' });
t.name('AnotherType', { kind: 'NamedType' });
t.eol();
});
});
describe('parses directive type def', () => {
it('with multiple locations', () => {
const { t } = getUtils(
'directive @someDirective on FIELD_DEFINITION | ENUM_VALUE ',
);
t.keyword('directive', { kind: 'DirectiveDef' });
t.meta('@');
t.meta('someDirective');
t.keyword('on');
t.value('Enum', 'FIELD_DEFINITION', { kind: 'DirectiveLocation' });
t.punctuation('|', { kind: 'DirectiveDef' });
t.value('Enum', 'ENUM_VALUE', { kind: 'DirectiveLocation' });
t.eol();
});
});
});
});