@apollo/gateway 2.3.4 → 2.4.0-alpha.1

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.
@@ -16,7 +16,7 @@ import {
16
16
  } from 'apollo-federation-integration-testsuite';
17
17
  import { QueryPlan, QueryPlanner } from '@apollo/query-planner';
18
18
  import { ApolloGateway } from '..';
19
- import { ApolloServerBase as ApolloServer } from 'apollo-server-core';
19
+ import { ApolloServer } from '@apollo/server';
20
20
  import { getFederatedTestingSchema } from './execution-utils';
21
21
  import { Schema, Operation, parseOperation, buildSchemaFromAST, arrayEquals } from '@apollo/federation-internals';
22
22
  import {
@@ -24,6 +24,7 @@ import {
24
24
  GraphQLResolverMap,
25
25
  } from '@apollo/subgraph/src/schema-helper';
26
26
  import {GatewayExecutionResult, GatewayGraphQLRequestContext} from '@apollo/server-gateway-interface';
27
+ import { unwrapSingleResultKind } from './gateway/testUtils';
27
28
 
28
29
  expect.addSnapshotSerializer(astSerializer);
29
30
  expect.addSnapshotSerializer(queryPlanSerializer);
@@ -1325,13 +1326,12 @@ describe('executeQueryPlan', () => {
1325
1326
  // But note that this is only one possible initialization path for the
1326
1327
  // gateway, and with the current duplication of logic we'd actually need
1327
1328
  // to test other scenarios (like loading from supergraph SDL) separately.
1328
- const gateway = new ApolloGateway({
1329
- supergraphSdl: print(superGraphWithInaccessible),
1329
+ const server = new ApolloServer({
1330
+ gateway: new ApolloGateway({
1331
+ supergraphSdl: print(superGraphWithInaccessible),
1332
+ }),
1330
1333
  });
1331
-
1332
- const { schema, executor } = await gateway.load();
1333
-
1334
- const server = new ApolloServer({ schema, executor });
1334
+ await server.start();
1335
1335
 
1336
1336
  const query = `#graphql
1337
1337
  query {
@@ -1349,10 +1349,22 @@ describe('executeQueryPlan', () => {
1349
1349
  query,
1350
1350
  });
1351
1351
 
1352
- expect(response.data).toBeUndefined();
1353
- expect(response.errors).toMatchInlineSnapshot(`
1352
+ const { errors, data } = unwrapSingleResultKind(response);
1353
+ expect(data).toBeUndefined();
1354
+ expect(errors).toMatchInlineSnapshot(`
1354
1355
  Array [
1355
- [ValidationError: Cannot query field "ssn" on type "User".],
1356
+ Object {
1357
+ "extensions": Object {
1358
+ "code": "GRAPHQL_VALIDATION_FAILED",
1359
+ },
1360
+ "locations": Array [
1361
+ Object {
1362
+ "column": 15,
1363
+ "line": 7,
1364
+ },
1365
+ ],
1366
+ "message": "Cannot query field \\"ssn\\" on type \\"User\\".",
1367
+ },
1356
1368
  ]
1357
1369
  `);
1358
1370
  });
@@ -3817,7 +3829,7 @@ describe('executeQueryPlan', () => {
3817
3829
  name: 'S1',
3818
3830
  typeDefs: gql`
3819
3831
  extend schema
3820
- @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"])
3832
+ @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key"])
3821
3833
 
3822
3834
  type Query {
3823
3835
  iFromS1: I
@@ -3863,7 +3875,7 @@ describe('executeQueryPlan', () => {
3863
3875
  name: 'S2',
3864
3876
  typeDefs: gql`
3865
3877
  extend schema
3866
- @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key", "@interfaceObject"])
3878
+ @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key", "@interfaceObject"])
3867
3879
 
3868
3880
  type Query {
3869
3881
  iFromS2: I
@@ -4207,7 +4219,7 @@ describe('executeQueryPlan', () => {
4207
4219
  // any specific extra resolving.
4208
4220
  const tester = defineSchema({});
4209
4221
 
4210
- let { plan, response } = await tester(`
4222
+ const { plan, response } = await tester(`
4211
4223
  query {
4212
4224
  iFromS2 {
4213
4225
  y
@@ -4242,7 +4254,7 @@ describe('executeQueryPlan', () => {
4242
4254
  s1: { iResolveReferenceExtra: (id: string) => ({ __typename: id === 'idA' ? 'A' : 'B' }), },
4243
4255
  });
4244
4256
 
4245
- let { plan, response } = await tester(`
4257
+ const { plan, response } = await tester(`
4246
4258
  query {
4247
4259
  iFromS2 {
4248
4260
  ... on B {
@@ -4329,7 +4341,7 @@ describe('executeQueryPlan', () => {
4329
4341
  name: 'products',
4330
4342
  typeDefs: gql`
4331
4343
  extend schema
4332
- @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"])
4344
+ @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key"])
4333
4345
 
4334
4346
  type Query {
4335
4347
  products: [Product!]!
@@ -4378,7 +4390,7 @@ describe('executeQueryPlan', () => {
4378
4390
  name: 'reviews',
4379
4391
  typeDefs: gql`
4380
4392
  extend schema
4381
- @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key", "@interfaceObject"])
4393
+ @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key", "@interfaceObject"])
4382
4394
 
4383
4395
  type Query {
4384
4396
  allReviewedProducts: [Product!]!
@@ -17,7 +17,7 @@ import { queryPlanSerializer, astSerializer } from 'apollo-federation-integratio
17
17
  import gql from 'graphql-tag';
18
18
  import { fixtures } from 'apollo-federation-integration-testsuite';
19
19
  import { composeServices } from '@apollo/composition';
20
- import { buildSchema, operationFromDocument, ServiceDefinition } from '@apollo/federation-internals';
20
+ import { buildSchema, Operation, operationFromDocument, ServiceDefinition } from '@apollo/federation-internals';
21
21
  import { GatewayExecutionResult, GatewayGraphQLRequest } from '@apollo/server-gateway-interface';
22
22
 
23
23
  const prettyFormat = require('pretty-format');
@@ -39,7 +39,7 @@ export async function execute(
39
39
  request: GatewayGraphQLRequest,
40
40
  services: ServiceDefinitionModule[] = fixtures,
41
41
  logger: Logger = console,
42
- ): Promise<GatewayExecutionResult & { queryPlan: QueryPlan }> {
42
+ ): Promise<GatewayExecutionResult & { queryPlan: QueryPlan, operation: Operation }> {
43
43
  const serviceMap = Object.fromEntries(
44
44
  services.map(({ name, typeDefs, resolvers }) => {
45
45
  return [
@@ -79,7 +79,7 @@ export async function execute(
79
79
  apiSchema,
80
80
  );
81
81
 
82
- return { ...result, queryPlan };
82
+ return { ...result, queryPlan, operation };
83
83
  }
84
84
 
85
85
  export function buildLocalService(modules: GraphQLSchemaModule[]) {
@@ -1,12 +1,13 @@
1
1
  import nock from 'nock';
2
2
 
3
- import { ApolloServerBase as ApolloServer } from 'apollo-server-core';
3
+ import { ApolloServer } from '@apollo/server';
4
4
 
5
5
  import { RemoteGraphQLDataSource } from '../../datasources/RemoteGraphQLDataSource';
6
6
  import { ApolloGateway, SERVICE_DEFINITION_QUERY } from '../../';
7
7
  import { fixtures } from 'apollo-federation-integration-testsuite';
8
8
  import { GraphQLDataSourceRequestKind } from '../../datasources/types';
9
9
  import { nockAfterEach, nockBeforeEach } from '../nockAssertions';
10
+ import { unwrapSingleResultKind } from '../gateway/testUtils';
10
11
 
11
12
  beforeEach(nockBeforeEach);
12
13
  afterEach(nockAfterEach);
@@ -62,15 +63,10 @@ it('correctly passes the context from ApolloServer to datasources', async () =>
62
63
  },
63
64
  });
64
65
 
65
- const { schema, executor } = await gateway.load();
66
-
67
66
  const server = new ApolloServer({
68
- schema,
69
- executor,
70
- context: () => ({
71
- userId: '1234',
72
- }),
67
+ gateway,
73
68
  });
69
+ await server.start();
74
70
 
75
71
  const query = `#graphql
76
72
  {
@@ -97,12 +93,20 @@ it('correctly passes the context from ApolloServer to datasources', async () =>
97
93
  replyHeaders,
98
94
  );
99
95
 
100
- const result = await server.executeOperation({
101
- query,
102
- });
96
+ const result = await server.executeOperation(
97
+ {
98
+ query,
99
+ },
100
+ {
101
+ contextValue: {
102
+ userId: '1234',
103
+ },
104
+ },
105
+ );
103
106
 
104
- expect(result.errors).toBeUndefined();
105
- expect(result.data).toEqual({
107
+ const { data, errors } = unwrapSingleResultKind(result);
108
+ expect(errors).toBeUndefined();
109
+ expect(data).toEqual({
106
110
  me: { username: '@jbaxleyiii' },
107
111
  });
108
112
  });
@@ -1,68 +1,49 @@
1
- import { buildSubgraphSchema } from '@apollo/subgraph';
2
- import { ApolloServer } from 'apollo-server';
3
- import fetch, { Response } from 'node-fetch';
4
- import { ApolloGateway } from '../..';
5
1
  import { fixtures } from 'apollo-federation-integration-testsuite';
6
- import { ApolloServerPluginInlineTrace } from 'apollo-server-core';
7
- import { GraphQLSchemaModule } from '@apollo/subgraph/src/schema-helper';
8
- import { buildSchema, ObjectType, ServiceDefinition } from '@apollo/federation-internals';
2
+ import { buildSchema, ObjectType } from '@apollo/federation-internals';
9
3
  import gql from 'graphql-tag';
10
4
  import { printSchema } from 'graphql';
5
+ import { startSubgraphsAndGateway, Services } from './testUtils'
6
+ import { InMemoryLRUCache } from '@apollo/utils.keyvaluecache';
7
+ import { QueryPlan } from '@apollo/query-planner';
8
+ import { createHash } from '@apollo/utils.createhash';
11
9
 
12
- async function startFederatedServer(modules: GraphQLSchemaModule[]) {
13
- const schema = buildSubgraphSchema(modules);
14
- const server = new ApolloServer({
15
- schema,
16
- // Manually installing the inline trace plugin means it doesn't log a message.
17
- plugins: [ApolloServerPluginInlineTrace()],
18
- });
19
- const { url } = await server.listen({ port: 0 });
20
- return { url, server };
21
- }
22
-
23
- let backendServers: ApolloServer[];
24
- let gateway: ApolloGateway;
25
- let gatewayServer: ApolloServer;
26
- let gatewayUrl: string;
27
-
28
- async function startServicesAndGateway(servicesDefs: ServiceDefinition[]) {
29
- backendServers = [];
30
- const serviceList = [];
31
- for (const serviceDef of servicesDefs) {
32
- const { server, url } = await startFederatedServer([serviceDef]);
33
- backendServers.push(server);
34
- serviceList.push({ name: serviceDef.name, url });
35
- }
36
-
37
- gateway = new ApolloGateway({ serviceList });
38
- gatewayServer = new ApolloServer({
39
- gateway,
40
- });
41
- ({ url: gatewayUrl } = await gatewayServer.listen({ port: 0 }));
10
+ function approximateObjectSize<T>(obj: T): number {
11
+ return Buffer.byteLength(JSON.stringify(obj), 'utf8');
42
12
  }
43
13
 
44
- async function queryGateway(query: string): Promise<Response> {
45
- return fetch(gatewayUrl, {
46
- method: 'POST',
47
- headers: {
48
- 'Content-Type': 'application/json',
49
- },
50
- body: JSON.stringify({ query }),
51
- });
52
- }
14
+ let services: Services;
53
15
 
54
16
  afterEach(async () => {
55
- for (const server of backendServers) {
56
- await server.stop();
57
- }
58
- if (gatewayServer) {
59
- await gatewayServer.stop();
17
+ if (services) {
18
+ await services.stop();
60
19
  }
61
20
  });
62
21
 
22
+
63
23
  describe('caching', () => {
24
+ const cache = new InMemoryLRUCache<QueryPlan>({maxSize: Math.pow(2, 20) * (30), sizeCalculation: approximateObjectSize});
64
25
  beforeEach(async () => {
65
- await startServicesAndGateway(fixtures);
26
+ services = await startSubgraphsAndGateway(fixtures, { gatewayConfig: { queryPlannerConfig: { cache } } });
27
+ });
28
+
29
+ it(`cached query plan`, async () => {
30
+ const query = `
31
+ query {
32
+ me {
33
+ name {
34
+ first
35
+ last
36
+ }
37
+ }
38
+ topProducts {
39
+ name
40
+ }
41
+ }
42
+ `;
43
+
44
+ await services.queryGateway(query);
45
+ const queryHash:string = createHash('sha256').update(query).digest('hex');
46
+ expect(await cache.get(queryHash)).toBeTruthy();
66
47
  });
67
48
 
68
49
  it(`cache control`, async () => {
@@ -80,7 +61,7 @@ describe('caching', () => {
80
61
  }
81
62
  `;
82
63
 
83
- const response = await queryGateway(query);
64
+ const response = await services.queryGateway(query);
84
65
  const result = await response.json();
85
66
  expect(result).toMatchInlineSnapshot(`
86
67
  Object {
@@ -134,7 +115,7 @@ describe('caching', () => {
134
115
  }
135
116
  `;
136
117
 
137
- const response = await queryGateway(query);
118
+ const response = await services.queryGateway(query);
138
119
  const result = await response.json();
139
120
  expect(result).toMatchInlineSnapshot(`
140
121
  Object {
@@ -167,7 +148,7 @@ describe('caching', () => {
167
148
  },
168
149
  }
169
150
  `);
170
- expect(response.headers.get('cache-control')).toBe(null);
151
+ expect(response.headers.get('cache-control')).toBe('no-store');
171
152
  });
172
153
  });
173
154
 
@@ -185,8 +166,8 @@ describe('end-to-end features', () => {
185
166
  typeDefs: gql`
186
167
  extend schema
187
168
  @link(
188
- url: "https://specs.apollo.dev/federation/v2.0",
189
- import: [ "@key", { name: "@tag", as: "@federationTag"} ]
169
+ url: "https://specs.apollo.dev/federation/v2.0"
170
+ import: ["@key", { name: "@tag", as: "@federationTag" }]
190
171
  )
191
172
 
192
173
  type Query {
@@ -202,10 +183,10 @@ describe('end-to-end features', () => {
202
183
  Query: {
203
184
  t: () => ({
204
185
  k: 42,
205
- x: 1
186
+ x: 1,
206
187
  }),
207
- }
208
- }
188
+ },
189
+ },
209
190
  };
210
191
 
211
192
  const subgraphB = {
@@ -214,8 +195,8 @@ describe('end-to-end features', () => {
214
195
  typeDefs: gql`
215
196
  extend schema
216
197
  @link(
217
- url: "https://specs.apollo.dev/federation/v2.0",
218
- import: [ "@key", { name: "@tag", as: "@federationTag"} ]
198
+ url: "https://specs.apollo.dev/federation/v2.0"
199
+ import: ["@key", { name: "@tag", as: "@federationTag" }]
219
200
  )
220
201
 
221
202
  type T @key(fields: "k") {
@@ -226,13 +207,13 @@ describe('end-to-end features', () => {
226
207
  resolvers: {
227
208
  T: {
228
209
  __resolveReference: ({ k }: { k: string }) => {
229
- return k === '42' ? ({ y: 2 }) : undefined;
210
+ return k === '42' ? { y: 2 } : undefined;
230
211
  },
231
- }
232
- }
212
+ },
213
+ },
233
214
  };
234
215
 
235
- await startServicesAndGateway([subgraphA, subgraphB]);
216
+ services = await startSubgraphsAndGateway([subgraphA, subgraphB]);
236
217
 
237
218
  const query = `
238
219
  {
@@ -243,7 +224,7 @@ describe('end-to-end features', () => {
243
224
  }
244
225
  `;
245
226
 
246
- const response = await queryGateway(query);
227
+ const response = await services.queryGateway(query);
247
228
  const result = await response.json();
248
229
  expect(result).toMatchInlineSnapshot(`
249
230
  Object {
@@ -256,12 +237,16 @@ describe('end-to-end features', () => {
256
237
  }
257
238
  `);
258
239
 
259
- const supergraphSdl = gateway.__testing().supergraphSdl;
240
+ const supergraphSdl = services.gateway.__testing().supergraphSdl;
260
241
  expect(supergraphSdl).toBeDefined();
261
242
  const supergraph = buildSchema(supergraphSdl!);
262
243
  const typeT = supergraph.type('T') as ObjectType;
263
- expect(typeT.field('x')?.appliedDirectivesOf('federationTag').toString()).toStrictEqual('@federationTag(name: "Important")');
264
- expect(typeT.field('y')?.appliedDirectivesOf('federationTag').toString()).toStrictEqual('@federationTag(name: "Less Important")');
244
+ expect(
245
+ typeT.field('x')?.appliedDirectivesOf('federationTag').toString(),
246
+ ).toStrictEqual('@federationTag(name: "Important")');
247
+ expect(
248
+ typeT.field('y')?.appliedDirectivesOf('federationTag').toString(),
249
+ ).toStrictEqual('@federationTag(name: "Less Important")');
265
250
  });
266
251
 
267
252
  it('handles fed1 schema', async () => {
@@ -282,10 +267,10 @@ describe('end-to-end features', () => {
282
267
  Query: {
283
268
  t: () => ({
284
269
  k: 42,
285
- x: 1
270
+ x: 1,
286
271
  }),
287
- }
288
- }
272
+ },
273
+ },
289
274
  };
290
275
 
291
276
  const subgraphB = {
@@ -300,13 +285,13 @@ describe('end-to-end features', () => {
300
285
  resolvers: {
301
286
  T: {
302
287
  __resolveReference: ({ k }: { k: string }) => {
303
- return k === '42' ? ({ y: 2 }) : undefined;
288
+ return k === '42' ? { y: 2 } : undefined;
304
289
  },
305
- }
306
- }
290
+ },
291
+ },
307
292
  };
308
293
 
309
- await startServicesAndGateway([subgraphA, subgraphB]);
294
+ services = await startSubgraphsAndGateway([subgraphA, subgraphB]);
310
295
 
311
296
  const query = `
312
297
  {
@@ -317,7 +302,7 @@ describe('end-to-end features', () => {
317
302
  }
318
303
  `;
319
304
 
320
- const response = await queryGateway(query);
305
+ const response = await services.queryGateway(query);
321
306
  const result = await response.json();
322
307
  expect(result).toMatchInlineSnapshot(`
323
308
  Object {
@@ -338,8 +323,8 @@ describe('end-to-end features', () => {
338
323
  typeDefs: gql`
339
324
  extend schema
340
325
  @link(
341
- url: "https://specs.apollo.dev/federation/v2.0",
342
- import: [ "@key", "@shareable", "@inaccessible"]
326
+ url: "https://specs.apollo.dev/federation/v2.0"
327
+ import: ["@key", "@shareable", "@inaccessible"]
343
328
  )
344
329
 
345
330
  type Query {
@@ -369,9 +354,9 @@ describe('end-to-end features', () => {
369
354
  }),
370
355
  f: (_: any, args: any) => {
371
356
  return args.e === 'FOO' ? 0 : 1;
372
- }
373
- }
374
- }
357
+ },
358
+ },
359
+ },
375
360
  };
376
361
 
377
362
  const subgraphB = {
@@ -380,8 +365,8 @@ describe('end-to-end features', () => {
380
365
  typeDefs: gql`
381
366
  extend schema
382
367
  @link(
383
- url: "https://specs.apollo.dev/federation/v2.0",
384
- import: [ "@key", "@shareable", "@inaccessible" ]
368
+ url: "https://specs.apollo.dev/federation/v2.0"
369
+ import: ["@key", "@shareable", "@inaccessible"]
385
370
  )
386
371
 
387
372
  type T @key(fields: "k") {
@@ -393,13 +378,13 @@ describe('end-to-end features', () => {
393
378
  resolvers: {
394
379
  T: {
395
380
  __resolveReference: ({ k }: { k: string }) => {
396
- return k === '42' ? ({ c: 'foo', d: 'bar' }) : undefined;
381
+ return k === '42' ? { c: 'foo', d: 'bar' } : undefined;
397
382
  },
398
- }
399
- }
383
+ },
384
+ },
400
385
  };
401
386
 
402
- await startServicesAndGateway([subgraphA, subgraphB]);
387
+ services = await startSubgraphsAndGateway([subgraphA, subgraphB]);
403
388
 
404
389
  const q1 = `
405
390
  {
@@ -411,7 +396,7 @@ describe('end-to-end features', () => {
411
396
  }
412
397
  `;
413
398
 
414
- const resp1 = await queryGateway(q1);
399
+ const resp1 = await services.queryGateway(q1);
415
400
  const res1 = await resp1.json();
416
401
  expect(res1).toMatchInlineSnapshot(`
417
402
  Object {
@@ -426,7 +411,7 @@ describe('end-to-end features', () => {
426
411
  `);
427
412
 
428
413
  // Make sure the exposed API doesn't have any @inaccessible elements.
429
- expect(printSchema(gateway.schema!)).toMatchInlineSnapshot(`
414
+ expect(printSchema(services.gateway.schema!)).toMatchInlineSnapshot(`
430
415
  "enum E {
431
416
  FOO
432
417
  }
@@ -449,7 +434,7 @@ describe('end-to-end features', () => {
449
434
  f(e: BAR)
450
435
  }
451
436
  `;
452
- const resp2 = await queryGateway(q2);
437
+ const resp2 = await services.queryGateway(q2);
453
438
  const res2 = await resp2.json();
454
439
  expect(res2).toMatchInlineSnapshot(`
455
440
  Object {
@@ -458,6 +443,12 @@ describe('end-to-end features', () => {
458
443
  "extensions": Object {
459
444
  "code": "GRAPHQL_VALIDATION_FAILED",
460
445
  },
446
+ "locations": Array [
447
+ Object {
448
+ "column": 14,
449
+ "line": 3,
450
+ },
451
+ ],
461
452
  "message": "Value \\"BAR\\" does not exist in \\"E\\" enum.",
462
453
  },
463
454
  ],
@@ -471,7 +462,7 @@ describe('end-to-end features', () => {
471
462
  }
472
463
  }
473
464
  `;
474
- const resp3 = await queryGateway(q3);
465
+ const resp3 = await services.queryGateway(q3);
475
466
  const res3 = await resp3.json();
476
467
  expect(res3).toMatchInlineSnapshot(`
477
468
  Object {
@@ -480,10 +471,16 @@ describe('end-to-end features', () => {
480
471
  "extensions": Object {
481
472
  "code": "GRAPHQL_VALIDATION_FAILED",
482
473
  },
474
+ "locations": Array [
475
+ Object {
476
+ "column": 11,
477
+ "line": 4,
478
+ },
479
+ ],
483
480
  "message": "Cannot query field \\"a\\" on type \\"T\\". Did you mean \\"b\\", \\"d\\", or \\"k\\"?",
484
481
  },
485
482
  ],
486
483
  }
487
484
  `);
488
485
  });
489
- })
486
+ });
@@ -1,11 +1,12 @@
1
1
  import gql from 'graphql-tag';
2
- import { ApolloServerBase as ApolloServer } from 'apollo-server-core';
2
+ import { ApolloServer } from '@apollo/server';
3
3
  import { buildSubgraphSchema } from '@apollo/subgraph';
4
4
 
5
5
  import { LocalGraphQLDataSource } from '../../datasources/LocalGraphQLDataSource';
6
6
  import { ApolloGateway } from '../../';
7
7
  import { fixtures } from 'apollo-federation-integration-testsuite';
8
8
  import { QueryPlanner } from '@apollo/query-planner';
9
+ import { unwrapSingleResultKind } from '../gateway/testUtils';
9
10
 
10
11
  it('caches the query plan for a request', async () => {
11
12
  const buildQueryPlanSpy = jest.spyOn(QueryPlanner.prototype, 'buildQueryPlan');
@@ -23,9 +24,8 @@ it('caches the query plan for a request', async () => {
23
24
  },
24
25
  });
25
26
 
26
- const { schema, executor } = await gateway.load();
27
-
28
- const server = new ApolloServer({ schema, executor });
27
+ const server = new ApolloServer({ gateway });
28
+ await server.start();
29
29
 
30
30
  const upc = '1';
31
31
 
@@ -42,7 +42,8 @@ it('caches the query plan for a request', async () => {
42
42
  variables: { upc },
43
43
  });
44
44
 
45
- expect(result.data).toEqual({
45
+ const { data: result1Data } = unwrapSingleResultKind(result);
46
+ expect(result1Data).toEqual({
46
47
  product: {
47
48
  name: 'Table',
48
49
  },
@@ -53,7 +54,7 @@ it('caches the query plan for a request', async () => {
53
54
  variables: { upc },
54
55
  });
55
56
 
56
- expect(result.data).toEqual(secondResult.data);
57
+ expect(unwrapSingleResultKind(secondResult).data).toEqual(result1Data);
57
58
  expect(buildQueryPlanSpy).toHaveBeenCalledTimes(1);
58
59
  });
59
60
 
@@ -85,24 +86,23 @@ it('supports multiple operations and operationName', async () => {
85
86
  },
86
87
  });
87
88
 
88
- const { schema, executor } = await gateway.load();
89
-
90
- const server = new ApolloServer({ schema, executor });
89
+ const server = new ApolloServer({ gateway });
90
+ await server.start();
91
91
 
92
- const { data: userData } = await server.executeOperation({
92
+ const userResult = await server.executeOperation({
93
93
  query,
94
94
  operationName: 'GetUser',
95
95
  });
96
96
 
97
- const { data: reviewsData } = await server.executeOperation({
97
+ const reviewsResult = await server.executeOperation({
98
98
  query,
99
99
  operationName: 'GetReviews',
100
100
  });
101
101
 
102
- expect(userData).toEqual({
102
+ expect(unwrapSingleResultKind(userResult).data).toEqual({
103
103
  me: { username: '@ada' },
104
104
  });
105
- expect(reviewsData).toEqual({
105
+ expect(unwrapSingleResultKind(reviewsResult).data).toEqual({
106
106
  topReviews: [
107
107
  { body: 'Love it!' },
108
108
  { body: 'Too expensive.' },
@@ -194,9 +194,8 @@ it('does not corrupt cached queryplan data across requests', async () => {
194
194
  },
195
195
  });
196
196
 
197
- const { schema, executor } = await gateway.load();
198
-
199
- const server = new ApolloServer({ schema, executor });
197
+ const server = new ApolloServer({ gateway });
198
+ await server.start();
200
199
 
201
200
  const query1 = `#graphql
202
201
  query UserFavoriteColor {
@@ -225,8 +224,8 @@ it('does not corrupt cached queryplan data across requests', async () => {
225
224
  query: query1,
226
225
  });
227
226
 
228
- expect(result1.errors).toEqual(undefined);
229
- expect(result2.errors).toEqual(undefined);
230
- expect(result3.errors).toEqual(undefined);
227
+ expect(unwrapSingleResultKind(result1).errors).toEqual(undefined);
228
+ expect(unwrapSingleResultKind(result2).errors).toEqual(undefined);
229
+ expect(unwrapSingleResultKind(result3).errors).toEqual(undefined);
231
230
  expect(result1).toEqual(result3);
232
231
  });