@apollo/gateway 2.3.0-beta.2 → 2.3.0-beta.3

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.
@@ -0,0 +1,467 @@
1
+ import { buildSchemaFromAST, parseOperation } from "@apollo/federation-internals"
2
+ import { gql } from "apollo-federation-integration-testsuite";
3
+ import { computeResponse } from "../resultShaping";
4
+
5
+ const introspectionHandling = () => null;
6
+
7
+ describe('gateway post-processing', () => {
8
+ test('filters unqueried fields', () => {
9
+ const schema = buildSchemaFromAST(gql`
10
+ type Query {
11
+ t: T
12
+ v: Int!
13
+ }
14
+
15
+ type T {
16
+ a: Int
17
+ b: String
18
+ c: [C]
19
+ d: Int
20
+ }
21
+
22
+ interface C {
23
+ x: Int
24
+ y: Int
25
+ }
26
+
27
+ type P1 implements C {
28
+ id: ID!
29
+ x: Int
30
+ y: Int
31
+ }
32
+
33
+ type P2 implements C {
34
+ x: Int
35
+ y: Int
36
+ w: Int
37
+ z: Int
38
+ }
39
+ `);
40
+
41
+ const input = {
42
+ "t": {
43
+ "a": 0,
44
+ "b": 'testData',
45
+ "c": [{
46
+ __typename: 'P1',
47
+ id: 'foo',
48
+ x: 1,
49
+ y: 2,
50
+ }, {
51
+ __typename: 'P2',
52
+ x: 10,
53
+ y: 20,
54
+ w: 30,
55
+ z: 40,
56
+ }],
57
+ "d": 1,
58
+ },
59
+ "v": 42
60
+ }
61
+
62
+ const operation = parseOperation(schema, `
63
+ {
64
+ t {
65
+ a
66
+ c {
67
+ x
68
+ ... on P1 {
69
+ x
70
+ y
71
+ }
72
+ ... on P2 {
73
+ z
74
+ }
75
+ }
76
+ }
77
+ }
78
+ `);
79
+
80
+ expect(computeResponse({
81
+ operation,
82
+ input,
83
+ introspectionHandling,
84
+ })).toMatchInlineSnapshot(`
85
+ Object {
86
+ "data": Object {
87
+ "t": Object {
88
+ "a": 0,
89
+ "c": Array [
90
+ Object {
91
+ "x": 1,
92
+ "y": 2,
93
+ },
94
+ Object {
95
+ "x": 10,
96
+ "z": 40,
97
+ },
98
+ ],
99
+ },
100
+ },
101
+ "errors": Array [],
102
+ }
103
+ `);
104
+ });
105
+
106
+ describe('null propagation for non-nullable types', () => {
107
+ const schema = buildSchemaFromAST(gql`
108
+ type Query {
109
+ tNullable: T
110
+ tNonNullable: T!
111
+ }
112
+
113
+ type T {
114
+ a: Int
115
+ b: Int!
116
+ c: [Int]
117
+ d: [Int]!
118
+ e: [Int!]
119
+ f: [Int!]!
120
+ }
121
+ `);
122
+
123
+ const tObj = {
124
+ "a": null,
125
+ "b": null,
126
+ "c": [24, null, 42, null],
127
+ "d": [24, null, 42, null],
128
+ "e": [24, null, 42, null],
129
+ "f": [24, null, 42, null],
130
+ }
131
+
132
+ const input = {
133
+ "tNullable": tObj,
134
+ "tNonNullable": tObj,
135
+ }
136
+
137
+ test('no propagation on nullable (non-list) type', () => {
138
+ const operation = parseOperation(schema, `
139
+ {
140
+ tNonNullable {
141
+ a
142
+ }
143
+ }
144
+ `);
145
+
146
+ expect(computeResponse({
147
+ operation,
148
+ input,
149
+ introspectionHandling,
150
+ })).toMatchInlineSnapshot(`
151
+ Object {
152
+ "data": Object {
153
+ "tNonNullable": Object {
154
+ "a": null,
155
+ },
156
+ },
157
+ "errors": Array [],
158
+ }
159
+ `);
160
+ });
161
+
162
+ test('propagation on non-nullable (non-list) type', () => {
163
+ const operationNonNullable = parseOperation(schema, `
164
+ {
165
+ tNonNullable {
166
+ b
167
+ }
168
+ }
169
+ `);
170
+
171
+ let res = computeResponse({
172
+ operation: operationNonNullable,
173
+ input,
174
+ introspectionHandling,
175
+ });
176
+ expect(res).toMatchInlineSnapshot(`
177
+ Object {
178
+ "data": null,
179
+ "errors": Array [
180
+ [GraphQLError: Cannot return null for non-nullable field T.b.],
181
+ ],
182
+ }
183
+ `);
184
+ expect(res.errors[0].path).toStrictEqual(['tNonNullable', 'b']);
185
+
186
+
187
+ const operationNullable = parseOperation(schema, `
188
+ {
189
+ tNullable {
190
+ b
191
+ }
192
+ }
193
+ `);
194
+
195
+ res = computeResponse({
196
+ operation: operationNullable,
197
+ input,
198
+ introspectionHandling,
199
+ });
200
+ expect(res).toMatchInlineSnapshot(`
201
+ Object {
202
+ "data": Object {
203
+ "tNullable": null,
204
+ },
205
+ "errors": Array [
206
+ [GraphQLError: Cannot return null for non-nullable field T.b.],
207
+ ],
208
+ }
209
+ `);
210
+ expect(res.errors[0].path).toStrictEqual(['tNullable', 'b']);
211
+ });
212
+
213
+ test('no propagation on nullable list type', () => {
214
+ const operation = parseOperation(schema, `
215
+ {
216
+ tNonNullable {
217
+ c
218
+ }
219
+ }
220
+ `);
221
+
222
+ expect(computeResponse({
223
+ operation,
224
+ input,
225
+ introspectionHandling,
226
+ })).toMatchInlineSnapshot(`
227
+ Object {
228
+ "data": Object {
229
+ "tNonNullable": Object {
230
+ "c": Array [
231
+ 24,
232
+ null,
233
+ 42,
234
+ null,
235
+ ],
236
+ },
237
+ },
238
+ "errors": Array [],
239
+ }
240
+ `);
241
+ });
242
+
243
+ test('no propagation on null elements of non-nullable list type with nullable inner element type', () => {
244
+ const operationNonNullable = parseOperation(schema, `
245
+ {
246
+ tNonNullable {
247
+ d
248
+ }
249
+ }
250
+ `);
251
+
252
+ let res = computeResponse({
253
+ operation: operationNonNullable,
254
+ input,
255
+ introspectionHandling,
256
+ });
257
+ expect(res).toMatchInlineSnapshot(`
258
+ Object {
259
+ "data": Object {
260
+ "tNonNullable": Object {
261
+ "d": Array [
262
+ 24,
263
+ null,
264
+ 42,
265
+ null,
266
+ ],
267
+ },
268
+ },
269
+ "errors": Array [],
270
+ }
271
+ `);
272
+ });
273
+
274
+ test('propagation on null elements of list type with non-nullable inner element type', () => {
275
+ const operationNonNullable = parseOperation(schema, `
276
+ {
277
+ tNonNullable {
278
+ e
279
+ }
280
+ }
281
+ `);
282
+
283
+ let res = computeResponse({
284
+ operation: operationNonNullable,
285
+ input,
286
+ introspectionHandling,
287
+ });
288
+ expect(res).toMatchInlineSnapshot(`
289
+ Object {
290
+ "data": Object {
291
+ "tNonNullable": Object {
292
+ "e": null,
293
+ },
294
+ },
295
+ "errors": Array [
296
+ [GraphQLError: Cannot return null for non-nullable array element of type Int at index 1.],
297
+ [GraphQLError: Cannot return null for non-nullable array element of type Int at index 3.],
298
+ ],
299
+ }
300
+ `);
301
+ expect(res.errors[0].path).toStrictEqual(['tNonNullable', 'e', 1]);
302
+ expect(res.errors[1].path).toStrictEqual(['tNonNullable', 'e', 3]);
303
+ });
304
+
305
+ test('propagation on null elements of non-nullable list type with non-nullable inner element type', () => {
306
+ const operationNonNullable = parseOperation(schema, `
307
+ {
308
+ tNonNullable {
309
+ f
310
+ }
311
+ }
312
+ `);
313
+
314
+ let res = computeResponse({
315
+ operation: operationNonNullable,
316
+ input,
317
+ introspectionHandling,
318
+ });
319
+ expect(res).toMatchInlineSnapshot(`
320
+ Object {
321
+ "data": null,
322
+ "errors": Array [
323
+ [GraphQLError: Cannot return null for non-nullable array element of type Int at index 1.],
324
+ [GraphQLError: Cannot return null for non-nullable array element of type Int at index 3.],
325
+ ],
326
+ }
327
+ `);
328
+ expect(res.errors[0].path).toStrictEqual(['tNonNullable', 'f', 1]);
329
+ expect(res.errors[1].path).toStrictEqual(['tNonNullable', 'f', 3]);
330
+
331
+ const operationNullable = parseOperation(schema, `
332
+ {
333
+ tNullable {
334
+ f
335
+ }
336
+ }
337
+ `);
338
+
339
+ res = computeResponse({
340
+ operation: operationNullable,
341
+ input,
342
+ introspectionHandling,
343
+ });
344
+ expect(res).toMatchInlineSnapshot(`
345
+ Object {
346
+ "data": Object {
347
+ "tNullable": null,
348
+ },
349
+ "errors": Array [
350
+ [GraphQLError: Cannot return null for non-nullable array element of type Int at index 1.],
351
+ [GraphQLError: Cannot return null for non-nullable array element of type Int at index 3.],
352
+ ],
353
+ }
354
+ `);
355
+ expect(res.errors[0].path).toStrictEqual(['tNullable', 'f', 1]);
356
+ expect(res.errors[1].path).toStrictEqual(['tNullable', 'f', 3]);
357
+ });
358
+ });
359
+
360
+ test('handles invalid values for native scalars', () => {
361
+ const schema = buildSchemaFromAST(gql`
362
+ type Query {
363
+ x: Int!
364
+ }
365
+ `);
366
+
367
+ const input = {
368
+ "x": 'foo',
369
+ }
370
+
371
+ const operation = parseOperation(schema, `
372
+ {
373
+ x
374
+ }
375
+ `);
376
+
377
+ const res = computeResponse({
378
+ operation,
379
+ input,
380
+ introspectionHandling,
381
+ });
382
+ expect(res).toMatchInlineSnapshot(`
383
+ Object {
384
+ "data": null,
385
+ "errors": Array [
386
+ [GraphQLError: Invalid value found for field Query.x.],
387
+ ],
388
+ }
389
+ `);
390
+ expect(res.errors[0].path).toStrictEqual(['x']);
391
+ });
392
+
393
+ test('Adds __typename for root types if necessary', () => {
394
+ const schema = buildSchemaFromAST(gql`
395
+ type Query {
396
+ t: T
397
+ }
398
+
399
+ type T {
400
+ a: Int
401
+ q: Query
402
+ }
403
+ `);
404
+
405
+ const input = {
406
+ "t": {
407
+ "a": 42,
408
+ "q": {
409
+ "t": {
410
+ "q": {
411
+ "t": {
412
+ "a": 24
413
+ },
414
+ },
415
+ },
416
+ },
417
+ },
418
+ }
419
+
420
+ const operation = parseOperation(schema, `
421
+ {
422
+ __typename
423
+ t {
424
+ a
425
+ q {
426
+ __typename
427
+ t {
428
+ q {
429
+ __typename
430
+ t {
431
+ a
432
+ }
433
+ }
434
+ }
435
+ }
436
+ }
437
+ }
438
+ `);
439
+
440
+ expect(computeResponse({
441
+ operation,
442
+ input,
443
+ introspectionHandling,
444
+ })).toMatchInlineSnapshot(`
445
+ Object {
446
+ "data": Object {
447
+ "__typename": "Query",
448
+ "t": Object {
449
+ "a": 42,
450
+ "q": Object {
451
+ "__typename": "Query",
452
+ "t": Object {
453
+ "q": Object {
454
+ "__typename": "Query",
455
+ "t": Object {
456
+ "a": 24,
457
+ },
458
+ },
459
+ },
460
+ },
461
+ },
462
+ },
463
+ "errors": Array [],
464
+ }
465
+ `);
466
+ });
467
+ })