@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.
Files changed (67) hide show
  1. package/dist/__generated__/graphqlTypes.d.ts +19 -1
  2. package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
  3. package/dist/__generated__/graphqlTypes.js +1 -0
  4. package/dist/__generated__/graphqlTypes.js.map +1 -1
  5. package/dist/executeQueryPlan.js +1 -1
  6. package/dist/executeQueryPlan.js.map +1 -1
  7. package/package.json +4 -4
  8. package/src/__generated__/graphqlTypes.ts +33 -2
  9. package/src/executeQueryPlan.ts +1 -1
  10. package/src/__mocks__/tsconfig.json +0 -7
  11. package/src/__tests__/.gitkeep +0 -0
  12. package/src/__tests__/CucumberREADME.md +0 -96
  13. package/src/__tests__/build-query-plan.feature +0 -1471
  14. package/src/__tests__/buildQueryPlan.test.ts +0 -1225
  15. package/src/__tests__/executeQueryPlan.conditions.test.ts +0 -1488
  16. package/src/__tests__/executeQueryPlan.introspection.test.ts +0 -140
  17. package/src/__tests__/executeQueryPlan.test.ts +0 -6140
  18. package/src/__tests__/execution-utils.ts +0 -124
  19. package/src/__tests__/gateway/__snapshots__/opentelemetry.test.ts.snap +0 -195
  20. package/src/__tests__/gateway/buildService.test.ts +0 -249
  21. package/src/__tests__/gateway/endToEnd.test.ts +0 -486
  22. package/src/__tests__/gateway/executor.test.ts +0 -96
  23. package/src/__tests__/gateway/extensions.test.ts +0 -37
  24. package/src/__tests__/gateway/lifecycle-hooks.test.ts +0 -239
  25. package/src/__tests__/gateway/opentelemetry.test.ts +0 -123
  26. package/src/__tests__/gateway/queryPlanCache.test.ts +0 -231
  27. package/src/__tests__/gateway/queryPlannerConfig.test.ts +0 -101
  28. package/src/__tests__/gateway/reporting.test.ts +0 -616
  29. package/src/__tests__/gateway/supergraphSdl.test.ts +0 -396
  30. package/src/__tests__/gateway/testUtils.ts +0 -89
  31. package/src/__tests__/integration/abstract-types.test.ts +0 -1861
  32. package/src/__tests__/integration/aliases.test.ts +0 -180
  33. package/src/__tests__/integration/boolean.test.ts +0 -279
  34. package/src/__tests__/integration/complex-key.test.ts +0 -197
  35. package/src/__tests__/integration/configuration.test.ts +0 -404
  36. package/src/__tests__/integration/custom-directives.test.ts +0 -174
  37. package/src/__tests__/integration/execution-style.test.ts +0 -35
  38. package/src/__tests__/integration/fragments.test.ts +0 -237
  39. package/src/__tests__/integration/list-key.test.ts +0 -128
  40. package/src/__tests__/integration/logger.test.ts +0 -122
  41. package/src/__tests__/integration/managed.test.ts +0 -319
  42. package/src/__tests__/integration/merge-arrays.test.ts +0 -34
  43. package/src/__tests__/integration/multiple-key.test.ts +0 -327
  44. package/src/__tests__/integration/mutations.test.ts +0 -287
  45. package/src/__tests__/integration/networkRequests.test.ts +0 -542
  46. package/src/__tests__/integration/nockMocks.ts +0 -157
  47. package/src/__tests__/integration/provides.test.ts +0 -77
  48. package/src/__tests__/integration/requires.test.ts +0 -359
  49. package/src/__tests__/integration/scope.test.ts +0 -557
  50. package/src/__tests__/integration/single-service.test.ts +0 -119
  51. package/src/__tests__/integration/unions.test.ts +0 -79
  52. package/src/__tests__/integration/value-types.test.ts +0 -382
  53. package/src/__tests__/integration/variables.test.ts +0 -120
  54. package/src/__tests__/nockAssertions.ts +0 -20
  55. package/src/__tests__/queryPlanCucumber.test.ts +0 -55
  56. package/src/__tests__/resultShaping.test.ts +0 -605
  57. package/src/__tests__/testSetup.ts +0 -1
  58. package/src/__tests__/tsconfig.json +0 -8
  59. package/src/core/__tests__/core.test.ts +0 -412
  60. package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +0 -51
  61. package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +0 -574
  62. package/src/schema-helper/__tests__/addExtensions.test.ts +0 -70
  63. package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +0 -364
  64. package/src/supergraphManagers/IntrospectAndCompose/__tests__/loadServicesFromRemoteEndpoint.test.ts +0 -40
  65. package/src/supergraphManagers/UplinkSupergraphManager/__tests__/UplinkSupergraphManager.test.ts +0 -65
  66. package/src/supergraphManagers/UplinkSupergraphManager/__tests__/loadSupergraphSdlFromStorage.test.ts +0 -511
  67. package/src/utilities/__tests__/deepMerge.test.ts +0 -77
