@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.
- package/CHANGELOG.md +10 -3
- package/dist/__generated__/graphqlTypes.d.ts +13 -12
- package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
- package/dist/__generated__/graphqlTypes.js.map +1 -1
- package/dist/config.d.ts +3 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -17
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -37
- package/dist/index.js.map +1 -1
- package/dist/loadSupergraphSdlFromStorage.d.ts +13 -5
- package/dist/loadSupergraphSdlFromStorage.d.ts.map +1 -1
- package/dist/loadSupergraphSdlFromStorage.js +34 -7
- package/dist/loadSupergraphSdlFromStorage.js.map +1 -1
- package/dist/outOfBandReporter.d.ts +10 -12
- package/dist/outOfBandReporter.d.ts.map +1 -1
- package/dist/outOfBandReporter.js +70 -73
- package/dist/outOfBandReporter.js.map +1 -1
- package/package.json +4 -4
- package/src/__generated__/graphqlTypes.ts +13 -12
- package/src/__tests__/gateway/reporting.test.ts +5 -3
- package/src/__tests__/integration/configuration.test.ts +32 -11
- package/src/__tests__/integration/networkRequests.test.ts +22 -22
- package/src/__tests__/integration/nockMocks.ts +12 -6
- package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +101 -377
- package/src/__tests__/nockAssertions.ts +20 -0
- package/src/config.ts +10 -43
- package/src/index.ts +36 -56
- package/src/loadSupergraphSdlFromStorage.ts +54 -8
- package/src/outOfBandReporter.ts +87 -89
- package/dist/legacyLoadServicesFromStorage.d.ts +0 -20
- package/dist/legacyLoadServicesFromStorage.d.ts.map +0 -1
- package/dist/legacyLoadServicesFromStorage.js +0 -62
- package/dist/legacyLoadServicesFromStorage.js.map +0 -1
- package/src/__tests__/integration/legacyNetworkRequests.test.ts +0 -279
- package/src/__tests__/integration/legacyNockMocks.ts +0 -113
- package/src/legacyLoadServicesFromStorage.ts +0 -170
|
@@ -1,355 +1,96 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
loadSupergraphSdlFromStorage,
|
|
3
|
+
loadSupergraphSdlFromUplinks
|
|
4
|
+
} from '../loadSupergraphSdlFromStorage';
|
|
2
5
|
import { getDefaultFetcher } from '../..';
|
|
3
6
|
import {
|
|
4
7
|
graphRef,
|
|
5
8
|
apiKey,
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
18
|
+
import { getTestingSupergraphSdl } from "./execution-utils";
|
|
19
|
+
import { nockAfterEach, nockBeforeEach } from './nockAssertions';
|
|
14
20
|
|
|
15
21
|
describe('loadSupergraphSdlFromStorage', () => {
|
|
16
|
-
|
|
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:
|
|
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).
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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:
|
|
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://
|
|
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:
|
|
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:
|
|
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:
|
|
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://
|
|
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
|
|
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:
|
|
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://
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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://
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
+
};
|