@apollo/gateway 2.4.0-alpha.1 → 2.4.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.
Files changed (30) hide show
  1. package/dist/__generated__/graphqlTypes.d.ts +1 -0
  2. package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
  3. package/dist/__generated__/graphqlTypes.js.map +1 -1
  4. package/dist/dataRewrites.d.ts +5 -0
  5. package/dist/dataRewrites.d.ts.map +1 -0
  6. package/dist/dataRewrites.js +103 -0
  7. package/dist/dataRewrites.js.map +1 -0
  8. package/dist/executeQueryPlan.d.ts.map +1 -1
  9. package/dist/executeQueryPlan.js +41 -110
  10. package/dist/executeQueryPlan.js.map +1 -1
  11. package/dist/resultShaping.js +3 -3
  12. package/dist/resultShaping.js.map +1 -1
  13. package/dist/supergraphManagers/UplinkSupergraphManager/index.js +1 -1
  14. package/dist/supergraphManagers/UplinkSupergraphManager/index.js.map +1 -1
  15. package/package.json +4 -4
  16. package/src/__generated__/graphqlTypes.ts +4 -3
  17. package/src/__tests__/buildQueryPlan.test.ts +0 -1
  18. package/src/__tests__/executeQueryPlan.introspection.test.ts +140 -0
  19. package/src/__tests__/executeQueryPlan.test.ts +269 -5
  20. package/src/__tests__/gateway/buildService.test.ts +2 -2
  21. package/src/__tests__/gateway/supergraphSdl.test.ts +2 -2
  22. package/src/__tests__/integration/complex-key.test.ts +4 -4
  23. package/src/__tests__/integration/list-key.test.ts +2 -2
  24. package/src/__tests__/integration/multiple-key.test.ts +2 -2
  25. package/src/__tests__/integration/requires.test.ts +2 -2
  26. package/src/__tests__/integration/single-service.test.ts +1 -1
  27. package/src/__tests__/integration/value-types.test.ts +13 -16
  28. package/src/dataRewrites.ts +130 -0
  29. package/src/executeQueryPlan.ts +57 -135
  30. package/src/resultShaping.ts +3 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apollo/gateway",
3
- "version": "2.4.0-alpha.1",
3
+ "version": "2.4.1",
4
4
  "description": "Apollo Gateway",
5
5
  "author": "Apollo <packages@apollographql.com>",
6
6
  "main": "dist/index.js",
@@ -25,9 +25,9 @@
25
25
  "access": "public"
26
26
  },