@@ -1,404 +0,0 @@
1
- import gql from 'graphql-tag';
2
- import http from 'http';
3
- import type { Logger } from '@apollo/utils.logger';
4
- import { ApolloGateway } from '../..';
5
- import {
6
- mockSdlQuerySuccess,
7
- mockSupergraphSdlRequestSuccess,
8
- mockApolloConfig,
9
- mockCloudConfigUrl1,
10
- } from './nockMocks';
11
- import { getTestingSupergraphSdl } from '../execution-utils';
12
- import { fixtures, Fixture } from 'apollo-federation-integration-testsuite';
13
-
14
- let logger: Logger;
15
-
16
- const service: Fixture = {
17
- name: 'accounts',
18
- url: 'http://localhost:4001',
19
- typeDefs: gql`
20
- extend type Query {
21
- me: User
22
- everyone: [User]
23
- }
24
-
25
- "This is my User"
26
- type User @key(fields: "id") {
27
- id: ID!
28
- name: String
29
- username: String
30
- }
31
- `,
32
- };
33
-
34
- beforeEach(() => {
35
- const warn = jest.fn();
36
- const debug = jest.fn();
37
- const error = jest.fn();
38
- const info = jest.fn();
39
-
40
- logger = {
41
- warn,
42
- debug,
43
- error,
44
- info,
45
- };
46
- });
47
-
48
- describe('gateway configuration warnings', () => {
49
- let gateway: ApolloGateway | null = null;
50
- afterEach(async () => {
51
- if (gateway) {
52
- await gateway.stop();
53
- gateway = null;
54
- }
55
- });
56
- it('warns when both supergraphSdl and studio configuration are provided', async () => {
57
- gateway = new ApolloGateway({
58
- supergraphSdl: getTestingSupergraphSdl(),
59
- logger,
60
- });
61
-
62
- await gateway.load(mockApolloConfig);
63
-
64
- expect(logger.warn).toHaveBeenCalledWith(
65
- 'A local gateway configuration is overriding a managed federation configuration.' +
66
- ' To use the managed configuration, do not specify a service list or supergraphSdl locally.',
67
- );
68
- });
69
-
70
- it('warns when both manual update configurations are provided', async () => {
71
- gateway = new ApolloGateway({
72
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
73
- // @ts-ignore
74
- experimental_updateSupergraphSdl: async () => undefined,
75
- experimental_updateServiceDefinitions: async () => undefined,
76
- logger,
77
- });
78
-
79
- expect(logger.warn).toHaveBeenCalledWith(
80
- 'Gateway found two manual update configurations when only one should be ' +
81
- 'provided. Gateway will default to using the provided `experimental_updateSupergraphSdl` ' +
82
- 'function when both `experimental_updateSupergraphSdl` and experimental_updateServiceDefinitions` ' +
83
- 'are provided.',
84
- );
85
-
86
- // Set to `null` so we don't try to call `stop` on it in the `afterEach`,
87
- // which triggers a different error that we're not testing for here.
88
- gateway = null;
89
- });
90
-
91
- it('conflicting configurations are warned about when present', async () => {
92
- mockSdlQuerySuccess(service);
93
-
94
- gateway = new ApolloGateway({
95
- serviceList: [{ name: 'accounts', url: service.url }],
96
- logger,
97
- });
98
-
99
- await gateway.load(mockApolloConfig);
100
-
101
- expect(logger.warn).toHaveBeenCalledWith(
102
- expect.stringMatching(
103
- /A local gateway configuration is overriding a managed federation configuration/,
104
- ),
105
- );
106
- });
107
-
108
- it('conflicting configurations are not warned about when absent', async () => {
109
- mockSupergraphSdlRequestSuccess();
110
-
111
- gateway = new ApolloGateway({
112
- logger,
113
- uplinkEndpoints: [mockCloudConfigUrl1],
114
- });
115
-
116
- await gateway.load(mockApolloConfig);
117
-
118
- await gateway.stop();
119
-
120
- expect(logger.warn).not.toHaveBeenCalledWith(
121
- expect.stringMatching(
122
- /A local gateway configuration is overriding a managed federation configuration/,
123
- ),
124
- );
125
- });
126
-
127
- it('deprecated conflicting configurations are not warned about when absent', async () => {
128
- mockSupergraphSdlRequestSuccess();
129
-
130
- gateway = new ApolloGateway({
131
- logger,
132
- schemaConfigDeliveryEndpoint: mockCloudConfigUrl1,
133
- });
134
-
135
- await gateway.load(mockApolloConfig);
136
-
137
- await gateway.stop();
138
-
139
- expect(logger.warn).not.toHaveBeenCalledWith(
140
- expect.stringMatching(
141
- /A local gateway configuration is overriding a managed federation configuration/,
142
- ),
143
- );
144
- });
145
-
146
- it('throws when no configuration is provided', async () => {
147
- gateway = new ApolloGateway({
148
- logger,
149
- });
150
-
151
- expect(gateway.load()).rejects.toThrowErrorMatchingInlineSnapshot(
152
- `"When a manual configuration is not provided, gateway requires an Apollo configuration. See https://www.apollographql.com/docs/apollo-server/federation/managed-federation/ for more information. Manual configuration options include: \`serviceList\`, \`supergraphSdl\`, and \`experimental_updateServiceDefinitions\`."`,
153
- );
154
-
155
- // Set to `null` so we don't try to call `stop` on it in the `afterEach`,
156
- // which triggers a different error that we're not testing for here.
157
- gateway = null;
158
- });
159
- });
160
-
161
- describe('gateway startup errors', () => {
162
- it("throws when static config can't be composed", async () => {
163
- const uncomposableSdl = gql`
164
- type Query {
165
- me: User
166
- everyone: [User]
167
- account(id: String): Account
168
- }
169
-
170
- type User @key(fields: "id") {
171
- name: String
172
- username: String
173
- }
174
-
175
- type Account @key(fields: "id") {
176
- name: String
177
- username: String
178
- }
179
- `;
180
-
181
- const gateway = new ApolloGateway({
182
- localServiceList: [
183
- { name: 'accounts', url: service.url, typeDefs: uncomposableSdl },
184
- ],
185
- logger,
186
- });
187
-
188
- // This is the ideal, but our version of Jest has a bug with printing error snapshots.
189
- // See: https://github.com/facebook/jest/pull/10217 (fixed in v26.2.0)
190
- // expect(gateway.load()).rejects.toThrowErrorMatchingInlineSnapshot(`
191
- // "A valid schema couldn't be composed. The following composition errors were found:
192
- // [accounts] User -> A @key selects id, but User.id could not be found
193
- // [accounts] Account -> A @key selects id, but Account.id could not be found"
194
- // `);
195
- // Instead we'll just use the regular snapshot matcher...
196
- let err: any;
197
- try {
198
- await gateway.load();
199
- } catch (e) {
200
- err = e;
201
- }
202
-
203
- const expected =
204
- "A valid schema couldn't be composed. The following composition errors were found:\n"
205
- + ' [accounts] On type "User", for @key(fields: "id"): Cannot query field "id" on type "User" (the field should either be added to this subgraph or, if it should not be resolved by this subgraph, you need to add it to this subgraph with @external).\n'
206
- + ' [accounts] On type "Account", for @key(fields: "id"): Cannot query field "id" on type "Account" (the field should either be added to this subgraph or, if it should not be resolved by this subgraph, you need to add it to this subgraph with @external).'
207
- expect(err.message).toBe(expected);
208
- });
209
- });
210
-
211
- describe('gateway config / env behavior', () => {
212
- let gateway: ApolloGateway | null = null;
213
- let cleanUp: (() => void) | null = null;
214
- afterEach(async () => {
215
- if (gateway) {
216
- await gateway.stop();
217
- gateway = null;
218
- }
219
-
220
- if (cleanUp) {
221
- cleanUp();
222
- cleanUp = null;
223
- }
224
- });
225
-
226
- describe('introspection headers', () => {
227
- it('should allow not passing introspectionHeaders', async () => {
228
- const receivedHeaders = jest.fn();
229
- const nock = mockSdlQuerySuccess(service);
230
- nock.on('request', (req: http.ClientRequest) =>
231
- receivedHeaders(req.getHeaders()),
232
- );
233
-
234
- gateway = new ApolloGateway({
235
- serviceList: [{ name: 'accounts', url: service.url }],
236
- });
237
-
238
- await gateway.load(mockApolloConfig);
239
-
240
- expect(receivedHeaders).toHaveBeenCalledWith(
241
- expect.objectContaining({
242
- host: 'localhost:4001',
243
- }),
244
- );
245
- });
246
-
247
- it('should use static headers', async () => {
248
- const receivedHeaders = jest.fn();
249
- const nock = mockSdlQuerySuccess(service);
250
- nock.on('request', (req: http.ClientRequest) =>
251
- receivedHeaders(req.getHeaders()),
252
- );
253
-
254
- gateway = new ApolloGateway({
255
- serviceList: [{ name: 'accounts', url: service.url }],
256
- introspectionHeaders: {
257
- Authorization: 'Bearer static',
258
- },
259
- });
260
-
261
- await gateway.load(mockApolloConfig);
262
-
263
- expect(receivedHeaders).toHaveBeenCalledWith(
264
- expect.objectContaining({
265
- authorization: ['Bearer static'],
266
- }),
267
- );
268
- });
269
-
270
- it('should use dynamic async headers', async () => {
271
- const receivedHeaders = jest.fn();
272
- const nock = mockSdlQuerySuccess(service);
273
- nock.on('request', (req: http.ClientRequest) =>
274
- receivedHeaders(req.getHeaders()),
275
- );
276
-
277
- gateway = new ApolloGateway({
278
- serviceList: [{ name: 'accounts', url: service.url }],
279
- introspectionHeaders: async ({ name }) => ({
280
- Authorization: 'Bearer dynamic-async',
281
- 'X-Service-Name': name,
282
- }),
283
- });
284
-
285
- await gateway.load(mockApolloConfig);
286
-
287
- expect(receivedHeaders).toHaveBeenCalledWith(
288
- expect.objectContaining({
289
- authorization: ['Bearer dynamic-async'],
290
- 'x-service-name': ['accounts'],
291
- }),
292
- );
293
- });
294
-
295
- it('should use dynamic non-async headers', async () => {
296
- const receivedHeaders = jest.fn();
297
- const nock = mockSdlQuerySuccess(service);
298
- nock.on('request', (req: http.ClientRequest) =>
299
- receivedHeaders(req.getHeaders()),
300
- );
301
-
302
- gateway = new ApolloGateway({
303
- serviceList: [{ name: 'accounts', url: service.url }],
304
- introspectionHeaders: ({ name }) => ({
305
- Authorization: 'Bearer dynamic-sync',
306
- 'X-Service-Name': name,
307
- }),
308
- });
309
-
310
- await gateway.load(mockApolloConfig);
311
-
312
- expect(receivedHeaders).toHaveBeenCalledWith(
313
- expect.objectContaining({
314
- authorization: ['Bearer dynamic-sync'],
315
- 'x-service-name': ['accounts'],
316
- }),
317
- );
318
- });
319
- });
320
- });
321
-
322
- describe('deprecation warnings', () => {
323
- it('warns with `experimental_updateSupergraphSdl` option set', async () => {
324
- const gateway = new ApolloGateway({
325
- async experimental_updateSupergraphSdl() {
326
- return {
327
- id: 'supergraph',
328
- supergraphSdl: getTestingSupergraphSdl(),
329
- };
330
- },
331
- logger,
332
- });
333
-
334
- await gateway.load();
335
-
336
- expect(logger.warn).toHaveBeenCalledWith(
337
- 'The `experimental_updateSupergraphSdl` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the function form of the `supergraphSdl` configuration option.',
338
- );
339
-
340
- await gateway.stop();
341
- });
342
-
343
- it('warns with `experimental_updateServiceDefinitions` option set', async () => {
344
- const gateway = new ApolloGateway({
345
- async experimental_updateServiceDefinitions() {
346
- return {
347
- isNewSchema: false,
348
- };
349
- },
350
- logger,
351
- });
352
-
353
- try {
354
- await gateway.load();
355
- // gateway will throw since we're not providing an actual service list, disregard
356
- } catch {}
357
-
358
- expect(logger.warn).toHaveBeenCalledWith(
359
- 'The `experimental_updateServiceDefinitions` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the function form of the `supergraphSdl` configuration option.',
360
- );
361
- });
362
-
363
- it('warns with `serviceList` option set', async () => {
364
- const gateway = new ApolloGateway({
365
- serviceList: [{ name: 'accounts', url: 'http://localhost:4001' }],
366
- logger,
367
- });
368
-
369
- try {
370
- await gateway.load();
371
- // gateway will throw since we haven't mocked these requests, unimportant for this test
372
- } catch {}
373
-
374
- expect(logger.warn).toHaveBeenCalledWith(
375
- 'The `serviceList` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to its replacement `IntrospectAndCompose`. More information on `IntrospectAndCompose` can be found in the documentation.',
376
- );
377
- });
378
-
379
- it('warns with `localServiceList` option set', async () => {
380
- const gateway = new ApolloGateway({
381
- localServiceList: fixtures,
382
- logger,
383
- });
384
-
385
- await gateway.load();
386
-
387
- expect(logger.warn).toHaveBeenCalledWith(
388
- 'The `localServiceList` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the `LocalCompose` supergraph manager exported by `@apollo/gateway`.',
389
- );
390
-
391
- await gateway.stop();
392
- });
393
-
394
- it('warns with `schemaConfigDeliveryEndpoint` option set', async () => {
395
- new ApolloGateway({
396
- schemaConfigDeliveryEndpoint: 'test',
397
- logger,
398
- });
399
-
400
- expect(logger.warn).toHaveBeenCalledWith(
401
- 'The `schemaConfigDeliveryEndpoint` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the equivalent (array form) `uplinkEndpoints` configuration option.',
402
- );
403
- });
404
- });
@@ -1,174 +0,0 @@
1
- import gql from 'graphql-tag';
2
- import { execute } from '../execution-utils';
3
- import {
4
- astSerializer,
5
- queryPlanSerializer,
6
- } from 'apollo-federation-integration-testsuite';
7
- import { fixtures } from 'apollo-federation-integration-testsuite';
8
-
9
- expect.addSnapshotSerializer(astSerializer);
10
- expect.addSnapshotSerializer(queryPlanSerializer);
11
-
12
- describe('custom executable directives', () => {
13
- it('successfully passes directives along in requests to an underlying service', async () => {
14
- const query = `#graphql
15
- query GetReviewers {
16
- topReviews {
17
- body @stream
18
- }
19
- }
20
- `;
21
-
22
- const { errors, queryPlan } = await execute({
23
- query,
24
- });
25
-
26
- expect(errors).toBeUndefined();
27
- expect(queryPlan).toCallService('reviews');
28
- expect(queryPlan).toMatchInlineSnapshot(`
29
- QueryPlan {
30
- Fetch(service: "reviews") {
31
- {
32
- topReviews {
33
- body @stream
34
- }
35
- }
36
- },
37
- }
38
- `);
39
- });
40
-
41
- it('successfully passes directives and their variables along in requests to underlying services', async () => {
42
- const query = `#graphql
43
- query GetReviewers {
44
- topReviews {
45
- body @stream
46
- author @transform(from: "JSON") {
47
- name @stream {
48
- first
49
- last
50
- }
51
- }
52
- }
53
- }
54
- `;
55
-
56
- const { errors, queryPlan } = await execute({
57
- query,
58
- });
59
-
60
- expect(errors).toBeUndefined();
61
- expect(queryPlan).toCallService('reviews');
62
- expect(queryPlan).toCallService('accounts');
63
- expect(queryPlan).toMatchInlineSnapshot(`
64
- QueryPlan {
65
- Sequence {
66
- Fetch(service: "reviews") {
67
- {
68
- topReviews {
69
- body @stream
70
- author @transform(from: "JSON") {
71
- __typename
72
- id
73
- }
74
- }
75
- }
76
- },
77
- Flatten(path: "topReviews.@.author") {
78
- Fetch(service: "accounts") {
79
- {
80
- ... on User {
81
- __typename
82
- id
83
- }
84
- } =>
85
- {
86
- ... on User {
87
- name @stream {
88
- first
89
- last
90
- }
91
- }
92
- }
93
- },
94
- },
95
- },
96
- }
97
- `);
98
- });
99
-
100
- // With relaxed composition, instead of erroring out if a directive is not declared everywhere, we compose but don't
101
- // include the directive in the supergraph and generate a hint. So the following test will complain that @stream
102
- // is unknown in the query. Not that the hints tests do test we properly raise an hint in that case.
103
- it.skip("returns validation errors when directives aren't present across all services", async () => {
104
- const invalidService = {
105
- name: 'invalidService',
106
- typeDefs: gql`
107
- directive @invalid on QUERY
108
- `,
109
- };
110
-
111
- const query = `#graphql
112
- query GetReviewers {
113
- topReviews {
114
- body @stream
115
- }
116
- }
117
- `;
118
-
119
- expect(
120
- execute(
121
- {
122
- query,
123
- },
124
- [...fixtures, invalidService],
125
- ),
126
- ).rejects.toThrowErrorMatchingInlineSnapshot(`
127
- "[@invalid] -> Custom directives must be implemented in every service. The following services do not implement the @invalid directive: accounts, books, documents, inventory, product, reviews.
128
-
129
- [@stream] -> Custom directives must be implemented in every service. The following services do not implement the @stream directive: invalidService.
130
-
131
- [@transform] -> Custom directives must be implemented in every service. The following services do not implement the @transform directive: invalidService."
132
- `);
133
- });
134
-
135
- // Same as previous: we don't of error out on inconsistent execution directives. Here, we instead look at the intersection of locations
136
- // defined, and as that is empty, we don't include the directive in the supergraph (and raise a hint).
137
- // So the following test will complain that @stream is unknown in the query. Not that the hints tests do test we properly raise an hint in that case.
138
- it.skip("returns validation errors when directives aren't identical across all services", async () => {
139
- const invalidService = {
140
- name: 'invalid',
141
- typeDefs: gql`
142
- directive @stream on QUERY
143
- `,
144
- };
145
-
146
- const query = `#graphql
147
- query GetReviewers {
148
- topReviews {
149
- body @stream
150
- }
151
- }
152
- `;
153
-
154
- expect(
155
- execute(
156
- {
157
- query,
158
- },
159
- [...fixtures, invalidService],
160
- ),
161
- ).rejects.toThrowErrorMatchingInlineSnapshot(`
162
- "[@transform] -> Custom directives must be implemented in every service. The following services do not implement the @transform directive: invalid.
163
-
164
- [@stream] -> custom directives must be defined identically across all services. See below for a list of current implementations:
165
- accounts: directive @stream on FIELD
166
- books: directive @stream on FIELD
167
- documents: directive @stream on FIELD
168
- inventory: directive @stream on FIELD
169
- product: directive @stream on FIELD
170
- reviews: directive @stream on FIELD
171
- invalid: directive @stream on QUERY"
172
- `);
173
- });
174
- });
@@ -1,35 +0,0 @@
1
- import { execute } from '../execution-utils';
2
-
3
- describe('query', () => {
4
- it('supports parallel root fields', async () => {
5
- const query = `#graphql
6
- query GetUserAndReviews {
7
- me {
8
- username
9
- }
10
- topReviews {
11
- body
12
- }
13
- }
14
- `;
15
-
16
- const { data, queryPlan } = await execute({
17
- query,
18
- });
19
-
20
- expect(data).toEqual({
21
- me: { username: '@ada' },
22
- topReviews: [
23
- { body: 'Love it!' },
24
- { body: 'Too expensive.' },
25
- { body: 'Could be better.' },
26
- { body: 'Prefer something else.' },
27
- { body: 'Wish I had read this before.' },
28
- ],
29
- });
30
-
31
- expect(queryPlan).toCallService('accounts');
32
- expect(queryPlan).toCallService('reviews');
33
- // FIXME: determine matcher for execution order
34
- });
35
- });