@apollo/gateway 0.43.0 → 0.45.0-alpha.0

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 (39) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/dist/__generated__/graphqlTypes.d.ts +13 -11
  3. package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
  4. package/dist/__generated__/graphqlTypes.js.map +1 -1
  5. package/dist/config.d.ts +3 -8
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +6 -17
  8. package/dist/config.js.map +1 -1
  9. package/dist/index.d.ts +4 -3
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +33 -33
  12. package/dist/index.js.map +1 -1
  13. package/dist/loadSupergraphSdlFromStorage.d.ts +15 -6
  14. package/dist/loadSupergraphSdlFromStorage.d.ts.map +1 -1
  15. package/dist/loadSupergraphSdlFromStorage.js +40 -9
  16. package/dist/loadSupergraphSdlFromStorage.js.map +1 -1
  17. package/dist/outOfBandReporter.d.ts +10 -12
  18. package/dist/outOfBandReporter.d.ts.map +1 -1
  19. package/dist/outOfBandReporter.js +70 -73
  20. package/dist/outOfBandReporter.js.map +1 -1
  21. package/package.json +8 -8
  22. package/src/__generated__/graphqlTypes.ts +13 -11
  23. package/src/__tests__/gateway/reporting.test.ts +5 -3
  24. package/src/__tests__/integration/configuration.test.ts +32 -11
  25. package/src/__tests__/integration/networkRequests.test.ts +44 -32
  26. package/src/__tests__/integration/nockMocks.ts +42 -8
  27. package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +129 -375
  28. package/src/__tests__/nockAssertions.ts +20 -0
  29. package/src/config.ts +10 -43
  30. package/src/index.ts +43 -54
  31. package/src/loadSupergraphSdlFromStorage.ts +61 -12
  32. package/src/outOfBandReporter.ts +87 -89
  33. package/dist/legacyLoadServicesFromStorage.d.ts +0 -20
  34. package/dist/legacyLoadServicesFromStorage.d.ts.map +0 -1
  35. package/dist/legacyLoadServicesFromStorage.js +0 -62
  36. package/dist/legacyLoadServicesFromStorage.js.map +0 -1
  37. package/src/__tests__/integration/legacyNetworkRequests.test.ts +0 -279
  38. package/src/__tests__/integration/legacyNockMocks.ts +0 -113
  39. package/src/legacyLoadServicesFromStorage.ts +0 -170
@@ -1,352 +1,96 @@
1
- import { loadSupergraphSdlFromStorage } from '../loadSupergraphSdlFromStorage';
1
+ import {
2
+ loadSupergraphSdlFromStorage,
3
+ loadSupergraphSdlFromUplinks
4
+ } from '../loadSupergraphSdlFromStorage';
2
5
  import { getDefaultFetcher } from '../..';
3
6
  import {
4
7
  graphRef,
5
8
  apiKey,
6
- mockCloudConfigUrl,
7
- mockSupergraphSdlRequest,
9
+ mockCloudConfigUrl1,
10
+ mockCloudConfigUrl2,
8
11
  mockOutOfBandReporterUrl,
12
+ mockSupergraphSdlRequest,
9
13
  mockOutOfBandReportRequestSuccess,
10
14
  mockSupergraphSdlRequestSuccess,
15
+ mockSupergraphSdlRequestIfAfterUnchanged,
16
+ mockSupergraphSdlRequestIfAfter
11
17
  } from './integration/nockMocks';
12
- import mockedEnv from 'mocked-env';
18
+ import { getTestingSupergraphSdl } from "./execution-utils";
19
+ import { nockAfterEach, nockBeforeEach } from './nockAssertions';
13
20
 
