@apollo/federation-internals 2.4.5 → 2.4.7
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.
- package/dist/operations.d.ts +43 -113
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +370 -297
- package/dist/operations.js.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/operations.ts +697 -453
- package/src/utils.ts +1 -1
- package/CHANGELOG.md +0 -211
- package/jest.config.js +0 -11
- package/src/__tests__/coreSpec.test.ts +0 -212
- package/src/__tests__/definitions.test.ts +0 -982
- package/src/__tests__/directiveAndTypeSpecifications.test.ts +0 -41
- package/src/__tests__/extractSubgraphsFromSupergraph.test.ts +0 -748
- package/src/__tests__/federation.test.ts +0 -31
- package/src/__tests__/graphQLJSSchemaToAST.test.ts +0 -156
- package/src/__tests__/matchers/index.ts +0 -1
- package/src/__tests__/matchers/toMatchString.ts +0 -87
- package/src/__tests__/operations.test.ts +0 -1266
- package/src/__tests__/removeInaccessibleElements.test.ts +0 -2471
- package/src/__tests__/schemaUpgrader.test.ts +0 -287
- package/src/__tests__/subgraphValidation.test.ts +0 -1254
- package/src/__tests__/supergraphSdl.graphql +0 -281
- package/src/__tests__/testUtils.ts +0 -28
- package/src/__tests__/toAPISchema.test.ts +0 -53
- package/src/__tests__/tsconfig.json +0 -7
- package/src/__tests__/utils.test.ts +0 -92
- package/src/__tests__/values.test.ts +0 -390
- package/tsconfig.json +0 -10
- package/tsconfig.test.json +0 -8
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1,982 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Schema,
|
|
3
|
-
ObjectType,
|
|
4
|
-
Type,
|
|
5
|
-
DirectiveDefinition,
|
|
6
|
-
InterfaceType,
|
|
7
|
-
EnumType,
|
|
8
|
-
SchemaElement,
|
|
9
|
-
UnionType,
|
|
10
|
-
InputObjectType,
|
|
11
|
-
} from '../../dist/definitions';
|
|
12
|
-
import {
|
|
13
|
-
printSchema as printGraphQLjsSchema,
|
|
14
|
-
} from 'graphql';
|
|
15
|
-
import { defaultPrintOptions, printSchema } from '../../dist/print';
|
|
16
|
-
import { buildSchema } from '../../dist/buildSchema';
|
|
17
|
-
import { buildSubgraph, federationMetadata, newEmptyFederation2Schema } from '../../dist/federation';
|
|
18
|
-
import './matchers';
|
|
19
|
-
|
|
20
|
-
function parseSchema(schema: string): Schema {
|
|
21
|
-
try {
|
|
22
|
-
return buildSchema(schema);
|
|
23
|
-
} catch (e) {
|
|
24
|
-
throw new Error(e.toString());
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function expectObjectType(type?: Type): asserts type is ObjectType {
|
|
29
|
-
expect(type).toBeDefined();
|
|
30
|
-
expect(type!.kind).toBe('ObjectType');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function expectInterfaceType(type?: Type): asserts type is InterfaceType {
|
|
34
|
-
expect(type).toBeDefined();
|
|
35
|
-
expect(type!.kind).toBe('InterfaceType');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function expectUnionType(type?: Type): asserts type is UnionType {
|
|
39
|
-
expect(type).toBeDefined();
|
|
40
|
-
expect(type!.kind).toBe('UnionType');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function expectEnumType(type?: Type): asserts type is EnumType {
|
|
44
|
-
expect(type).toBeDefined();
|
|
45
|
-
expect(type!.kind).toBe('EnumType');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
declare global {
|
|
49
|
-
namespace jest {
|
|
50
|
-
interface Matchers<R> {
|
|
51
|
-
toHaveField(name: string, type?: Type): R;
|
|
52
|
-
toHaveDirective<TArgs extends {[key: string]: any}>(directive: DirectiveDefinition<TArgs>, args?: TArgs): R;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
expect.extend({
|
|
58
|
-
toHaveField(parentType: ObjectType | InterfaceType, name: string, type?: Type) {
|
|
59
|
-
const field = parentType.field(name);
|
|
60
|
-
if (!field) {
|
|
61
|
-
return {
|
|
62
|
-
message: () => `Cannot find field '${name}' in Object Type ${parentType} with fields [${[...parentType.fields()]}]`,
|
|
63
|
-
pass: false
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
if (field.name != name) {
|
|
67
|
-
return {
|
|
68
|
-
message: () => `Type ${parentType} has a field linked to name ${name} but that field name is actually ${field.name}`,
|
|
69
|
-
pass: false
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
if (type && field.type != type) {
|
|
73
|
-
return {
|
|
74
|
-
message: () => `Expected field ${parentType}.${name} to have type ${type} but got type ${field.type}`,
|
|
75
|
-
pass: false
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
return {
|
|
79
|
-
message: () => `Expected ${parentType} not to have field ${name} but it does (${field})`,
|
|
80
|
-
pass: true
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
|
|
84
|
-
toHaveDirective(element: SchemaElement<any, any>, definition: DirectiveDefinition, args?: Record<string, any>) {
|
|
85
|
-
const directives = element.appliedDirectivesOf(definition);
|
|
86
|
-
if (directives.length == 0) {
|
|
87
|
-
return {
|
|
88
|
-
message: () => `Cannot find directive @${definition} applied to element ${element} (whose applied directives are [${element.appliedDirectives.join(', ')}]`,
|
|
89
|
-
pass: false
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
if (!args) {
|
|
93
|
-
return {
|
|
94
|
-
message: () => `Expected directive @${definition} to not be applied to ${element} but it is`,
|
|
95
|
-
pass: true
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
for (const directive of directives) {
|
|
100
|
-
if (directive.matchArguments(args)) {
|
|
101
|
-
return {
|
|
102
|
-
// Not 100% certain that message is correct but I don't think it's going to be used ...
|
|
103
|
-
message: () => `Expected directive ${directive.name} applied to ${element} to have arguments ${JSON.stringify(args)} but got ${JSON.stringify(directive.arguments)}`,
|
|
104
|
-
pass: true
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return {
|
|
109
|
-
message: () => `Element ${element} has application of directive @${definition} but not with the requested arguments. Got applications: [${directives.join(', ')}]`,
|
|
110
|
-
pass: false
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test('building a simple schema programatically', () => {
|
|
116
|
-
const schema = newEmptyFederation2Schema();
|
|
117
|
-
const queryType = schema.schemaDefinition.setRoot('query', schema.addType(new ObjectType('Query'))).type;
|
|
118
|
-
const typeA = schema.addType(new ObjectType('A'));
|
|
119
|
-
const key = federationMetadata(schema)!.keyDirective();
|
|
120
|
-
|
|
121
|
-
queryType.addField('a', typeA);
|
|
122
|
-
typeA.addField('q', queryType);
|
|
123
|
-
typeA.applyDirective(key, { fields: 'a'});
|
|
124
|
-
|
|
125
|
-
expect(queryType).toBe(schema.schemaDefinition.root('query')!.type);
|
|
126
|
-
expect(queryType).toHaveField('a', typeA);
|
|
127
|
-
expect(typeA).toHaveField('q', queryType);
|
|
128
|
-
expect(typeA).toHaveDirective(key, { fields: 'a'});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
test('parse schema and modify', () => {
|
|
133
|
-
const sdl = `
|
|
134
|
-
schema {
|
|
135
|
-
query: MyQuery
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
directive @inaccessible on FIELD_DEFINITION | ARGUMENT_DEFINITION
|
|
139
|
-
|
|
140
|
-
type A {
|
|
141
|
-
f1(x: Int @inaccessible): String
|
|
142
|
-
f2: String @inaccessible
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
type MyQuery {
|
|
146
|
-
a: A
|
|
147
|
-
b: Int
|
|
148
|
-
}`;
|
|
149
|
-
const schema = parseSchema(sdl);
|
|
150
|
-
|
|
151
|
-
const queryType = schema.type('MyQuery')!;
|
|
152
|
-
const typeA = schema.type('A')!;
|
|
153
|
-
const inaccessibleDirective = schema.directive('inaccessible')!;
|
|
154
|
-
expectObjectType(queryType);
|
|
155
|
-
expectObjectType(typeA);
|
|
156
|
-
expect(schema.schemaDefinition.root('query')!.type).toBe(queryType);
|
|
157
|
-
expect(queryType).toHaveField('a', typeA);
|
|
158
|
-
const f2 = typeA.field('f2');
|
|
159
|
-
expect(f2).toHaveDirective(inaccessibleDirective);
|
|
160
|
-
expect(printSchema(schema)).toMatchString(sdl);
|
|
161
|
-
|
|
162
|
-
expect(typeA).toHaveField('f1');
|
|
163
|
-
typeA.field('f1')!.remove();
|
|
164
|
-
expect(typeA).not.toHaveField('f1');
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
test('removal of all directives of a schema', () => {
|
|
168
|
-
const subgraph = buildSubgraph('foo', '', `
|
|
169
|
-
schema @foo {
|
|
170
|
-
query: Query
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
type Query {
|
|
174
|
-
a(id: String @bar): A @inaccessible
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
type A {
|
|
178
|
-
a1: String @foo
|
|
179
|
-
a2: [Int]
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
type B @foo {
|
|
183
|
-
b: String @bar
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
union U @foobar = A | B
|
|
187
|
-
|
|
188
|
-
directive @inaccessible on FIELD_DEFINITION
|
|
189
|
-
directive @foo on SCHEMA | FIELD_DEFINITION | OBJECT
|
|
190
|
-
directive @foobar on UNION
|
|
191
|
-
directive @bar on ARGUMENT_DEFINITION | FIELD_DEFINITION
|
|
192
|
-
`).validate();
|
|
193
|
-
|
|
194
|
-
const schema = subgraph.schema;
|
|
195
|
-
for (const element of schema.allSchemaElement()) {
|
|
196
|
-
element.appliedDirectives.forEach(d => d.remove());
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
expect(subgraph.toString()).toMatchString(`
|
|
200
|
-
directive @inaccessible on FIELD_DEFINITION
|
|
201
|
-
|
|
202
|
-
directive @foo on SCHEMA | FIELD_DEFINITION | OBJECT
|
|
203
|
-
|
|
204
|
-
directive @foobar on UNION
|
|
205
|
-
|
|
206
|
-
directive @bar on ARGUMENT_DEFINITION | FIELD_DEFINITION
|
|
207
|
-
|
|
208
|
-
type Query {
|
|
209
|
-
a(id: String): A
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
type A {
|
|
213
|
-
a1: String
|
|
214
|
-
a2: [Int]
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
type B {
|
|
218
|
-
b: String
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
union U = A | B`);
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
test('removal of an enum type should remove enum values', () => {
|
|
225
|
-
const schema = buildSchema(`
|
|
226
|
-
type Query {
|
|
227
|
-
someField: String!
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
enum Enum {
|
|
231
|
-
SOME_VALUE
|
|
232
|
-
OTHER_VALUE
|
|
233
|
-
}
|
|
234
|
-
`);
|
|
235
|
-
|
|
236
|
-
const enumType = schema.type("Enum");
|
|
237
|
-
expectEnumType(enumType)
|
|
238
|
-
const enumValues = Array.from(enumType.values);
|
|
239
|
-
enumType.remove()
|
|
240
|
-
for (const value of enumValues) {
|
|
241
|
-
expect(value.isAttached()).toBe(false)
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
test('removal of all inaccessible elements of a schema', () => {
|
|
246
|
-
const subgraph = buildSubgraph('foo', '', `
|
|
247
|
-
schema @foo {
|
|
248
|
-
query: Query
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
type Query {
|
|
252
|
-
a(id: String @bar, arg: Int @inaccessible): A
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
type A {
|
|
256
|
-
a1: String @inaccessible
|
|
257
|
-
a2: [Int]
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
type B @inaccessible {
|
|
261
|
-
b: String @bar
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
union U @inaccessible = A | B
|
|
265
|
-
|
|
266
|
-
directive @inaccessible on FIELD_DEFINITION | OBJECT | ARGUMENT_DEFINITION | UNION
|
|
267
|
-
directive @foo on SCHEMA | FIELD_DEFINITION
|
|
268
|
-
directive @bar on ARGUMENT_DEFINITION | FIELD_DEFINITION
|
|
269
|
-
`);
|
|
270
|
-
|
|
271
|
-
const schema = subgraph.schema;
|
|
272
|
-
const inaccessibleDirective = schema.directive('inaccessible')!;
|
|
273
|
-
for (const element of schema.allNamedSchemaElement()) {
|
|
274
|
-
if (element.hasAppliedDirective(inaccessibleDirective)) {
|
|
275
|
-
element.remove();
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
expect(subgraph.toString()).toMatchString(`
|
|
280
|
-
schema
|
|
281
|
-
@foo
|
|
282
|
-
{
|
|
283
|
-
query: Query
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
directive @inaccessible on FIELD_DEFINITION | OBJECT | ARGUMENT_DEFINITION | UNION
|
|
287
|
-
|
|
288
|
-
directive @foo on SCHEMA | FIELD_DEFINITION
|
|
289
|
-
|
|
290
|
-
directive @bar on ARGUMENT_DEFINITION | FIELD_DEFINITION
|
|
291
|
-
|
|
292
|
-
type Query {
|
|
293
|
-
a(id: String @bar): A
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
type A {
|
|
297
|
-
a2: [Int]
|
|
298
|
-
}
|
|
299
|
-
`);
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
test('handling of interfaces', () => {
|
|
303
|
-
const schema = parseSchema(`
|
|
304
|
-
type Query {
|
|
305
|
-
bestIs: [I!]!
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
interface B {
|
|
309
|
-
a: Int
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
interface I implements B {
|
|
313
|
-
a: Int
|
|
314
|
-
b: String
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
type T1 implements B & I {
|
|
318
|
-
a: Int
|
|
319
|
-
b: String
|
|
320
|
-
c: Int
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
type T2 implements B & I {
|
|
324
|
-
a: Int
|
|
325
|
-
b: String
|
|
326
|
-
c: String
|
|
327
|
-
}
|
|
328
|
-
`);
|
|
329
|
-
|
|
330
|
-
const b = schema.type('B');
|
|
331
|
-
const i = schema.type('I');
|
|
332
|
-
const t1 = schema.type('T1');
|
|
333
|
-
const t2 = schema.type('T2');
|
|
334
|
-
expectInterfaceType(b);
|
|
335
|
-
expectInterfaceType(i);
|
|
336
|
-
expectObjectType(t1);
|
|
337
|
-
expectObjectType(t2);
|
|
338
|
-
|
|
339
|
-
for (const t of [b, i, t1, t2]) {
|
|
340
|
-
expect(t).toHaveField('a', schema.intType());
|
|
341
|
-
}
|
|
342
|
-
for (const t of [i, t1, t2]) {
|
|
343
|
-
expect(t).toHaveField('b', schema.stringType());
|
|
344
|
-
}
|
|
345
|
-
expect(t1).toHaveField('c', schema.intType());
|
|
346
|
-
expect(t2).toHaveField('c', schema.stringType());
|
|
347
|
-
|
|
348
|
-
expect(i.implementsInterface(b.name)).toBeTruthy();
|
|
349
|
-
expect(t1.implementsInterface(b.name)).toBeTruthy();
|
|
350
|
-
expect(t1.implementsInterface(i.name)).toBeTruthy();
|
|
351
|
-
expect(t2.implementsInterface(b.name)).toBeTruthy();
|
|
352
|
-
expect(t2.implementsInterface(i.name)).toBeTruthy();
|
|
353
|
-
|
|
354
|
-
expect(b.allImplementations()).toEqual([i, t1, t2]);
|
|
355
|
-
expect(i.allImplementations()).toEqual([t1, t2]);
|
|
356
|
-
|
|
357
|
-
for (const itf of [b, i]) {
|
|
358
|
-
expect(itf.possibleRuntimeTypes()).toEqual([t1, t2]);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
b.remove();
|
|
362
|
-
|
|
363
|
-
expect(printSchema(schema)).toMatchString(`
|
|
364
|
-
type Query {
|
|
365
|
-
bestIs: [I!]!
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
interface I {
|
|
369
|
-
a: Int
|
|
370
|
-
b: String
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
type T1 implements I {
|
|
374
|
-
a: Int
|
|
375
|
-
b: String
|
|
376
|
-
c: Int
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
type T2 implements I {
|
|
380
|
-
a: Int
|
|
381
|
-
b: String
|
|
382
|
-
c: String
|
|
383
|
-
}`);
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
test('handling of enums', () => {
|
|
387
|
-
const schema = parseSchema(`
|
|
388
|
-
type Query {
|
|
389
|
-
a: A
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
enum E {
|
|
393
|
-
V1
|
|
394
|
-
V2
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
type A {
|
|
398
|
-
a: Int
|
|
399
|
-
e: E
|
|
400
|
-
}
|
|
401
|
-
`);
|
|
402
|
-
|
|
403
|
-
const a = schema.type('A');
|
|
404
|
-
const e = schema.type('E');
|
|
405
|
-
expectObjectType(a);
|
|
406
|
-
expectEnumType(e);
|
|
407
|
-
|
|
408
|
-
expect(a).toHaveField('e', e);
|
|
409
|
-
const v1 = e.value('V1');
|
|
410
|
-
const v2 = e.value('V2');
|
|
411
|
-
expect(v1).toBeDefined();
|
|
412
|
-
expect(v2).toBeDefined();
|
|
413
|
-
expect(e.values).toEqual([v1, v2]);
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
test('handling of descriptions', () => {
|
|
417
|
-
const sdl = `
|
|
418
|
-
"""A super schema full of great queries"""
|
|
419
|
-
schema {
|
|
420
|
-
query: ASetOfQueries
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
"""Marks field that are deemed more important than others"""
|
|
424
|
-
directive @Important(
|
|
425
|
-
"""The reason for the importance of this field"""
|
|
426
|
-
why: String = "because!"
|
|
427
|
-
) on FIELD_DEFINITION
|
|
428
|
-
|
|
429
|
-
"""The actual queries of the schema"""
|
|
430
|
-
type ASetOfQueries {
|
|
431
|
-
"""Returns a set of products"""
|
|
432
|
-
bestProducts: [Product!]!
|
|
433
|
-
|
|
434
|
-
"""Finds a product by ID"""
|
|
435
|
-
product(
|
|
436
|
-
"""The ID identifying the product"""
|
|
437
|
-
id: ID!
|
|
438
|
-
): Product
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
"""A product that is also a book"""
|
|
442
|
-
type Book implements Product {
|
|
443
|
-
id: ID!
|
|
444
|
-
description: String!
|
|
445
|
-
|
|
446
|
-
"""
|
|
447
|
-
Number of pages in the book. Good so the customer knows its buying a 1000 page book for instance
|
|
448
|
-
"""
|
|
449
|
-
pages: Int @Important
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
extend type Book {
|
|
453
|
-
author: String
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
type DVD implements Product {
|
|
457
|
-
id: ID!
|
|
458
|
-
description: String!
|
|
459
|
-
|
|
460
|
-
"""The film author"""
|
|
461
|
-
author: String @Important(why: "it's good to give credit!")
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
"""Common interface to all our products"""
|
|
465
|
-
interface Product {
|
|
466
|
-
"""Identifies the product"""
|
|
467
|
-
id: ID!
|
|
468
|
-
|
|
469
|
-
"""
|
|
470
|
-
Something that explains what the product is. This can just be the title of the product, but this can be more than that if we want to. But it should be useful you know, otherwise our customer won't buy it.
|
|
471
|
-
"""
|
|
472
|
-
description: String!
|
|
473
|
-
}`;
|
|
474
|
-
const schema = parseSchema(sdl);
|
|
475
|
-
|
|
476
|
-
// Checking we get back the schema through printing it is mostly good enough, but let's just
|
|
477
|
-
// make sure long descriptions don't get annoying formatting newlines for instance when acessed on the
|
|
478
|
-
// schema directly.
|
|
479
|
-
const longComment = "Something that explains what the product is. This can just be the title of the product, but this can be more than that if we want to. But it should be useful you know, otherwise our customer won't buy it.";
|
|
480
|
-
const product = schema.type('Product');
|
|
481
|
-
expectInterfaceType(product);
|
|
482
|
-
expect(product.field('description')!.description).toBe(longComment);
|
|
483
|
-
|
|
484
|
-
expect(printSchema(schema)).toMatchString(sdl);
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
test('handling of extensions', () => {
|
|
488
|
-
const sdl = `
|
|
489
|
-
directive @foo on SCALAR
|
|
490
|
-
|
|
491
|
-
type Query {
|
|
492
|
-
f: Int
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
interface AInterface {
|
|
496
|
-
i1: Int
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
extend interface AInterface {
|
|
500
|
-
i2: Int
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
scalar AScalar
|
|
504
|
-
|
|
505
|
-
extend scalar AScalar
|
|
506
|
-
@foo
|
|
507
|
-
|
|
508
|
-
extend type AType {
|
|
509
|
-
t1: Int
|
|
510
|
-
t2: String
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
type AType2 {
|
|
514
|
-
t1: String
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
type AType3 {
|
|
518
|
-
t2: Int
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
union AUnion = AType | AType2
|
|
522
|
-
|
|
523
|
-
extend union AUnion = AType3
|
|
524
|
-
`;
|
|
525
|
-
|
|
526
|
-
// Note that we mark it as a subgraph because validation of extension is relaxed. In other words, it's
|
|
527
|
-
// expected that this will fail validation as a normal schema even though we don't use any
|
|
528
|
-
// federation directives.
|
|
529
|
-
const subgraph = buildSubgraph('foo', '', sdl);
|
|
530
|
-
expect(subgraph.toString()).toMatchString(sdl);
|
|
531
|
-
const schema = subgraph.schema;
|
|
532
|
-
|
|
533
|
-
const atype = schema.type('AType');
|
|
534
|
-
expectObjectType(atype);
|
|
535
|
-
expect(atype).toHaveField('t1', schema.intType());
|
|
536
|
-
expect(atype).toHaveField('t2', schema.stringType());
|
|
537
|
-
|
|
538
|
-
const aunion = schema.type('AUnion');
|
|
539
|
-
expectUnionType(aunion);
|
|
540
|
-
expect([...aunion.types()].map(t => t.name)).toEqual(['AType', 'AType2', 'AType3']);
|
|
541
|
-
|
|
542
|
-
expect(subgraph.toString({ ...defaultPrintOptions, mergeTypesAndExtensions: true })).toMatchString(`
|
|
543
|
-
directive @foo on SCALAR
|
|
544
|
-
|
|
545
|
-
type Query {
|
|
546
|
-
f: Int
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
interface AInterface {
|
|
550
|
-
i1: Int
|
|
551
|
-
i2: Int
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
scalar AScalar
|
|
555
|
-
@foo
|
|
556
|
-
|
|
557
|
-
type AType {
|
|
558
|
-
t1: Int
|
|
559
|
-
t2: String
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
type AType2 {
|
|
563
|
-
t1: String
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
type AType3 {
|
|
567
|
-
t2: Int
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
union AUnion = AType | AType2 | AType3
|
|
571
|
-
`);
|
|
572
|
-
});
|
|
573
|
-
|
|
574
|
-
describe('type extension where definition is empty', () => {
|
|
575
|
-
it('works for object types', () => {
|
|
576
|
-
const sdl = `
|
|
577
|
-
type Query {
|
|
578
|
-
foo: Foo
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
type Foo
|
|
582
|
-
|
|
583
|
-
extend type Foo {
|
|
584
|
-
baz: String
|
|
585
|
-
}
|
|
586
|
-
`;
|
|
587
|
-
|
|
588
|
-
const schema = buildSchema(sdl);
|
|
589
|
-
expect(printSchema(schema)).toMatchString(sdl);
|
|
590
|
-
expect(schema.type('Foo')?.hasNonExtensionElements()).toBeTruthy();
|
|
591
|
-
expect(schema.type('Foo')?.hasExtensionElements()).toBeTruthy();
|
|
592
|
-
});
|
|
593
|
-
|
|
594
|
-
it('works for union', () => {
|
|
595
|
-
const sdl = `
|
|
596
|
-
type Query {
|
|
597
|
-
foo: Foo
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
union Foo
|
|
601
|
-
|
|
602
|
-
extend union Foo = Bar
|
|
603
|
-
|
|
604
|
-
type Bar {
|
|
605
|
-
x: Int
|
|
606
|
-
}
|
|
607
|
-
`;
|
|
608
|
-
|
|
609
|
-
const schema = buildSchema(sdl);
|
|
610
|
-
expect(printSchema(schema)).toMatchString(sdl);
|
|
611
|
-
expect(schema.type('Foo')?.hasNonExtensionElements()).toBeTruthy();
|
|
612
|
-
expect(schema.type('Foo')?.hasExtensionElements()).toBeTruthy();
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
it('works for enum', () => {
|
|
616
|
-
const sdl = `
|
|
617
|
-
type Query {
|
|
618
|
-
foo: Foo
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
enum Foo
|
|
622
|
-
|
|
623
|
-
extend enum Foo {
|
|
624
|
-
Bar
|
|
625
|
-
}
|
|
626
|
-
`;
|
|
627
|
-
|
|
628
|
-
const schema = buildSchema(sdl);
|
|
629
|
-
expect(printSchema(schema)).toMatchString(sdl);
|
|
630
|
-
expect(schema.type('Foo')?.hasNonExtensionElements()).toBeTruthy();
|
|
631
|
-
expect(schema.type('Foo')?.hasExtensionElements()).toBeTruthy();
|
|
632
|
-
});
|
|
633
|
-
|
|
634
|
-
it('works for input object types', () => {
|
|
635
|
-
const sdl = `
|
|
636
|
-
type Query {
|
|
637
|
-
foo: Int
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
input Foo
|
|
641
|
-
|
|
642
|
-
extend input Foo {
|
|
643
|
-
bar: Int
|
|
644
|
-
}
|
|
645
|
-
`;
|
|
646
|
-
|
|
647
|
-
const schema = buildSchema(sdl);
|
|
648
|
-
expect(printSchema(schema)).toMatchString(sdl);
|
|
649
|
-
expect(schema.type('Foo')?.hasNonExtensionElements()).toBeTruthy();
|
|
650
|
-
expect(schema.type('Foo')?.hasExtensionElements()).toBeTruthy();
|
|
651
|
-
});
|
|
652
|
-
|
|
653
|
-
it('works for scalar type', () => {
|
|
654
|
-
const sdl = `
|
|
655
|
-
type Query {
|
|
656
|
-
foo: Int
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
scalar Foo
|
|
660
|
-
|
|
661
|
-
extend scalar Foo
|
|
662
|
-
@specifiedBy(url: "something")
|
|
663
|
-
`;
|
|
664
|
-
|
|
665
|
-
const schema = buildSchema(sdl);
|
|
666
|
-
expect(printSchema(schema)).toMatchString(sdl);
|
|
667
|
-
expect(schema.type('Foo')?.hasNonExtensionElements()).toBeTruthy();
|
|
668
|
-
expect(schema.type('Foo')?.hasExtensionElements()).toBeTruthy();
|
|
669
|
-
});
|
|
670
|
-
})
|
|
671
|
-
|
|
672
|
-
test('reject type defined multiple times', () => {
|
|
673
|
-
const sdl = `
|
|
674
|
-
type Query {
|
|
675
|
-
foo: Foo
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
type Foo {
|
|
679
|
-
bar: String
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
type Foo {
|
|
683
|
-
baz: String
|
|
684
|
-
}
|
|
685
|
-
`;
|
|
686
|
-
|
|
687
|
-
expect(() => buildSchema(sdl).validate()).toThrow('There can be only one type named "Foo"');
|
|
688
|
-
});
|
|
689
|
-
|
|
690
|
-
test('default arguments for directives', () => {
|
|
691
|
-
const sdl = `
|
|
692
|
-
directive @Example(inputObject: ExampleInputObject! = {}) on FIELD_DEFINITION
|
|
693
|
-
|
|
694
|
-
type Query {
|
|
695
|
-
v1: Int @Example
|
|
696
|
-
v2: Int @Example(inputObject: {})
|
|
697
|
-
v3: Int @Example(inputObject: {number: 3})
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
input ExampleInputObject {
|
|
701
|
-
number: Int! = 3
|
|
702
|
-
}
|
|
703
|
-
`;
|
|
704
|
-
|
|
705
|
-
const schema = parseSchema(sdl);
|
|
706
|
-
expect(printSchema(schema)).toMatchString(sdl);
|
|
707
|
-
|
|
708
|
-
const query = schema.schemaDefinition.root('query')!.type;
|
|
709
|
-
const exampleDirective = schema.directive('Example')!;
|
|
710
|
-
expect(query).toHaveField('v1');
|
|
711
|
-
expect(query).toHaveField('v2');
|
|
712
|
-
expect(query).toHaveField('v3');
|
|
713
|
-
const v1 = query.field('v1')!;
|
|
714
|
-
const v2 = query.field('v2')!;
|
|
715
|
-
const v3 = query.field('v3')!;
|
|
716
|
-
|
|
717
|
-
const d1 = v1.appliedDirectivesOf(exampleDirective)[0];
|
|
718
|
-
const d2 = v2.appliedDirectivesOf(exampleDirective)[0];
|
|
719
|
-
const d3 = v3.appliedDirectivesOf(exampleDirective)[0];
|
|
720
|
-
|
|
721
|
-
expect(d1.arguments()).toEqual({});
|
|
722
|
-
expect(d2.arguments()).toEqual({ inputObject: {}});
|
|
723
|
-
expect(d3.arguments()).toEqual({ inputObject: { number: 3 }});
|
|
724
|
-
|
|
725
|
-
expect(d1.arguments(true)).toEqual({ inputObject: { number: 3 }});
|
|
726
|
-
expect(d2.arguments(true)).toEqual({ inputObject: { number: 3 }});
|
|
727
|
-
expect(d3.arguments(true)).toEqual({ inputObject: { number: 3 }});
|
|
728
|
-
});
|
|
729
|
-
|
|
730
|
-
describe('clone', () => {
|
|
731
|
-
it('should allow directive application before definition', () => {
|
|
732
|
-
const schema = buildSchema(`
|
|
733
|
-
directive @foo(arg: String @wizz(arg: "foo")) on FIELD_DEFINITION
|
|
734
|
-
directive @wizz(arg: String @fuzz(arg: "wizz")) on ARGUMENT_DEFINITION
|
|
735
|
-
directive @fuzz(arg: String @buzz(arg: "fuzz")) on ARGUMENT_DEFINITION
|
|
736
|
-
directive @buzz(arg: String @baz(arg: "buzz")) on ARGUMENT_DEFINITION
|
|
737
|
-
directive @baz(arg: String @bar) on ARGUMENT_DEFINITION
|
|
738
|
-
directive @bar on ARGUMENT_DEFINITION
|
|
739
|
-
|
|
740
|
-
type Query {
|
|
741
|
-
foo: String! @foo(arg: "query")
|
|
742
|
-
}
|
|
743
|
-
`).clone();
|
|
744
|
-
|
|
745
|
-
expect(schema.elementByCoordinate("@foo")).toBeDefined();
|
|
746
|
-
expect(schema.elementByCoordinate("@wizz")).toBeDefined();
|
|
747
|
-
expect(schema.elementByCoordinate("@fuzz")).toBeDefined();
|
|
748
|
-
expect(schema.elementByCoordinate("@buzz")).toBeDefined();
|
|
749
|
-
expect(schema.elementByCoordinate("@baz")).toBeDefined();
|
|
750
|
-
expect(schema.elementByCoordinate("@bar")).toBeDefined();
|
|
751
|
-
});
|
|
752
|
-
|
|
753
|
-
// https://github.com/apollographql/federation/issues/1794
|
|
754
|
-
it('should allow using an imported federation diretive in another directive', () => {
|
|
755
|
-
const schema = buildSubgraph('foo', "", `
|
|
756
|
-
extend schema
|
|
757
|
-
@link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@tag"])
|
|
758
|
-
|
|
759
|
-
directive @foo(arg: String @tag(name: "tag")) on FIELD_DEFINITION
|
|
760
|
-
|
|
761
|
-
type Query {
|
|
762
|
-
hi: String! @foo
|
|
763
|
-
}
|
|
764
|
-
`).schema.clone();
|
|
765
|
-
expect(schema.elementByCoordinate("@foo")).toBeDefined();
|
|
766
|
-
expect(schema.elementByCoordinate("@tag")).toBeDefined();
|
|
767
|
-
});
|
|
768
|
-
|
|
769
|
-
it('should allow type use in directives', () => {
|
|
770
|
-
const schema = buildSchema(`
|
|
771
|
-
directive @foo(arg: Thing!) on FIELD_DEFINITION
|
|
772
|
-
scalar Thing
|
|
773
|
-
|
|
774
|
-
type Query {
|
|
775
|
-
foo: String! @foo(arg: "sunshine")
|
|
776
|
-
}
|
|
777
|
-
`).clone();
|
|
778
|
-
|
|
779
|
-
expect(schema.elementByCoordinate("@foo")).toBeDefined();
|
|
780
|
-
});
|
|
781
|
-
|
|
782
|
-
it('should allow recursive directive definitions', () => {
|
|
783
|
-
const schema = buildSchema(`
|
|
784
|
-
directive @foo(a: Int @bar) on ARGUMENT_DEFINITION
|
|
785
|
-
directive @bar(b: Int @foo) on ARGUMENT_DEFINITION
|
|
786
|
-
|
|
787
|
-
type Query {
|
|
788
|
-
getData(arg: String @foo): String!
|
|
789
|
-
}
|
|
790
|
-
`).clone();
|
|
791
|
-
expect(schema.elementByCoordinate("@foo")).toBeDefined();
|
|
792
|
-
expect(schema.elementByCoordinate("@bar")).toBeDefined();
|
|
793
|
-
});
|
|
794
|
-
});
|
|
795
|
-
|
|
796
|
-
describe('Conversion to graphQL-js schema', () => {
|
|
797
|
-
test('works on simple schema', () => {
|
|
798
|
-
const sdl = `
|
|
799
|
-
schema {
|
|
800
|
-
query: MyQuery
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
directive @foo on FIELD
|
|
804
|
-
|
|
805
|
-
type A {
|
|
806
|
-
f1(x: Int): String
|
|
807
|
-
f2: String
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
type MyQuery {
|
|
811
|
-
a: A
|
|
812
|
-
b: Int
|
|
813
|
-
}
|
|
814
|
-
`;
|
|
815
|
-
const schema = parseSchema(sdl);
|
|
816
|
-
|
|
817
|
-
const graphqQLSchema = schema.toGraphQLJSSchema();
|
|
818
|
-
expect(printGraphQLjsSchema(graphqQLSchema)).toMatchString(sdl);
|
|
819
|
-
});
|
|
820
|
-
|
|
821
|
-
test('can optionally add @defer and/or @streams definition(s)', () => {
|
|
822
|
-
const sdl = `
|
|
823
|
-
type Query {
|
|
824
|
-
x: Int
|
|
825
|
-
}
|
|
826
|
-
`;
|
|
827
|
-
const schema = parseSchema(sdl);
|
|
828
|
-
|
|
829
|
-
expect(printGraphQLjsSchema(schema.toGraphQLJSSchema({ includeDefer: true }))).toMatchString(`
|
|
830
|
-
directive @defer(label: String, if: Boolean! = true) on FRAGMENT_SPREAD | INLINE_FRAGMENT
|
|
831
|
-
|
|
832
|
-
type Query {
|
|
833
|
-
x: Int
|
|
834
|
-
}
|
|
835
|
-
`);
|
|
836
|
-
|
|
837
|
-
expect(printGraphQLjsSchema(schema.toGraphQLJSSchema({ includeDefer: true, includeStream: true }))).toMatchString(`
|
|
838
|
-
directive @defer(label: String, if: Boolean! = true) on FRAGMENT_SPREAD | INLINE_FRAGMENT
|
|
839
|
-
|
|
840
|
-
directive @stream(label: String, initialCount: Int = 0, if: Boolean! = true) on FIELD
|
|
841
|
-
|
|
842
|
-
type Query {
|
|
843
|
-
x: Int
|
|
844
|
-
}
|
|
845
|
-
`);
|
|
846
|
-
});
|
|
847
|
-
|
|
848
|
-
test('adding @defer and/or @streams definition(s) works properly for API schema of supergraphs with their own @defer definition', () => {
|
|
849
|
-
// Note that this test doesn't use a valid supergraph schema, but that doesn't really matter in this test. All that matter
|
|
850
|
-
// is that taking `toAPISchema()` followed by `toGraphQLJSSchema(config)` works properly when the original schema already has
|
|
851
|
-
// a `@defer` definition.
|
|
852
|
-
const sdl = `
|
|
853
|
-
directive @defer(label: String, if: Boolean! = true) on FRAGMENT_SPREAD | INLINE_FRAGMENT
|
|
854
|
-
directive @stream(label: String, initialCount: Int = 0, if: Boolean! = true) on FIELD
|
|
855
|
-
|
|
856
|
-
type Query {
|
|
857
|
-
x: Int
|
|
858
|
-
}
|
|
859
|
-
`;
|
|
860
|
-
|
|
861
|
-
// Note that with API schema, we want the @defer/@stream definitions from the original schema to essentially be ignored.
|
|
862
|
-
// So whether or not the @defer/@stream definition ends up in the output of `toGraphQLJSSchema` (of that API schema) should
|
|
863
|
-
// solely depend on the config provided to that method.
|
|
864
|
-
const apiSchema = parseSchema(sdl).toAPISchema();
|
|
865
|
-
|
|
866
|
-
expect(printGraphQLjsSchema(apiSchema.toGraphQLJSSchema())).toMatchString(`
|
|
867
|
-
type Query {
|
|
868
|
-
x: Int
|
|
869
|
-
}
|
|
870
|
-
`);
|
|
871
|
-
|
|
872
|
-
expect(printGraphQLjsSchema(apiSchema.toGraphQLJSSchema({ includeDefer: true }))).toMatchString(`
|
|
873
|
-
directive @defer(label: String, if: Boolean! = true) on FRAGMENT_SPREAD | INLINE_FRAGMENT
|
|
874
|
-
|
|
875
|
-
type Query {
|
|
876
|
-
x: Int
|
|
877
|
-
}
|
|
878
|
-
`);
|
|
879
|
-
|
|
880
|
-
expect(printGraphQLjsSchema(apiSchema.toGraphQLJSSchema({ includeDefer: true, includeStream: true }))).toMatchString(`
|
|
881
|
-
directive @defer(label: String, if: Boolean! = true) on FRAGMENT_SPREAD | INLINE_FRAGMENT
|
|
882
|
-
|
|
883
|
-
directive @stream(label: String, initialCount: Int = 0, if: Boolean! = true) on FIELD
|
|
884
|
-
|
|
885
|
-
type Query {
|
|
886
|
-
x: Int
|
|
887
|
-
}
|
|
888
|
-
`);
|
|
889
|
-
});
|
|
890
|
-
});
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
test('retrieving elements by coordinate', () => {
|
|
894
|
-
const sdl = `
|
|
895
|
-
directive @foo(bar: Int) on FIELD
|
|
896
|
-
|
|
897
|
-
type Query {
|
|
898
|
-
t: T
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
type T {
|
|
902
|
-
f1(x: Int): String
|
|
903
|
-
f2: String
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
interface I {
|
|
907
|
-
i: String
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
input O {
|
|
911
|
-
x: Int
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
enum E {
|
|
915
|
-
FOO
|
|
916
|
-
BAR
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
scalar Date
|
|
920
|
-
`;
|
|
921
|
-
const schema = parseSchema(sdl);
|
|
922
|
-
|
|
923
|
-
expect(schema.elementByCoordinate('Query')).toBe(schema.schemaDefinition.rootType('query'));
|
|
924
|
-
expect(schema.elementByCoordinate('Query.t')).toBe(schema.schemaDefinition.rootType('query')?.field('t'));
|
|
925
|
-
|
|
926
|
-
const typeT = schema.type('T') as ObjectType;
|
|
927
|
-
expect(schema.elementByCoordinate('T')).toBe(typeT);
|
|
928
|
-
expect(schema.elementByCoordinate('T.f1')).toBe(typeT.field('f1'));
|
|
929
|
-
expect(schema.elementByCoordinate('T.f2')).toBe(typeT.field('f2'));
|
|
930
|
-
expect(schema.elementByCoordinate('T.f1(x:)')).toBe(typeT.field('f1')?.argument('x'));
|
|
931
|
-
|
|
932
|
-
const typeI = schema.type('I') as InterfaceType;
|
|
933
|
-
expect(schema.elementByCoordinate('I')).toBe(typeI);
|
|
934
|
-
expect(schema.elementByCoordinate('I.i')).toBe(typeI.field('i'));
|
|
935
|
-
|
|
936
|
-
const typeO = schema.type('O') as InputObjectType;
|
|
937
|
-
expect(schema.elementByCoordinate('O')).toBe(typeO);
|
|
938
|
-
expect(schema.elementByCoordinate('O.x')).toBe(typeO.field('x'));
|
|
939
|
-
|
|
940
|
-
const typeE = schema.type('E') as EnumType;
|
|
941
|
-
expect(schema.elementByCoordinate('E')).toBe(typeE);
|
|
942
|
-
expect(schema.elementByCoordinate('E.FOO')).toBe(typeE.value('FOO'));
|
|
943
|
-
|
|
944
|
-
expect(schema.elementByCoordinate('Date')).toBe(schema.type('Date'));
|
|
945
|
-
|
|
946
|
-
const directiveFoo = schema.directive('foo')!;
|
|
947
|
-
expect(schema.elementByCoordinate('@foo')).toBe(directiveFoo);
|
|
948
|
-
expect(schema.elementByCoordinate('@foo(bar:)')).toBe(directiveFoo.argument('bar'));
|
|
949
|
-
|
|
950
|
-
expect(schema.elementByCoordinate('SomeType')).toBeUndefined();
|
|
951
|
-
expect(schema.elementByCoordinate('T.f3')).toBeUndefined();
|
|
952
|
-
expect(schema.elementByCoordinate('T.f1(y:)')).toBeUndefined();
|
|
953
|
-
expect(schema.elementByCoordinate('I.j')).toBeUndefined();
|
|
954
|
-
expect(schema.elementByCoordinate('I.j(x:)')).toBeUndefined();
|
|
955
|
-
expect(schema.elementByCoordinate('O.z')).toBeUndefined();
|
|
956
|
-
expect(schema.elementByCoordinate('@bar')).toBeUndefined();
|
|
957
|
-
expect(schema.elementByCoordinate('@foo(unknown:)')).toBeUndefined();
|
|
958
|
-
|
|
959
|
-
expect(() => schema.elementByCoordinate('foo bar')).toThrow();
|
|
960
|
-
expect(() => schema.elementByCoordinate('@foo.bar')).toThrow();
|
|
961
|
-
// Note that because 'O' is an input type, it's field can't have args
|
|
962
|
-
expect(() => schema.elementByCoordinate('O.x(foo:)')).toThrow();
|
|
963
|
-
// Note that because 'Date' is a scalar, it cannot have fields
|
|
964
|
-
expect(() => schema.elementByCoordinate('Date.bar')).toThrow();
|
|
965
|
-
})
|
|
966
|
-
|
|
967
|
-
test('parse error', () => {
|
|
968
|
-
const schema = `
|
|
969
|
-
extend schema
|
|
970
|
-
@link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@tag"])
|
|
971
|
-
{
|
|
972
|
-
query: Query
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
type Query {
|
|
976
|
-
hello: String
|
|
977
|
-
}
|
|
978
|
-
`;
|
|
979
|
-
const subgraph = buildSubgraph('test', '', schema);
|
|
980
|
-
|
|
981
|
-
expect(subgraph.toString()).toMatchString(schema);
|
|
982
|
-
});
|