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