14
21
  describe('loadSupergraphSdlFromStorage', () => {
15
- let cleanUp: (() => void) | null = null;
16
-
17
- afterAll(async () => {
18
- if (cleanUp) {
19
- cleanUp();
20
- cleanUp = null;
21
- }
22
- });
22
+ beforeEach(nockBeforeEach);
23
+ afterEach(nockAfterEach);
23
24
 
24
25
  it('fetches Supergraph SDL as expected', async () => {
25
26
  mockSupergraphSdlRequestSuccess();
26
-
27
27
  const fetcher = getDefaultFetcher();
28
28
  const result = await loadSupergraphSdlFromStorage({
29
29
  graphRef,
30
30
  apiKey,
31
- endpoint: mockCloudConfigUrl,
31
+ endpoint: mockCloudConfigUrl1,
32
+ errorReportingEndpoint: undefined,
32
33
  fetcher,
34
+ compositionId: null,
35
+ });
36
+ expect(result).toMatchObject({
37
+ id: 'originalId-1234',
38
+ supergraphSdl: getTestingSupergraphSdl(),
33
39
  });
40
+ });
41
+
42
+ it('Queries alternate Uplink URL if first one fails', async () => {
43
+ mockSupergraphSdlRequest('originalId-1234', mockCloudConfigUrl1).reply(500);
44
+ mockSupergraphSdlRequestIfAfter('originalId-1234', mockCloudConfigUrl2).reply(
45
+ 200,
46
+ JSON.stringify({
47
+ data: {
48
+ routerConfig: {
49
+ __typename: 'RouterConfigResult',
50
+ id: 'originalId-1234',
51
+ supergraphSdl: getTestingSupergraphSdl()
52
+ },
53
+ },
54
+ }),
55
+ );
34
56
 
35
- expect(result).toMatchInlineSnapshot(`
36
- Object {
37
- "id": "originalId-1234",
38
- "supergraphSdl": "schema
39
- @core(feature: \\"https://specs.apollo.dev/core/v0.2\\"),
40
- @core(feature: \\"https://specs.apollo.dev/join/v0.1\\", for: EXECUTION),
41
- @core(feature: \\"https://specs.apollo.dev/tag/v0.1\\")
42
- {
43
- query: Query
44
- mutation: Mutation
45
- }
46
-
47
- directive @core(as: String, feature: String!, for: core__Purpose) repeatable on SCHEMA
48
-
49
- directive @join__field(graph: join__Graph, provides: join__FieldSet, requires: join__FieldSet) on FIELD_DEFINITION
50
-
51
- directive @join__graph(name: String!, url: String!) on ENUM_VALUE
52
-
53
- directive @join__owner(graph: join__Graph!) on INTERFACE | OBJECT
54
-
55
- directive @join__type(graph: join__Graph!, key: join__FieldSet) repeatable on INTERFACE | OBJECT
56
-
57
- directive @stream on FIELD
58
-
59
- directive @tag(name: String!) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
60
-
61
- directive @transform(from: String!) on FIELD
62
-
63
- union AccountType
64
- @tag(name: \\"from-accounts\\")
65
- = PasswordAccount | SMSAccount
66
-
67
- type Amazon {
68
- referrer: String
69
- }
70
-
71
- union Body = Image | Text
72
-
73
- type Book implements Product
74
- @join__owner(graph: BOOKS)
75
- @join__type(graph: BOOKS, key: \\"isbn\\")
76
- @join__type(graph: INVENTORY, key: \\"isbn\\")
77
- @join__type(graph: PRODUCT, key: \\"isbn\\")
78
- @join__type(graph: REVIEWS, key: \\"isbn\\")
79
- {
80
- details: ProductDetailsBook @join__field(graph: PRODUCT)
81
- inStock: Boolean @join__field(graph: INVENTORY)
82
- isCheckedOut: Boolean @join__field(graph: INVENTORY)
83
- isbn: String! @join__field(graph: BOOKS)
84
- metadata: [MetadataOrError] @join__field(graph: BOOKS)
85
- name(delimeter: String = \\" \\"): String @join__field(graph: PRODUCT, requires: \\"title year\\")
86
- price: String @join__field(graph: PRODUCT)
87
- relatedReviews: [Review!]! @join__field(graph: REVIEWS, requires: \\"similarBooks{isbn}\\")
88
- reviews: [Review] @join__field(graph: REVIEWS)
89
- similarBooks: [Book]! @join__field(graph: BOOKS)
90
- sku: String! @join__field(graph: PRODUCT)
91
- title: String @join__field(graph: BOOKS)
92
- upc: String! @join__field(graph: PRODUCT)
93
- year: Int @join__field(graph: BOOKS)
94
- }
95
-
96
- union Brand = Amazon | Ikea
97
-
98
- enum CacheControlScope {
99
- PRIVATE
100
- PUBLIC
101
- }
102
-
103
- type Car implements Vehicle
104
- @join__owner(graph: PRODUCT)
105
- @join__type(graph: PRODUCT, key: \\"id\\")
106
- @join__type(graph: REVIEWS, key: \\"id\\")
107
- {
108
- description: String @join__field(graph: PRODUCT)
109
- id: String! @join__field(graph: PRODUCT)
110
- price: String @join__field(graph: PRODUCT)
111
- retailPrice: String @join__field(graph: REVIEWS, requires: \\"price\\")
112
- }
113
-
114
- type Error {
115
- code: Int
116
- message: String
117
- }
118
-
119
- type Furniture implements Product
120
- @join__owner(graph: PRODUCT)
121
- @join__type(graph: PRODUCT, key: \\"upc\\")
122
- @join__type(graph: PRODUCT, key: \\"sku\\")
123
- @join__type(graph: INVENTORY, key: \\"sku\\")
124
- @join__type(graph: REVIEWS, key: \\"upc\\")
125
- {
126
- brand: Brand @join__field(graph: PRODUCT)
127
- details: ProductDetailsFurniture @join__field(graph: PRODUCT)
128
- inStock: Boolean @join__field(graph: INVENTORY)
129
- isHeavy: Boolean @join__field(graph: INVENTORY)
130
- metadata: [MetadataOrError] @join__field(graph: PRODUCT)
131
- name: String @join__field(graph: PRODUCT)
132
- price: String @join__field(graph: PRODUCT)
133
- reviews: [Review] @join__field(graph: REVIEWS)
134
- sku: String! @join__field(graph: PRODUCT)
135
- upc: String! @join__field(graph: PRODUCT)
136
- }
137
-
138
- type Ikea {
139
- asile: Int
140
- }
141
-
142
- type Image implements NamedObject {
143
- attributes: ImageAttributes!
144
- name: String!
145
- }
146
-
147
- type ImageAttributes {
148
- url: String!
149
- }
150
-
151
- scalar JSON @specifiedBy(url: \\"https://json-spec.dev\\")
152
-
153
- type KeyValue {
154
- key: String!
155
- value: String!
156
- }
157
-
158
- type Library
159
- @join__owner(graph: BOOKS)
160
- @join__type(graph: BOOKS, key: \\"id\\")
161
- @join__type(graph: ACCOUNTS, key: \\"id\\")
162
- {
163
- id: ID! @join__field(graph: BOOKS)
164
- name: String @join__field(graph: BOOKS)
165
- userAccount(id: ID! = 1): User @join__field(graph: ACCOUNTS, requires: \\"name\\")
166
- }
167
-
168
- union MetadataOrError = Error | KeyValue
169
-
170
- type Mutation {
171
- deleteReview(id: ID!): Boolean @join__field(graph: REVIEWS)
172
- login(password: String!, userId: String @deprecated(reason: \\"Use username instead\\"), username: String!): User @join__field(graph: ACCOUNTS)
173
- reviewProduct(input: ReviewProduct!): Product @join__field(graph: REVIEWS)
174
- updateReview(review: UpdateReviewInput!): Review @join__field(graph: REVIEWS)
175
- }
176
-
177
- type Name {
178
- first: String
179
- last: String
180
- }
181
-
182
- interface NamedObject {
183
- name: String!
184
- }
185
-
186
- type PasswordAccount
187
- @join__owner(graph: ACCOUNTS)
188
- @join__type(graph: ACCOUNTS, key: \\"email\\")
189
- {
190
- email: String! @join__field(graph: ACCOUNTS)
191
- }
192
-
193
- interface Product
194
- @tag(name: \\"from-reviews\\")
195
- {
196
- details: ProductDetails
197
- inStock: Boolean
198
- name: String
199
- price: String
200
- reviews: [Review]
201
- sku: String!
202
- upc: String!
203
- }
204
-
205
- interface ProductDetails {
206
- country: String
207
- }
208
-
209
- type ProductDetailsBook implements ProductDetails {
210
- country: String
211
- pages: Int
212
- }
213
-
214
- type ProductDetailsFurniture implements ProductDetails {
215
- color: String
216
- country: String
217
- }
218
-
219
- type Query {
220
- body: Body! @join__field(graph: DOCUMENTS)
221
- book(isbn: String!): Book @join__field(graph: BOOKS)
222
- books: [Book] @join__field(graph: BOOKS)
223
- library(id: ID!): Library @join__field(graph: BOOKS)
224
- me: User @join__field(graph: ACCOUNTS)
225
- product(upc: String!): Product @join__field(graph: PRODUCT)
226
- topCars(first: Int = 5): [Car] @join__field(graph: PRODUCT)
227
- topProducts(first: Int = 5): [Product] @join__field(graph: PRODUCT)
228
- topReviews(first: Int = 5): [Review] @join__field(graph: REVIEWS)
229
- user(id: ID!): User @join__field(graph: ACCOUNTS)
230
- vehicle(id: String!): Vehicle @join__field(graph: PRODUCT)
231
- }
232
-
233
- type Review
234
- @join__owner(graph: REVIEWS)
235
- @join__type(graph: REVIEWS, key: \\"id\\")
236
- {
237
- author: User @join__field(graph: REVIEWS, provides: \\"username\\")
238
- body(format: Boolean = false): String @join__field(graph: REVIEWS)
239
- id: ID! @join__field(graph: REVIEWS)
240
- metadata: [MetadataOrError] @join__field(graph: REVIEWS)
241
- product: Product @join__field(graph: REVIEWS)
242
- }
243
-
244
- input ReviewProduct {
245
- body: String!
246
- stars: Int @deprecated(reason: \\"Stars are no longer in use\\")
247
- upc: String!
248
- }
249
-
250
- type SMSAccount
251
- @join__owner(graph: ACCOUNTS)
252
- @join__type(graph: ACCOUNTS, key: \\"number\\")
253
- {
254
- number: String @join__field(graph: ACCOUNTS)
255
- }
256
-
257
- type Text implements NamedObject {
258
- attributes: TextAttributes!
259
- name: String!
260
- }
261
-
262
- type TextAttributes {
263
- bold: Boolean
264
- text: String
265
- }
266
-
267
- union Thing = Car | Ikea
268
-
269
- input UpdateReviewInput {
270
- body: String
271
- id: ID!
272
- }
273
-
274
- type User
275
- @join__owner(graph: ACCOUNTS)
276
- @join__type(graph: ACCOUNTS, key: \\"id\\")
277
- @join__type(graph: ACCOUNTS, key: \\"username name{first last}\\")
278
- @join__type(graph: INVENTORY, key: \\"id\\")
279
- @join__type(graph: PRODUCT, key: \\"id\\")
280
- @join__type(graph: REVIEWS, key: \\"id\\")
281
- @tag(name: \\"from-accounts\\")
282
- @tag(name: \\"from-reviews\\")
283
- {
284
- account: AccountType @join__field(graph: ACCOUNTS)
285
- birthDate(locale: String): String @join__field(graph: ACCOUNTS) @tag(name: \\"admin\\") @tag(name: \\"dev\\")
286
- goodAddress: Boolean @join__field(graph: REVIEWS, requires: \\"metadata{address}\\")
287
- goodDescription: Boolean @join__field(graph: INVENTORY, requires: \\"metadata{description}\\")
288
- id: ID! @join__field(graph: ACCOUNTS) @tag(name: \\"accounts\\") @tag(name: \\"on-external\\")
289
- metadata: [UserMetadata] @join__field(graph: ACCOUNTS)
290
- name: Name @join__field(graph: ACCOUNTS)
291
- numberOfReviews: Int! @join__field(graph: REVIEWS)
292
- reviews: [Review] @join__field(graph: REVIEWS)
293
- ssn: String @join__field(graph: ACCOUNTS)
294
- thing: Thing @join__field(graph: PRODUCT)
295
- username: String @join__field(graph: ACCOUNTS)
296
- vehicle: Vehicle @join__field(graph: PRODUCT)
297
- }
298
-
299
- type UserMetadata {
300
- address: String
301
- description: String
302
- name: String
303
- }
304
-
305
- type Van implements Vehicle
306
- @join__owner(graph: PRODUCT)
307
- @join__type(graph: PRODUCT, key: \\"id\\")
308
- @join__type(graph: REVIEWS, key: \\"id\\")
309
- {
310
- description: String @join__field(graph: PRODUCT)
311
- id: String! @join__field(graph: PRODUCT)
312
- price: String @join__field(graph: PRODUCT)
313
- retailPrice: String @join__field(graph: REVIEWS, requires: \\"price\\")
314
- }
315
-
316
- interface Vehicle {
317
- description: String
318
- id: String!
319
- price: String
320
- retailPrice: String
321
- }
322
-
323
- enum core__Purpose {
324
- \\"\\"\\"
325
- \`EXECUTION\` features provide metadata necessary to for operation execution.
326
- \\"\\"\\"
327
- EXECUTION
328
-
329
- \\"\\"\\"
330
- \`SECURITY\` features provide metadata necessary to securely resolve fields.
331
- \\"\\"\\"
332
- SECURITY
333
- }
334
-
335
- scalar join__FieldSet
336
-
337
- enum join__Graph {
338
- ACCOUNTS @join__graph(name: \\"accounts\\" url: \\"https://accounts.api.com\\")
339
- BOOKS @join__graph(name: \\"books\\" url: \\"https://books.api.com\\")
340
- DOCUMENTS @join__graph(name: \\"documents\\" url: \\"https://documents.api.com\\")
341
- INVENTORY @join__graph(name: \\"inventory\\" url: \\"https://inventory.api.com\\")
342
- PRODUCT @join__graph(name: \\"product\\" url: \\"https://product.api.com\\")
343
- REVIEWS @join__graph(name: \\"reviews\\" url: \\"https://reviews.api.com\\")
344
- }
345
- ",
346
- }
347
- `);
57
+ const fetcher = getDefaultFetcher();
58
+ const result = await loadSupergraphSdlFromUplinks({
59
+ graphRef,
60
+ apiKey,
61
+ endpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2],
62
+ errorReportingEndpoint: undefined,
63
+ fetcher,
64
+ compositionId: "originalId-1234",
65
+ maxRetries: 1
66
+ });
67
+
68
+ expect(result).toMatchObject({
69
+ id: 'originalId-1234',
70
+ supergraphSdl: getTestingSupergraphSdl(),
71
+ });
348
72
  });
349
73
 
74
+ it('Throws error if all Uplink URLs fail', async () => {
75
+ mockSupergraphSdlRequest("originalId-1234", mockCloudConfigUrl1).reply(500);
76
+ mockSupergraphSdlRequestIfAfter("originalId-1234", mockCloudConfigUrl2).reply(500);
77
+
78
+ const fetcher = getDefaultFetcher();
79
+ await expect(
80
+ loadSupergraphSdlFromUplinks({
81
+ graphRef,
82
+ apiKey,
83
+ endpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2],
84
+ errorReportingEndpoint: undefined,
85
+ fetcher,
86
+ compositionId: "originalId-1234",
87
+ maxRetries: 1
88
+ }),
89
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
90
+ `"An error occurred while fetching your schema from Apollo: 500 Internal Server Error"`,
91
+ );
92
+ })
93
+
350
94
  describe('errors', () => {
351
95
  it('throws on a malformed response', async () => {
352
96
  mockSupergraphSdlRequest().reply(200, 'Invalid JSON');
@@ -356,11 +100,13 @@ describe('loadSupergraphSdlFromStorage', () => {
356
100
  loadSupergraphSdlFromStorage({
357
101
  graphRef,
358
102
  apiKey,
359
- endpoint: mockCloudConfigUrl,
103
+ endpoint: mockCloudConfigUrl1,
104
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
360
105
  fetcher,
106
+ compositionId: null,
361
107
  }),
362
108
  ).rejects.toThrowErrorMatchingInlineSnapshot(
363
- `"An error occurred while fetching your schema from Apollo: 200 invalid json response body at https://example.cloud-config-url.com/cloudconfig/ reason: Unexpected token I in JSON at position 0"`,
109
+ `"An error occurred while fetching your schema from Apollo: 200 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected token I in JSON at position 0"`,
364
110
  );
365
111
  });
366
112
 
@@ -378,22 +124,27 @@ describe('loadSupergraphSdlFromStorage', () => {
378
124
  loadSupergraphSdlFromStorage({
379
125
  graphRef,
380
126
  apiKey,
381
- endpoint: mockCloudConfigUrl,
127
+ endpoint: mockCloudConfigUrl1,
128
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
382
129
  fetcher,
130
+ compositionId: null,
383
131
  }),
384
132
  ).rejects.toThrowError(message);
385
133
  });
386
134
 
387
135
  it("throws on non-OK status codes when `errors` isn't present in a JSON response", async () => {
388
136
  mockSupergraphSdlRequest().reply(500);
137
+ mockOutOfBandReportRequestSuccess();
389
138
 
390
139
  const fetcher = getDefaultFetcher();
391
140
  await expect(
392
141
  loadSupergraphSdlFromStorage({
393
142
  graphRef,
394
143
  apiKey,
395
- endpoint: mockCloudConfigUrl,
144
+ endpoint: mockCloudConfigUrl1,
145
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
396
146
  fetcher,
147
+ compositionId: null,
397
148
  }),
398
149
  ).rejects.toThrowErrorMatchingInlineSnapshot(
399
150
  `"An error occurred while fetching your schema from Apollo: 500 Internal Server Error"`,
@@ -410,40 +161,36 @@ describe('loadSupergraphSdlFromStorage', () => {
410
161
  loadSupergraphSdlFromStorage({
411
162
  graphRef,
412
163
  apiKey,
413
- endpoint: mockCloudConfigUrl,
164
+ endpoint: mockCloudConfigUrl1,
165
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
414
166
  fetcher,
167
+ compositionId: null,
415
168
  }),
416
169
  ).rejects.toThrowErrorMatchingInlineSnapshot(
417
- `"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input"`,
170
+ `"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input"`,
418
171
  );
419
172
  });
420
173
 
421
- it('throws on 400 status response and successfully submits an out of band error', async () => {
422
- cleanUp = mockedEnv({
423
- APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT: mockOutOfBandReporterUrl,
424
- });
174
+ it('throws on 400 status response and does not submit an out of band error', async () => {
425
175
 
426
176
  mockSupergraphSdlRequest().reply(400);
427
- mockOutOfBandReportRequestSuccess();
428
177
 
429
178
  const fetcher = getDefaultFetcher();
430
179
  await expect(
431
180
  loadSupergraphSdlFromStorage({
432
181
  graphRef,
433
182
  apiKey,
434
- endpoint: mockCloudConfigUrl,
183
+ endpoint: mockCloudConfigUrl1,
184
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
435
185
  fetcher,
186
+ compositionId: null,
436
187
  }),
437
188
  ).rejects.toThrowErrorMatchingInlineSnapshot(
438
- `"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input"`,
189
+ `"An error occurred while fetching your schema from Apollo: 400 invalid json response body at https://example1.cloud-config-url.com/cloudconfig/ reason: Unexpected end of JSON input"`,
439
190
  );
440
191
  });
441
192
 
442
193
  it('throws on 413 status response and successfully submits an out of band error', async () => {
443
- cleanUp = mockedEnv({
444
- APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT: mockOutOfBandReporterUrl,
445
- });
446
-
447
194
  mockSupergraphSdlRequest().reply(413);
448
195
  mockOutOfBandReportRequestSuccess();
449
196
 
@@ -452,8 +199,10 @@ describe('loadSupergraphSdlFromStorage', () => {
452
199
  loadSupergraphSdlFromStorage({
453
200
  graphRef,
454
201
  apiKey,
455
- endpoint: mockCloudConfigUrl,
202
+ endpoint: mockCloudConfigUrl1,
203
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
456
204
  fetcher,
205
+ compositionId: null,
457
206
  }),
458
207
  ).rejects.toThrowErrorMatchingInlineSnapshot(
459
208
  `"An error occurred while fetching your schema from Apollo: 413 Payload Too Large"`,
@@ -461,10 +210,6 @@ describe('loadSupergraphSdlFromStorage', () => {
461
210
  });
462
211
 
463
212
  it('throws on 422 status response and successfully submits an out of band error', async () => {
464
- cleanUp = mockedEnv({
465
- APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT: mockOutOfBandReporterUrl,
466
- });
467
-
468
213
  mockSupergraphSdlRequest().reply(422);
469
214
  mockOutOfBandReportRequestSuccess();
470
215
 
@@ -473,8 +218,10 @@ describe('loadSupergraphSdlFromStorage', () => {
473
218
  loadSupergraphSdlFromStorage({
474
219
  graphRef,
475
220
  apiKey,
476
- endpoint: mockCloudConfigUrl,
221
+ endpoint: mockCloudConfigUrl1,
222
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
477
223
  fetcher,
224
+ compositionId: null,
478
225
  }),
479
226
  ).rejects.toThrowErrorMatchingInlineSnapshot(
480
227
  `"An error occurred while fetching your schema from Apollo: 422 Unprocessable Entity"`,
@@ -482,10 +229,6 @@ describe('loadSupergraphSdlFromStorage', () => {
482
229
  });
483
230
 
484
231
  it('throws on 408 status response and successfully submits an out of band error', async () => {
485
- cleanUp = mockedEnv({
486
- APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT: mockOutOfBandReporterUrl,
487
- });
488
-
489
232
  mockSupergraphSdlRequest().reply(408);
490
233
  mockOutOfBandReportRequestSuccess();
491
234
 
@@ -494,8 +237,10 @@ describe('loadSupergraphSdlFromStorage', () => {
494
237
  loadSupergraphSdlFromStorage({
495
238
  graphRef,
496
239
  apiKey,
497
- endpoint: mockCloudConfigUrl,
240
+ endpoint: mockCloudConfigUrl1,
241
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
498
242
  fetcher,
243
+ compositionId: null,
499
244
  }),
500
245
  ).rejects.toThrowErrorMatchingInlineSnapshot(
501
246
  `"An error occurred while fetching your schema from Apollo: 408 Request Timeout"`,
@@ -504,9 +249,6 @@ describe('loadSupergraphSdlFromStorage', () => {
504
249
  });
505
250
 
506
251
  it('throws on 504 status response and successfully submits an out of band error', async () => {
507
- cleanUp = mockedEnv({
508
- APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT: mockOutOfBandReporterUrl,
509
- });
510
252
 
511
253
  mockSupergraphSdlRequest().reply(504);
512
254
  mockOutOfBandReportRequestSuccess();
@@ -516,8 +258,10 @@ describe('loadSupergraphSdlFromStorage', () => {
516
258
  loadSupergraphSdlFromStorage({
517
259
  graphRef,
518
260
  apiKey,
519
- endpoint: mockCloudConfigUrl,
261
+ endpoint: mockCloudConfigUrl1,
262
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
520
263
  fetcher,
264
+ compositionId: null,
521
265
  }),
522
266
  ).rejects.toThrowErrorMatchingInlineSnapshot(
523
267
  `"An error occurred while fetching your schema from Apollo: 504 Gateway Timeout"`,
@@ -525,10 +269,6 @@ describe('loadSupergraphSdlFromStorage', () => {
525
269
  });
526
270
 
527
271
  it('throws when there is no response and successfully submits an out of band error', async () => {
528
- cleanUp = mockedEnv({
529
- APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT: mockOutOfBandReporterUrl,
530
- });
531
-
532
272
  mockSupergraphSdlRequest().replyWithError('no response');
533
273
  mockOutOfBandReportRequestSuccess();
534
274
 
@@ -537,19 +277,17 @@ describe('loadSupergraphSdlFromStorage', () => {
537
277
  loadSupergraphSdlFromStorage({
538
278
  graphRef,
539
279
  apiKey,
540
- endpoint: mockCloudConfigUrl,
280
+ endpoint: mockCloudConfigUrl1,
281
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
541
282
  fetcher,
283
+ compositionId: null,
542
284
  }),
543
285
  ).rejects.toThrowErrorMatchingInlineSnapshot(
544
- `"An error occurred while fetching your schema from Apollo: request to https://example.cloud-config-url.com/cloudconfig/ failed, reason: no response"`,
286
+ `"An error occurred while fetching your schema from Apollo: request to https://example1.cloud-config-url.com/cloudconfig/ failed, reason: no response"`,
545
287
  );
546
288
  });
547
289
 
548
290
  it('throws on 502 status response and successfully submits an out of band error', async () => {
549
- cleanUp = mockedEnv({
550
- APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT: mockOutOfBandReporterUrl,
551
- });
552
-
553
291
  mockSupergraphSdlRequest().reply(502);
554
292
  mockOutOfBandReportRequestSuccess();
555
293
 
@@ -558,8 +296,10 @@ describe('loadSupergraphSdlFromStorage', () => {
558
296
  loadSupergraphSdlFromStorage({
559
297
  graphRef,
560
298
  apiKey,
561
- endpoint: mockCloudConfigUrl,
299
+ endpoint: mockCloudConfigUrl1,
300
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
562
301
  fetcher,
302
+ compositionId: null,
563
303
  }),
564
304
  ).rejects.toThrowErrorMatchingInlineSnapshot(
565
305
  `"An error occurred while fetching your schema from Apollo: 502 Bad Gateway"`,
@@ -567,10 +307,6 @@ describe('loadSupergraphSdlFromStorage', () => {
567
307
  });
568
308
 
569
309
  it('throws on 503 status response and successfully submits an out of band error', async () => {
570
- cleanUp = mockedEnv({
571
- APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT: mockOutOfBandReporterUrl,
572
- });
573
-
574
310
  mockSupergraphSdlRequest().reply(503);
575
311
  mockOutOfBandReportRequestSuccess();
576
312
 
@@ -579,11 +315,29 @@ describe('loadSupergraphSdlFromStorage', () => {
579
315
  loadSupergraphSdlFromStorage({
580
316
  graphRef,
581
317
  apiKey,
582
- endpoint: mockCloudConfigUrl,
318
+ endpoint: mockCloudConfigUrl1,
319
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
583
320
  fetcher,
321
+ compositionId: null,
584
322
  }),
585
323
  ).rejects.toThrowErrorMatchingInlineSnapshot(
586
324
  `"An error occurred while fetching your schema from Apollo: 503 Service Unavailable"`,
587
325
  );
588
326
  });
327
+
328
+ it('successfully responds to SDL unchanged by returning null', async () => {
329
+ mockSupergraphSdlRequestIfAfterUnchanged("id-1234");
330
+
331
+ const fetcher = getDefaultFetcher();
332
+ const result = await loadSupergraphSdlFromStorage({
333
+ graphRef,
334
+ apiKey,
335
+ endpoint: mockCloudConfigUrl1,
336
+ errorReportingEndpoint: mockOutOfBandReporterUrl,
337
+ fetcher,
338
+ compositionId: "id-1234",
339
+ });
340
+ expect(result).toBeNull();
341
+ });
589
342
  });
343
+