@apollo/gateway 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/__generated__/graphqlTypes.d.ts +19 -1
- package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
- package/dist/__generated__/graphqlTypes.js +1 -0
- package/dist/__generated__/graphqlTypes.js.map +1 -1
- package/dist/executeQueryPlan.js +1 -1
- package/dist/executeQueryPlan.js.map +1 -1
- package/package.json +4 -4
- package/src/__generated__/graphqlTypes.ts +33 -2
- package/src/executeQueryPlan.ts +1 -1
- package/src/__mocks__/tsconfig.json +0 -7
- package/src/__tests__/.gitkeep +0 -0
- package/src/__tests__/CucumberREADME.md +0 -96
- package/src/__tests__/build-query-plan.feature +0 -1471
- package/src/__tests__/buildQueryPlan.test.ts +0 -1225
- package/src/__tests__/executeQueryPlan.conditions.test.ts +0 -1488
- package/src/__tests__/executeQueryPlan.introspection.test.ts +0 -140
- package/src/__tests__/executeQueryPlan.test.ts +0 -6140
- package/src/__tests__/execution-utils.ts +0 -124
- package/src/__tests__/gateway/__snapshots__/opentelemetry.test.ts.snap +0 -195
- package/src/__tests__/gateway/buildService.test.ts +0 -249
- package/src/__tests__/gateway/endToEnd.test.ts +0 -486
- package/src/__tests__/gateway/executor.test.ts +0 -96
- package/src/__tests__/gateway/extensions.test.ts +0 -37
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +0 -239
- package/src/__tests__/gateway/opentelemetry.test.ts +0 -123
- package/src/__tests__/gateway/queryPlanCache.test.ts +0 -231
- package/src/__tests__/gateway/queryPlannerConfig.test.ts +0 -101
- package/src/__tests__/gateway/reporting.test.ts +0 -616
- package/src/__tests__/gateway/supergraphSdl.test.ts +0 -396
- package/src/__tests__/gateway/testUtils.ts +0 -89
- package/src/__tests__/integration/abstract-types.test.ts +0 -1861
- package/src/__tests__/integration/aliases.test.ts +0 -180
- package/src/__tests__/integration/boolean.test.ts +0 -279
- package/src/__tests__/integration/complex-key.test.ts +0 -197
- package/src/__tests__/integration/configuration.test.ts +0 -404
- package/src/__tests__/integration/custom-directives.test.ts +0 -174
- package/src/__tests__/integration/execution-style.test.ts +0 -35
- package/src/__tests__/integration/fragments.test.ts +0 -237
- package/src/__tests__/integration/list-key.test.ts +0 -128
- package/src/__tests__/integration/logger.test.ts +0 -122
- package/src/__tests__/integration/managed.test.ts +0 -319
- package/src/__tests__/integration/merge-arrays.test.ts +0 -34
- package/src/__tests__/integration/multiple-key.test.ts +0 -327
- package/src/__tests__/integration/mutations.test.ts +0 -287
- package/src/__tests__/integration/networkRequests.test.ts +0 -542
- package/src/__tests__/integration/nockMocks.ts +0 -157
- package/src/__tests__/integration/provides.test.ts +0 -77
- package/src/__tests__/integration/requires.test.ts +0 -359
- package/src/__tests__/integration/scope.test.ts +0 -557
- package/src/__tests__/integration/single-service.test.ts +0 -119
- package/src/__tests__/integration/unions.test.ts +0 -79
- package/src/__tests__/integration/value-types.test.ts +0 -382
- package/src/__tests__/integration/variables.test.ts +0 -120
- package/src/__tests__/nockAssertions.ts +0 -20
- package/src/__tests__/queryPlanCucumber.test.ts +0 -55
- package/src/__tests__/resultShaping.test.ts +0 -605
- package/src/__tests__/testSetup.ts +0 -1
- package/src/__tests__/tsconfig.json +0 -8
- package/src/core/__tests__/core.test.ts +0 -412
- package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +0 -51
- package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +0 -574
- package/src/schema-helper/__tests__/addExtensions.test.ts +0 -70
- package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +0 -364
- package/src/supergraphManagers/IntrospectAndCompose/__tests__/loadServicesFromRemoteEndpoint.test.ts +0 -40
- package/src/supergraphManagers/UplinkSupergraphManager/__tests__/UplinkSupergraphManager.test.ts +0 -65
- package/src/supergraphManagers/UplinkSupergraphManager/__tests__/loadSupergraphSdlFromStorage.test.ts +0 -511
- package/src/utilities/__tests__/deepMerge.test.ts +0 -77
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import gql from 'graphql-tag';
|
|
2
|
-
import { astSerializer, queryPlanSerializer } from 'apollo-federation-integration-testsuite';
|
|
3
|
-
import { execute } from '../execution-utils';
|
|
4
|
-
|
|
5
|
-
expect.addSnapshotSerializer(astSerializer);
|
|
6
|
-
expect.addSnapshotSerializer(queryPlanSerializer);
|
|
7
|
-
|
|
8
|
-
it('handles multiple union type conditions that share a response name (media)', async () => {
|
|
9
|
-
const query = `#graphql
|
|
10
|
-
query {
|
|
11
|
-
content {
|
|
12
|
-
...Audio
|
|
13
|
-
... on Video {
|
|
14
|
-
media {
|
|
15
|
-
aspectRatio
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
fragment Audio on Audio {
|
|
21
|
-
media {
|
|
22
|
-
url
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
`;
|
|
26
|
-
|
|
27
|
-
const { queryPlan, errors } = await execute(
|
|
28
|
-
{ query },
|
|
29
|
-
[
|
|
30
|
-
{
|
|
31
|
-
name: 'contentService',
|
|
32
|
-
typeDefs: gql`
|
|
33
|
-
extend type Query {
|
|
34
|
-
content: Content
|
|
35
|
-
}
|
|
36
|
-
union Content = Audio | Video
|
|
37
|
-
type Audio {
|
|
38
|
-
media: AudioURL
|
|
39
|
-
}
|
|
40
|
-
type AudioURL {
|
|
41
|
-
url: String
|
|
42
|
-
}
|
|
43
|
-
type Video {
|
|
44
|
-
media: VideoAspectRatio
|
|
45
|
-
}
|
|
46
|
-
type VideoAspectRatio {
|
|
47
|
-
aspectRatio: String
|
|
48
|
-
}
|
|
49
|
-
`,
|
|
50
|
-
resolvers: {
|
|
51
|
-
Query: {},
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
],
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
expect(errors).toBeUndefined();
|
|
58
|
-
expect(queryPlan).toMatchInlineSnapshot(`
|
|
59
|
-
QueryPlan {
|
|
60
|
-
Fetch(service: "contentService") {
|
|
61
|
-
{
|
|
62
|
-
content {
|
|
63
|
-
__typename
|
|
64
|
-
... on Audio {
|
|
65
|
-
media {
|
|
66
|
-
url
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
... on Video {
|
|
70
|
-
media {
|
|
71
|
-
aspectRatio
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
}
|
|
78
|
-
`);
|
|
79
|
-
});
|
|
@@ -1,382 +0,0 @@
|
|
|
1
|
-
import { execute } from '../execution-utils';
|
|
2
|
-
import {
|
|
3
|
-
astSerializer,
|
|
4
|
-
fed2gql as gql,
|
|
5
|
-
queryPlanSerializer,
|
|
6
|
-
} from 'apollo-federation-integration-testsuite';
|
|
7
|
-
|
|
8
|
-
expect.addSnapshotSerializer(astSerializer);
|
|
9
|
-
expect.addSnapshotSerializer(queryPlanSerializer);
|
|
10
|
-
|
|
11
|
-
describe('value types', () => {
|
|
12
|
-
it('resolves value types within their respective services', async () => {
|
|
13
|
-
const query = `#graphql
|
|
14
|
-
fragment Metadata on MetadataOrError {
|
|
15
|
-
... on KeyValue {
|
|
16
|
-
key
|
|
17
|
-
value
|
|
18
|
-
}
|
|
19
|
-
... on Error {
|
|
20
|
-
code
|
|
21
|
-
message
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
query ProducsWithMetadata {
|
|
26
|
-
topProducts(first: 10) {
|
|
27
|
-
upc
|
|
28
|
-
... on Book {
|
|
29
|
-
metadata {
|
|
30
|
-
...Metadata
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
... on Furniture {
|
|
34
|
-
metadata {
|
|
35
|
-
...Metadata
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
reviews {
|
|
39
|
-
metadata {
|
|
40
|
-
...Metadata
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
`;
|
|
46
|
-
|
|
47
|
-
const { data, errors, queryPlan } = await execute({
|
|
48
|
-
query,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
expect(errors).toBeUndefined();
|
|
52
|
-
|
|
53
|
-
expect(queryPlan).toMatchInlineSnapshot(`
|
|
54
|
-
QueryPlan {
|
|
55
|
-
Sequence {
|
|
56
|
-
Fetch(service: "product") {
|
|
57
|
-
{
|
|
58
|
-
topProducts(first: 10) {
|
|
59
|
-
__typename
|
|
60
|
-
upc
|
|
61
|
-
... on Book {
|
|
62
|
-
__typename
|
|
63
|
-
isbn
|
|
64
|
-
}
|
|
65
|
-
... on Furniture {
|
|
66
|
-
__typename
|
|
67
|
-
upc
|
|
68
|
-
metadata {
|
|
69
|
-
__typename
|
|
70
|
-
... on KeyValue {
|
|
71
|
-
key
|
|
72
|
-
value
|
|
73
|
-
}
|
|
74
|
-
... on Error {
|
|
75
|
-
code
|
|
76
|
-
message
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
Parallel {
|
|
84
|
-
Flatten(path: "topProducts.@") {
|
|
85
|
-
Fetch(service: "reviews") {
|
|
86
|
-
{
|
|
87
|
-
... on Book {
|
|
88
|
-
__typename
|
|
89
|
-
isbn
|
|
90
|
-
}
|
|
91
|
-
... on Furniture {
|
|
92
|
-
__typename
|
|
93
|
-
upc
|
|
94
|
-
}
|
|
95
|
-
} =>
|
|
96
|
-
{
|
|
97
|
-
... on Book {
|
|
98
|
-
reviews {
|
|
99
|
-
metadata {
|
|
100
|
-
__typename
|
|
101
|
-
...Metadata
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
... on Furniture {
|
|
106
|
-
reviews {
|
|
107
|
-
metadata {
|
|
108
|
-
__typename
|
|
109
|
-
...Metadata
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
fragment Metadata on MetadataOrError {
|
|
116
|
-
... on KeyValue {
|
|
117
|
-
key
|
|
118
|
-
value
|
|
119
|
-
}
|
|
120
|
-
... on Error {
|
|
121
|
-
code
|
|
122
|
-
message
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
Flatten(path: "topProducts.@") {
|
|
128
|
-
Fetch(service: "books") {
|
|
129
|
-
{
|
|
130
|
-
... on Book {
|
|
131
|
-
__typename
|
|
132
|
-
isbn
|
|
133
|
-
}
|
|
134
|
-
} =>
|
|
135
|
-
{
|
|
136
|
-
... on Book {
|
|
137
|
-
metadata {
|
|
138
|
-
__typename
|
|
139
|
-
... on KeyValue {
|
|
140
|
-
key
|
|
141
|
-
value
|
|
142
|
-
}
|
|
143
|
-
... on Error {
|
|
144
|
-
code
|
|
145
|
-
message
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
}
|
|
155
|
-
`);
|
|
156
|
-
|
|
157
|
-
const [furniture, , , , book] = data!.topProducts;
|
|
158
|
-
|
|
159
|
-
// Sanity check, referenceable ID
|
|
160
|
-
expect(furniture.upc).toEqual('1');
|
|
161
|
-
// Value type resolves from the correct service
|
|
162
|
-
expect(furniture.metadata[0]).toEqual({
|
|
163
|
-
key: 'Condition',
|
|
164
|
-
value: 'excellent',
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
// Value type from a different service (reviews) also resolves correctly
|
|
168
|
-
expect(furniture.reviews[0].metadata[0]).toEqual({
|
|
169
|
-
code: 418,
|
|
170
|
-
message: "I'm a teapot",
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
// Sanity check, referenceable ID
|
|
174
|
-
expect(book.upc).toEqual('0136291554');
|
|
175
|
-
// Value type as a union resolves correctly
|
|
176
|
-
expect(book.metadata).toEqual([
|
|
177
|
-
{
|
|
178
|
-
key: 'Condition',
|
|
179
|
-
value: 'used',
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
code: 401,
|
|
183
|
-
message: 'Unauthorized',
|
|
184
|
-
},
|
|
185
|
-
]);
|
|
186
|
-
|
|
187
|
-
expect(queryPlan).toCallService('product');
|
|
188
|
-
expect(queryPlan).toCallService('books');
|
|
189
|
-
expect(queryPlan).toCallService('reviews');
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
it('resolves @provides fields on value types correctly via contrived example', async () => {
|
|
193
|
-
const firstService = {
|
|
194
|
-
name: 'firstService',
|
|
195
|
-
typeDefs: gql`
|
|
196
|
-
extend type Query {
|
|
197
|
-
valueType: ValueType
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
type ValueType @shareable {
|
|
201
|
-
id: ID!
|
|
202
|
-
user: User! @provides(fields: "name")
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
extend type User @key(fields: "id") {
|
|
206
|
-
id: ID! @external
|
|
207
|
-
name: String! @external
|
|
208
|
-
}
|
|
209
|
-
`,
|
|
210
|
-
resolvers: {
|
|
211
|
-
Query: {
|
|
212
|
-
valueType() {
|
|
213
|
-
return { id: '123', user: { id: '1', name: 'trevor' } };
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
},
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const secondService = {
|
|
220
|
-
name: 'secondService',
|
|
221
|
-
typeDefs: gql`
|
|
222
|
-
extend type Query {
|
|
223
|
-
otherValueType: ValueType
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
type ValueType @shareable {
|
|
227
|
-
id: ID!
|
|
228
|
-
user: User! @provides(fields: "name")
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
extend type User @key(fields: "id") {
|
|
232
|
-
id: ID! @external
|
|
233
|
-
name: String! @external
|
|
234
|
-
}
|
|
235
|
-
`,
|
|
236
|
-
resolvers: {
|
|
237
|
-
Query: {
|
|
238
|
-
otherValueType() {
|
|
239
|
-
return { id: '456', user: { id: '2', name: 'james' } };
|
|
240
|
-
},
|
|
241
|
-
},
|
|
242
|
-
},
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
const userService = {
|
|
246
|
-
name: 'userService',
|
|
247
|
-
typeDefs: gql`
|
|
248
|
-
type User @key(fields: "id") {
|
|
249
|
-
id: ID!
|
|
250
|
-
name: String! @shareable
|
|
251
|
-
address: String!
|
|
252
|
-
}
|
|
253
|
-
`,
|
|
254
|
-
resolvers: {
|
|
255
|
-
User: {
|
|
256
|
-
__resolveReference(user: any) {
|
|
257
|
-
return user.id === '1'
|
|
258
|
-
? { id: '1', name: 'trevor', address: '123 Abc St' }
|
|
259
|
-
: { id: '2', name: 'james', address: '456 Hello St.' };
|
|
260
|
-
},
|
|
261
|
-
},
|
|
262
|
-
},
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
const query = `#graphql
|
|
266
|
-
query Hello {
|
|
267
|
-
valueType {
|
|
268
|
-
id
|
|
269
|
-
user {
|
|
270
|
-
id
|
|
271
|
-
name
|
|
272
|
-
address
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
otherValueType {
|
|
276
|
-
id
|
|
277
|
-
user {
|
|
278
|
-
id
|
|
279
|
-
name
|
|
280
|
-
address
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
`;
|
|
285
|
-
|
|
286
|
-
const { data, errors, queryPlan } = await execute(
|
|
287
|
-
{
|
|
288
|
-
query,
|
|
289
|
-
},
|
|
290
|
-
[firstService, secondService, userService],
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
expect(errors).toBeUndefined();
|
|
294
|
-
expect(queryPlan).toCallService('firstService');
|
|
295
|
-
expect(queryPlan).toCallService('secondService');
|
|
296
|
-
expect(queryPlan).toCallService('userService');
|
|
297
|
-
expect(data).toMatchInlineSnapshot(`
|
|
298
|
-
Object {
|
|
299
|
-
"otherValueType": Object {
|
|
300
|
-
"id": "456",
|
|
301
|
-
"user": Object {
|
|
302
|
-
"address": "456 Hello St.",
|
|
303
|
-
"id": "2",
|
|
304
|
-
"name": "james",
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
|
-
"valueType": Object {
|
|
308
|
-
"id": "123",
|
|
309
|
-
"user": Object {
|
|
310
|
-
"address": "123 Abc St",
|
|
311
|
-
"id": "1",
|
|
312
|
-
"name": "trevor",
|
|
313
|
-
},
|
|
314
|
-
},
|
|
315
|
-
}
|
|
316
|
-
`);
|
|
317
|
-
expect(queryPlan).toMatchInlineSnapshot(`
|
|
318
|
-
QueryPlan {
|
|
319
|
-
Parallel {
|
|
320
|
-
Sequence {
|
|
321
|
-
Fetch(service: "firstService") {
|
|
322
|
-
{
|
|
323
|
-
valueType {
|
|
324
|
-
id
|
|
325
|
-
user {
|
|
326
|
-
__typename
|
|
327
|
-
id
|
|
328
|
-
name
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
},
|
|
333
|
-
Flatten(path: "valueType.user") {
|
|
334
|
-
Fetch(service: "userService") {
|
|
335
|
-
{
|
|
336
|
-
... on User {
|
|
337
|
-
__typename
|
|
338
|
-
id
|
|
339
|
-
}
|
|
340
|
-
} =>
|
|
341
|
-
{
|
|
342
|
-
... on User {
|
|
343
|
-
address
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
},
|
|
347
|
-
},
|
|
348
|
-
},
|
|
349
|
-
Sequence {
|
|
350
|
-
Fetch(service: "secondService") {
|
|
351
|
-
{
|
|
352
|
-
otherValueType {
|
|
353
|
-
id
|
|
354
|
-
user {
|
|
355
|
-
__typename
|
|
356
|
-
id
|
|
357
|
-
name
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
},
|
|
362
|
-
Flatten(path: "otherValueType.user") {
|
|
363
|
-
Fetch(service: "userService") {
|
|
364
|
-
{
|
|
365
|
-
... on User {
|
|
366
|
-
__typename
|
|
367
|
-
id
|
|
368
|
-
}
|
|
369
|
-
} =>
|
|
370
|
-
{
|
|
371
|
-
... on User {
|
|
372
|
-
address
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
},
|
|
376
|
-
},
|
|
377
|
-
},
|
|
378
|
-
},
|
|
379
|
-
}
|
|
380
|
-
`);
|
|
381
|
-
});
|
|
382
|
-
});
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { execute } from '../execution-utils';
|
|
2
|
-
|
|
3
|
-
it('passes variables to root fields', async () => {
|
|
4
|
-
const query = `#graphql
|
|
5
|
-
query GetProduct($upc: String!) {
|
|
6
|
-
product(upc: $upc) {
|
|
7
|
-
name
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
`;
|
|
11
|
-
|
|
12
|
-
const upc = '1';
|
|
13
|
-
const { data, errors, queryPlan } = await execute({
|
|
14
|
-
query,
|
|
15
|
-
variables: { upc },
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
expect(errors).toBeUndefined();
|
|
19
|
-
expect(data).toEqual({
|
|
20
|
-
product: {
|
|
21
|
-
name: 'Table',
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
expect(queryPlan).toCallService('product');
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('supports default variables in a variable definition', async () => {
|
|
29
|
-
const query = `#graphql
|
|
30
|
-
query GetProduct($upc: String = "1") {
|
|
31
|
-
product(upc: $upc) {
|
|
32
|
-
name
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
`;
|
|
36
|
-
|
|
37
|
-
const { data, errors, queryPlan } = await execute({
|
|
38
|
-
query,
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
expect(errors).toBeUndefined();
|
|
42
|
-
expect(data).toEqual({
|
|
43
|
-
product: {
|
|
44
|
-
name: 'Table',
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
expect(queryPlan).toCallService('product');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('passes variables to nested services', async () => {
|
|
52
|
-
const query = `#graphql
|
|
53
|
-
query GetProductsForUser($format: Boolean) {
|
|
54
|
-
me {
|
|
55
|
-
reviews {
|
|
56
|
-
body(format: $format)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
`;
|
|
61
|
-
|
|
62
|
-
const format = true;
|
|
63
|
-
const { data, errors, queryPlan } = await execute({
|
|
64
|
-
query,
|
|
65
|
-
variables: { format },
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
expect(errors).toBeUndefined();
|
|
69
|
-
expect(data).toEqual({
|
|
70
|
-
me: {
|
|
71
|
-
reviews: [
|
|
72
|
-
{ body: 'Love it!' },
|
|
73
|
-
{ body: 'Too expensive.' },
|
|
74
|
-
{
|
|
75
|
-
body: 'A classic.',
|
|
76
|
-
},
|
|
77
|
-
],
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
expect(queryPlan).toCallService('accounts');
|
|
82
|
-
expect(queryPlan).toCallService('reviews');
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('works with default variables in the schema', async () => {
|
|
86
|
-
const query = `#graphql
|
|
87
|
-
query LibraryUser($libraryId: ID!, $userId: ID) {
|
|
88
|
-
library(id: $libraryId) {
|
|
89
|
-
userAccount(id: $userId) {
|
|
90
|
-
id
|
|
91
|
-
name {
|
|
92
|
-
first
|
|
93
|
-
last
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
`;
|
|
99
|
-
|
|
100
|
-
const { data, queryPlan, errors } = await execute({
|
|
101
|
-
query,
|
|
102
|
-
variables: { libraryId: '1' },
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
expect(data).toEqual({
|
|
106
|
-
library: {
|
|
107
|
-
userAccount: {
|
|
108
|
-
id: '1',
|
|
109
|
-
name: {
|
|
110
|
-
first: 'Ada',
|
|
111
|
-
last: 'Lovelace',
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
expect(errors).toBeUndefined();
|
|
118
|
-
expect(queryPlan).toCallService('books');
|
|
119
|
-
expect(queryPlan).toCallService('accounts');
|
|
120
|
-
});
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import nock from 'nock';
|
|
2
|
-
|
|
3
|
-
// Ensures an active and clean nock before every test
|
|
4
|
-
export function nockBeforeEach() {
|
|
5
|
-
if (!nock.isActive()) {
|
|
6
|
-
nock.activate();
|
|
7
|
-
}
|
|
8
|
-
// Cleaning _before_ each test ensures that any mocks from a previous test
|
|
9
|
-
// which failed don't affect the current test.
|
|
10
|
-
nock.cleanAll();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// Ensures a test is complete (all expected requests were run) and a clean
|
|
14
|
-
// global state after each test.
|
|
15
|
-
export function nockAfterEach() {
|
|
16
|
-
// unmock HTTP interceptor
|
|
17
|
-
nock.restore();
|
|
18
|
-
// effectively nock.isDone() but with more helpful messages in test failures
|
|
19
|
-
expect(nock.activeMocks()).toEqual([]);
|
|
20
|
-
};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import gql from 'graphql-tag';
|
|
2
|
-
import { defineFeature, loadFeature } from 'jest-cucumber';
|
|
3
|
-
import { DocumentNode } from 'graphql';
|
|
4
|
-
|
|
5
|
-
import { QueryPlan } from '@apollo/query-planner';
|
|
6
|
-
import { getFederatedTestingSchema } from './execution-utils';
|
|
7
|
-
import { operationFromDocument } from '@apollo/federation-internals';
|
|
8
|
-
|
|
9
|
-
const buildQueryPlanFeature = loadFeature(
|
|
10
|
-
'./gateway-js/src/__tests__/build-query-plan.feature'
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const features = [
|
|
15
|
-
buildQueryPlanFeature
|
|
16
|
-
];
|
|
17
|
-
|
|
18
|
-
features.forEach((feature) => {
|
|
19
|
-
defineFeature(feature, (test) => {
|
|
20
|
-
feature.scenarios.forEach((scenario) => {
|
|
21
|
-
test(scenario.title, async ({ given, then }) => {
|
|
22
|
-
let operationDocument: DocumentNode;
|
|
23
|
-
let queryPlan: QueryPlan;
|
|
24
|
-
|
|
25
|
-
// throws on composition errors
|
|
26
|
-
const { schema, queryPlanner } = getFederatedTestingSchema();
|
|
27
|
-
|
|
28
|
-
const givenQuery = () => {
|
|
29
|
-
given(/^query$/im, (operation: string) => {
|
|
30
|
-
operationDocument = gql(operation);
|
|
31
|
-
})
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const thenQueryPlanShouldBe = () => {
|
|
35
|
-
then(/^query plan$/i, (expectedQueryPlan: string) => {
|
|
36
|
-
queryPlan = queryPlanner.buildQueryPlan(operationFromDocument(schema, operationDocument));
|
|
37
|
-
|
|
38
|
-
const parsedExpectedPlan = JSON.parse(expectedQueryPlan);
|
|
39
|
-
|
|
40
|
-
expect(queryPlan).toEqual(parsedExpectedPlan);
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// step over each defined step in the .feature and execute the correct
|
|
45
|
-
// matching step fn defined above
|
|
46
|
-
scenario.steps.forEach(({ stepText }) => {
|
|
47
|
-
const title = stepText.toLocaleLowerCase();
|
|
48
|
-
if (title === "query") givenQuery();
|
|
49
|
-
else if (title === "query plan") thenQueryPlanShouldBe();
|
|
50
|
-
else throw new Error(`Unrecognized steps used in "build-query-plan.feature"`);
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
});
|