27
27
  "dependencies": {
28
- "@apollo/composition": "2.4.0-alpha.1",
29
- "@apollo/federation-internals": "2.4.0-alpha.1",
30
- "@apollo/query-planner": "2.4.0-alpha.1",
28
+ "@apollo/composition": "2.4.1",
29
+ "@apollo/federation-internals": "2.4.1",
30
+ "@apollo/query-planner": "2.4.1",
31
31
  "@apollo/server-gateway-interface": "^1.1.0",
32
32
  "@apollo/usage-reporting-protobuf": "^4.1.0",
33
33
  "@apollo/utils.createhash": "^2.0.0",
@@ -51,11 +51,11 @@ export type FetchError = {
51
51
  export enum FetchErrorCode {
52
52
  /** This token does not have access to fetch the schema for this ref. Do not retry. */
53
53
  AccessDenied = 'ACCESS_DENIED',
54
- /** This token provided is not a valid graph token. Do not retry */
54
+ /** This token provided is not a valid graph token. Do not retry. */
55
55
  AuthenticationFailed = 'AUTHENTICATION_FAILED',
56
- /** An internal server error occurred. Please retry with some backoff */
56
+ /** An internal server error occurred. Please retry with some backoff. */
57
57
  RetryLater = 'RETRY_LATER',
58
- /** The graphRef passed is not a valid ref or no configuration for that ref is found. Do not retry */
58
+ /** The graphRef passed is not a valid ref or no configuration for that ref is found. Please retry with some backoff, eg in case of undeletion. */
59
59
  UnknownRef = 'UNKNOWN_REF'
60
60
  }
61
61
 
@@ -105,6 +105,7 @@ export type QueryRouterConfigArgs = {
105
105
 
106
106
  export type QueryRouterEntitlementsArgs = {
107
107
  apiKey: Scalars['String'];
108
+ ifAfterId?: InputMaybe<Scalars['ID']>;
108
109
  ref: Scalars['String'];
109
110
  unlessId?: InputMaybe<Scalars['ID']>;
110
111
  };
@@ -465,7 +465,6 @@ describe('buildQueryPlan', () => {
465
465
  });
466
466
  });
467
467
 
468
- // TODO: Ask martijn about the meaning of this test
469
468
  it(`should only add requirements once`, () => {
470
469
  const operationString = `#graphql
471
470
  query {
@@ -0,0 +1,140 @@
1
+ import gql from 'graphql-tag';
2
+ import { getFederatedTestingSchema, ServiceDefinitionModule } from './execution-utils';
3
+ import { Operation, parseOperation, Schema } from "@apollo/federation-internals";
4
+ import { QueryPlan } from '@apollo/query-planner';
5
+ import { LocalGraphQLDataSource } from '../datasources';
6
+ import { GatewayExecutionResult, GatewayGraphQLRequestContext } from '@apollo/server-gateway-interface';
7
+ import { buildOperationContext } from '../operationContext';
8
+ import { executeQueryPlan } from '../executeQueryPlan';
9
+
10
+ function buildRequestContext(variables: Record<string, any>): GatewayGraphQLRequestContext {
11
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
12
+ // @ts-ignore
13
+ return {
14
+ cache: undefined as any,
15
+ context: {},
16
+ request: {
17
+ variables,
18
+ },
19
+ metrics: {},
20
+ };
21
+ }
22
+
23
+ async function executePlan(
24
+ queryPlan: QueryPlan,
25
+ operation: Operation,
26
+ schema: Schema,
27
+ serviceMap: { [serviceName: string]: LocalGraphQLDataSource },
28
+ variables: Record<string, any> = {},
29
+ ): Promise<GatewayExecutionResult> {
30
+ const apiSchema = schema.toAPISchema();
31
+ const operationContext = buildOperationContext({
32
+ schema: apiSchema.toGraphQLJSSchema(),
33
+ operationDocument: gql`${operation.toString()}`,
34
+ });
35
+ return executeQueryPlan(
36
+ queryPlan,
37
+ serviceMap,
38
+ buildRequestContext(variables),
39
+ operationContext,
40
+ schema.toGraphQLJSSchema(),
41
+ apiSchema,
42
+ );
43
+ }
44
+
45
+ describe('handling of introspection queries', () => {
46
+ const typeDefs: ServiceDefinitionModule[] = [
47
+ {
48
+ name: 'S1',
49
+ typeDefs: gql`
50
+ type Query {
51
+ t: [T]
52
+ }
53
+
54
+ interface T {
55
+ id: ID!
56
+ }
57
+
58
+ type T1 implements T @key(fields: "id") {
59
+ id: ID!
60
+ a1: Int
61
+ }
62
+
63
+ type T2 implements T @key(fields: "id") {
64
+ id: ID!
65
+ a2: Int
66
+ }
67
+ `,
68
+ },
69
+ ];
70
+ const { serviceMap, schema, queryPlanner} = getFederatedTestingSchema(typeDefs);
71
+
72
+ it('it handles aliases on introspection fields', async () => {
73
+ const operation = parseOperation(schema, `
74
+ {
75
+ myAlias: __type(name: "T1") {
76
+ kind
77
+ name
78
+ }
79
+ }
80
+ `);
81
+
82
+ const queryPlan = queryPlanner.buildQueryPlan(operation);
83
+ const response = await executePlan(queryPlan, operation, schema, serviceMap);
84
+ expect(response.errors).toBeUndefined();
85
+ expect(response.data).toMatchInlineSnapshot(`
86
+ Object {
87
+ "myAlias": Object {
88
+ "kind": "OBJECT",
89
+ "name": "T1",
90
+ },
91
+ }
92
+ `);
93
+ });
94
+
95
+ it('it handles aliases inside introspection fields', async () => {
96
+ const operation = parseOperation(schema, `
97
+ {
98
+ __type(name: "T1") {
99
+ myKind: kind
100
+ name
101
+ }
102
+ }
103
+ `);
104
+
105
+ const queryPlan = queryPlanner.buildQueryPlan(operation);
106
+ const response = await executePlan(queryPlan, operation, schema, serviceMap);
107
+ expect(response.errors).toBeUndefined();
108
+ expect(response.data).toMatchInlineSnapshot(`
109
+ Object {
110
+ "__type": Object {
111
+ "myKind": "OBJECT",
112
+ "name": "T1",
113
+ },
114
+ }
115
+ `);
116
+ });
117
+
118
+ it('it handles variables passed to introspection fields', async () => {
119
+ const operation = parseOperation(schema, `
120
+ query ($name: String!) {
121
+ __type(name: $name) {
122
+ kind
123
+ name
124
+ }
125
+ }
126
+ `);
127
+
128
+ const queryPlan = queryPlanner.buildQueryPlan(operation);
129
+ const response = await executePlan(queryPlan, operation, schema, serviceMap, { name: "T1" });
130
+ expect(response.errors).toBeUndefined();
131
+ expect(response.data).toMatchInlineSnapshot(`
132
+ Object {
133
+ "__type": Object {
134
+ "kind": "OBJECT",
135
+ "name": "T1",
136
+ },
137
+ }
138
+ `);
139
+ });
140
+ });
@@ -3165,7 +3165,8 @@ describe('executeQueryPlan', () => {
3165
3165
  data {
3166
3166
  __typename
3167
3167
  foo
3168
- ... on Data {
3168
+ ... on Bar {
3169
+ __typename
3169
3170
  bar
3170
3171
  }
3171
3172
  }
@@ -3829,7 +3830,7 @@ describe('executeQueryPlan', () => {
3829
3830
  name: 'S1',
3830
3831
  typeDefs: gql`
3831
3832
  extend schema
3832
- @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key"])
3833
+ @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"])
3833
3834
 
3834
3835
  type Query {
3835
3836
  iFromS1: I
@@ -3875,7 +3876,7 @@ describe('executeQueryPlan', () => {
3875
3876
  name: 'S2',
3876
3877
  typeDefs: gql`
3877
3878
  extend schema
3878
- @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key", "@interfaceObject"])
3879
+ @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key", "@interfaceObject"])
3879
3880
 
3880
3881
  type Query {
3881
3882
  iFromS2: I
@@ -4341,7 +4342,7 @@ describe('executeQueryPlan', () => {
4341
4342
  name: 'products',
4342
4343
  typeDefs: gql`
4343
4344
  extend schema
4344
- @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key"])
4345
+ @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"])
4345
4346
 
4346
4347
  type Query {
4347
4348
  products: [Product!]!
@@ -4390,7 +4391,7 @@ describe('executeQueryPlan', () => {
4390
4391
  name: 'reviews',
4391
4392
  typeDefs: gql`
4392
4393
  extend schema
4393
- @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key", "@interfaceObject"])
4394
+ @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key", "@interfaceObject"])
4394
4395
 
4395
4396
  type Query {
4396
4397
  allReviewedProducts: [Product!]!
@@ -4599,6 +4600,269 @@ describe('executeQueryPlan', () => {
4599
4600
  }
4600
4601
  `);
4601
4602
  });
4603
+
4604
+ test('handles querying @interfaceObject from a specific implementation', async () => {
4605
+ const s1 = {
4606
+ name: 's1',
4607
+ typeDefs: gql`
4608
+ extend schema
4609
+ @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key"])
4610
+
4611
+ type Query {
4612
+ ts: [T!]!
4613
+ }
4614
+
4615
+ interface I {
4616
+ id: ID!
4617
+ }
4618
+
4619
+ type T implements I @key(fields: "id") {
4620
+ id: ID!
4621
+ }
4622
+ `,
4623
+ resolvers: {
4624
+ Query: {
4625
+ ts: () => [ { id: '2' }, { id: '4' }, { id: '1' } ]
4626
+ },
4627
+ }
4628
+ }
4629
+
4630
+ const s2 = {
4631
+ name: 's2',
4632
+ typeDefs: gql`
4633
+ extend schema
4634
+ @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key", "@interfaceObject", "@external", "@requires"])
4635
+
4636
+ type I @key(fields: "id") @interfaceObject {
4637
+ id: ID!
4638
+ v: String
4639
+ }
4640
+ `,
4641
+ resolvers: {
4642
+ I: {
4643
+ __resolveReference(ref: any) {
4644
+ return {
4645
+ ...ref,
4646
+ v: `id=${ref.id}`
4647
+ };
4648
+ },
4649
+ }
4650
+ }
4651
+ }
4652
+
4653
+ const { serviceMap, schema, queryPlanner} = getFederatedTestingSchema([ s1, s2 ]);
4654
+
4655
+ let operation = parseOp(`
4656
+ {
4657
+ ts {
4658
+ v
4659
+ }
4660
+ }
4661
+ `, schema);
4662
+
4663
+ let queryPlan = buildPlan(operation, queryPlanner);
4664
+ const expectedPlan = `
4665
+ QueryPlan {
4666
+ Sequence {
4667
+ Fetch(service: "s1") {
4668
+ {
4669
+ ts {
4670
+ __typename
4671
+ id
4672
+ }
4673
+ }
4674
+ },
4675
+ Flatten(path: "ts.@") {
4676
+ Fetch(service: "s2") {
4677
+ {
4678
+ ... on T {
4679
+ __typename
4680
+ id
4681
+ }
4682
+ } =>
4683
+ {
4684
+ ... on I {
4685
+ v
4686
+ }
4687
+ }
4688
+ },
4689
+ },
4690
+ },
4691
+ }
4692
+ `;
4693
+ expect(queryPlan).toMatchInlineSnapshot(expectedPlan);
4694
+
4695
+ let response = await executePlan(queryPlan, operation, undefined, schema, serviceMap);
4696
+ expect(response.data).toMatchInlineSnapshot(`
4697
+ Object {
4698
+ "ts": Array [
4699
+ Object {
4700
+ "v": "id=2",
4701
+ },
4702
+ Object {
4703
+ "v": "id=4",
4704
+ },
4705
+ Object {
4706
+ "v": "id=1",
4707
+ },
4708
+ ],
4709
+ }
4710
+ `);
4711
+ });
4712
+
4713
+ test('handles querying @interfaceObject from a specific implementation (even when the subgraph does not have the corresponding interface)', async () => {
4714
+ const s1 = {
4715
+ name: 's1',
4716
+ typeDefs: gql`
4717
+ extend schema
4718
+ @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key"])
4719
+
4720
+ type Query {
4721
+ ts: [T!]!
4722
+ }
4723
+
4724
+ type T @key(fields: "id", resolvable: false) {
4725
+ id: ID!
4726
+ }
4727
+ `,
4728
+ resolvers: {
4729
+ Query: {
4730
+ ts: () => [ { id: '2' }, { id: '4' }, { id: '1' } ]
4731
+ },
4732
+ }
4733
+ }
4734
+
4735
+ const s2 = {
4736
+ name: 's2',
4737
+ typeDefs: gql`
4738
+ extend schema
4739
+ @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key", "@interfaceObject"])
4740
+
4741
+ interface I @key(fields: "id") {
4742
+ id: ID!
4743
+ required: String
4744
+ }
4745
+
4746
+ type T implements I @key(fields: "id") {
4747
+ id: ID!
4748
+ required: String
4749
+ }
4750
+
4751
+ `,
4752
+ resolvers: {
4753
+ I: {
4754
+ __resolveReference(ref: any) {
4755
+ return [
4756
+ { id: '1', __typename: "T", required: "r1" },
4757
+ { id: '2', __typename: "T", required: "r2" },
4758
+ { id: '3', __typename: "T", required: "r3" },
4759
+ { id: '4', __typename: "T", required: "r4" },
4760
+ ].find(({id}) => id === ref.id);
4761
+ },
4762
+ },
4763
+ }
4764
+ }
4765
+
4766
+ const s3 = {
4767
+ name: 's3',
4768
+ typeDefs: gql`
4769
+ extend schema
4770
+ @link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key", "@interfaceObject", "@external", "@requires"])
4771
+
4772
+ type I @key(fields: "id") @interfaceObject {
4773
+ id: ID!
4774
+ required: String @external
4775
+ v: String @requires(fields: "required")
4776
+ }
4777
+ `,
4778
+ resolvers: {
4779
+ I: {
4780
+ __resolveReference(ref: any) {
4781
+ return {
4782
+ ...ref,
4783
+ v: `req=${ref.required}`
4784
+ };
4785
+ },
4786
+ }
4787
+ }
4788
+ }
4789
+
4790
+ const { serviceMap, schema, queryPlanner} = getFederatedTestingSchema([ s1, s2, s3 ]);
4791
+
4792
+ let operation = parseOp(`
4793
+ {
4794
+ ts {
4795
+ v
4796
+ }
4797
+ }
4798
+ `, schema);
4799
+
4800
+ let queryPlan = buildPlan(operation, queryPlanner);
4801
+ const expectedPlan = `
4802
+ QueryPlan {
4803
+ Sequence {
4804
+ Fetch(service: "s1") {
4805
+ {
4806
+ ts {
4807
+ __typename
4808
+ id
4809
+ }
4810
+ }
4811
+ },
4812
+ Flatten(path: "ts.@") {
4813
+ Fetch(service: "s2") {
4814
+ {
4815
+ ... on I {
4816
+ __typename
4817
+ id
4818
+ }
4819
+ } =>
4820
+ {
4821
+ ... on I {
4822
+ __typename
4823
+ required
4824
+ }
4825
+ }
4826
+ },
4827
+ },
4828
+ Flatten(path: "ts.@") {
4829
+ Fetch(service: "s3") {
4830
+ {
4831
+ ... on I {
4832
+ __typename
4833
+ required
4834
+ id
4835
+ }
4836
+ } =>
4837
+ {
4838
+ ... on I {
4839
+ v
4840
+ }
4841
+ }
4842
+ },
4843
+ },
4844
+ },
4845
+ }
4846
+ `;
4847
+ expect(queryPlan).toMatchInlineSnapshot(expectedPlan);
4848
+
4849
+ let response = await executePlan(queryPlan, operation, undefined, schema, serviceMap);
4850
+ expect(response.data).toMatchInlineSnapshot(`
4851
+ Object {
4852
+ "ts": Array [
4853
+ Object {
4854
+ "v": "req=r2",
4855
+ },
4856
+ Object {
4857
+ "v": "req=r4",
4858
+ },
4859
+ Object {
4860
+ "v": "req=r1",
4861
+ },
4862
+ ],
4863
+ }
4864
+ `);
4865
+ });
4602
4866
  });
4603
4867
 
4604
4868
  describe('fields with conflicting types needing aliasing', () => {
@@ -88,7 +88,7 @@ it('correctly passes the context from ApolloServer to datasources', async () =>
88
88
  .reply(
89
89
  200,
90
90
  {
91
- data: { me: { username: '@jbaxleyiii' } },
91
+ data: { me: { username: '@apollo-user' } },
92
92
  },
93
93
  replyHeaders,
94
94
  );
@@ -107,7 +107,7 @@ it('correctly passes the context from ApolloServer to datasources', async () =>
107
107
  const { data, errors } = unwrapSingleResultKind(result);
108
108
  expect(errors).toBeUndefined();
109
109
  expect(data).toEqual({
110
- me: { username: '@jbaxleyiii' },
110
+ me: { username: '@apollo-user' },
111
111
  });
112
112
  });
113
113
 
@@ -62,7 +62,7 @@ describe('Using supergraphSdl static configuration', () => {
62
62
 
63
63
  nock(accounts.url)
64
64
  .post('/', { query: '{me{username}}', variables: {} })
65
- .reply(200, { data: { me: { username: '@jbaxleyiii' } } });
65
+ .reply(200, { data: { me: { username: '@apollo-user' } } });
66
66
 
67
67
 
68
68
  const result = await server.executeOperation({
@@ -72,7 +72,7 @@ describe('Using supergraphSdl static configuration', () => {
72
72
  expect(unwrapSingleResultKind(result).data).toMatchInlineSnapshot(`
73
73
  Object {
74
74
  "me": Object {
75
- "username": "@jbaxleyiii",
75
+ "username": "@apollo-user",
76
76
  },
77
77
  }
78
78
  `);
@@ -6,8 +6,8 @@ expect.addSnapshotSerializer(astSerializer);
6
6
  expect.addSnapshotSerializer(queryPlanSerializer);
7
7
 
8
8
  const users = [
9
- { id: '1', name: 'Trevor Scheer', organizationId: '1', __typename: 'User' },
10
- { id: '1', name: 'Trevor Scheer', organizationId: '2', __typename: 'User' },
9
+ { id: '1', name: 'Trevor', organizationId: '1', __typename: 'User' },
10
+ { id: '1', name: 'Trevor', organizationId: '2', __typename: 'User' },
11
11
  { id: '2', name: 'James Baxley', organizationId: '1', __typename: 'User' },
12
12
  { id: '2', name: 'James Baxley', organizationId: '3', __typename: 'User' },
13
13
  ];
@@ -162,7 +162,7 @@ it('works fetches data correctly with complex / nested @key fields', async () =>
162
162
  reviews: [
163
163
  {
164
164
  author: {
165
- name: 'Trevor Scheer',
165
+ name: 'Trevor',
166
166
  organization: {
167
167
  name: 'Apollo',
168
168
  },
@@ -170,7 +170,7 @@ it('works fetches data correctly with complex / nested @key fields', async () =>
170
170
  },
171
171
  {
172
172
  author: {
173
- name: 'Trevor Scheer',
173
+ name: 'Trevor',
174
174
  organization: {
175
175
  name: 'Wayfair',
176
176
  },
@@ -6,7 +6,7 @@ expect.addSnapshotSerializer(astSerializer);
6
6
  expect.addSnapshotSerializer(queryPlanSerializer);
7
7
 
8
8
  const users = [
9
- { id: ['1', '1'], name: 'Trevor Scheer', __typename: 'User' },
9
+ { id: ['1', '1'], name: 'Trevor', __typename: 'User' },
10
10
  { id: ['2', '2'], name: 'James Baxley', __typename: 'User' },
11
11
  ];
12
12
 
@@ -89,7 +89,7 @@ it('fetches data correctly list type @key fields', async () => {
89
89
 
90
90
  expect(data).toEqual({
91
91
  reviews: [
92
- { body: 'Good', author: { name: 'Trevor Scheer' } },
92
+ { body: 'Good', author: { name: 'Trevor' } },
93
93
  { body: 'Bad', author: { name: 'James Baxley' } },
94
94
  ],
95
95
  });
@@ -7,7 +7,7 @@ expect.addSnapshotSerializer(queryPlanSerializer);
7
7
 
8
8
  const users = [
9
9
  { ssn: '111-11-1111', name: 'Trevor', id: '10', __typename: 'User' },
10
- { ssn: '222-22-2222', name: 'Scheer', id: '20', __typename: 'User' },
10
+ { ssn: '222-22-2222', name: 'Joel', id: '20', __typename: 'User' },
11
11
  { ssn: '333-33-3333', name: 'James', id: '30', __typename: 'User' },
12
12
  { ssn: '444-44-4444', name: 'Baxley', id: '40', __typename: 'User' },
13
13
  ];
@@ -148,7 +148,7 @@ it('fetches data correctly with multiple @key fields', async () => {
148
148
  body: 'B',
149
149
  author: {
150
150
  risk: 0.2,
151
- name: 'Scheer',
151
+ name: 'Joel',
152
152
  },
153
153
  },
154
154
  {
@@ -218,13 +218,13 @@ it('collapses nested requires with user-defined fragments', async () => {
218
218
  {
219
219
  user {
220
220
  __typename
221
- id
222
221
  preferences {
223
222
  favorites {
224
- animal
225
223
  color
224
+ animal
226
225
  }
227
226
  }
227
+ id
228
228
  }
229
229
  }
230
230
  },
@@ -18,7 +18,7 @@ const accounts = {
18
18
  `,
19
19
  resolvers: {
20
20
  Query: {
21
- me: () => ({ id: 1, name: 'Martijn' }),
21
+ me: () => ({ id: 1, name: 'Me' }),
22
22
  },
23
23
  },
24
24
  };
@@ -98,14 +98,7 @@ describe('value types', () => {
98
98
  reviews {
99
99
  metadata {
100
100
  __typename
101
- ... on KeyValue {
102
- key
103
- value
104
- }
105
- ... on Error {
106
- code
107
- message
108
- }
101
+ ...Metadata
109
102
  }
110
103
  }
111
104
  }
@@ -113,18 +106,22 @@ describe('value types', () => {
113
106
  reviews {
114
107
  metadata {
115
108
  __typename
116
- ... on KeyValue {
117
- key
118
- value
119
- }
120
- ... on Error {
121
- code
122
- message
123
- }
109
+ ...Metadata
124
110
  }
125
111
  }
126
112
  }
127
113
  }
114
+
115
+ fragment Metadata on MetadataOrError {
116
+ ... on KeyValue {
117
+ key
118
+ value
119
+ }
120
+ ... on Error {
121
+ code
122
+ message
123
+ }
124
+ }
128
125
  },
129
126
  },
130
127
  Flatten(path: "topProducts.@") {