@khanacademy/wonder-blocks-testing 2.0.8 → 4.0.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 +22 -0
- package/dist/es/index.js +255 -140
- package/dist/index.js +304 -145
- package/package.json +2 -1
- package/src/{gql/__tests__/make-gql-mock-response.test.js → __tests__/make-mock-response.test.js} +196 -34
- package/src/__tests__/mock-requester.test.js +213 -0
- package/src/__tests__/response-impl.test.js +47 -0
- package/src/fetch/__tests__/__snapshots__/mock-fetch.test.js.snap +29 -0
- package/src/fetch/__tests__/fetch-request-matches-mock.test.js +99 -0
- package/src/fetch/__tests__/mock-fetch.test.js +84 -0
- package/src/fetch/fetch-request-matches-mock.js +43 -0
- package/src/fetch/mock-fetch.js +19 -0
- package/src/fetch/types.js +18 -0
- package/src/fixtures/__tests__/fixtures.test.js +66 -22
- package/src/fixtures/adapters/__tests__/adapter-group.test.js +24 -0
- package/src/fixtures/adapters/__tests__/adapter.test.js +6 -0
- package/src/fixtures/adapters/storybook.js +4 -1
- package/src/fixtures/fixtures.basic.stories.js +1 -1
- package/src/fixtures/fixtures.defaultwrapper.stories.js +1 -1
- package/src/fixtures/fixtures.js +47 -3
- package/src/fixtures/types.js +10 -1
- package/src/gql/__tests__/mock-gql-fetch.test.js +24 -15
- package/src/gql/__tests__/wb-data-integration.test.js +7 -4
- package/src/gql/mock-gql-fetch.js +9 -80
- package/src/gql/types.js +11 -10
- package/src/index.js +9 -3
- package/src/make-mock-response.js +150 -0
- package/src/mock-requester.js +75 -0
- package/src/response-impl.js +9 -0
- package/src/types.js +39 -0
- package/src/gql/make-gql-mock-response.js +0 -124
package/dist/index.js
CHANGED
|
@@ -82,7 +82,7 @@ module.exports =
|
|
|
82
82
|
/******/
|
|
83
83
|
/******/
|
|
84
84
|
/******/ // Load entry module and return exports
|
|
85
|
-
/******/ return __webpack_require__(__webpack_require__.s =
|
|
85
|
+
/******/ return __webpack_require__(__webpack_require__.s = 18);
|
|
86
86
|
/******/ })
|
|
87
87
|
/************************************************************************/
|
|
88
88
|
/******/ ([
|
|
@@ -121,89 +121,114 @@ const getConfiguration = () => {
|
|
|
121
121
|
|
|
122
122
|
"use strict";
|
|
123
123
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return RespondWith; });
|
|
124
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return
|
|
124
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return makeMockResponse; });
|
|
125
|
+
/* harmony import */ var _response_impl_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(15);
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Helper for creating a text-based mock response.
|
|
130
|
+
*/
|
|
131
|
+
const textResponse = (text, statusCode = 200) => ({
|
|
132
|
+
type: "text",
|
|
133
|
+
text,
|
|
134
|
+
statusCode
|
|
135
|
+
});
|
|
136
|
+
/**
|
|
137
|
+
* Helper for creating a rejected mock response.
|
|
138
|
+
*/
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
const rejectResponse = error => ({
|
|
142
|
+
type: "reject",
|
|
143
|
+
error
|
|
144
|
+
});
|
|
125
145
|
/**
|
|
126
|
-
* Helpers to define
|
|
146
|
+
* Helpers to define mock responses for mocked requests.
|
|
127
147
|
*/
|
|
148
|
+
|
|
149
|
+
|
|
128
150
|
const RespondWith = Object.freeze({
|
|
129
|
-
|
|
130
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Response with text body and status code.
|
|
153
|
+
* Status code defaults to 200.
|
|
154
|
+
*/
|
|
155
|
+
text: (text, statusCode = 200) => textResponse(text, statusCode),
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Response with JSON body and status code 200.
|
|
159
|
+
*/
|
|
160
|
+
json: json => textResponse(() => JSON.stringify(json)),
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Response with GraphQL data JSON body and status code 200.
|
|
164
|
+
*/
|
|
165
|
+
graphQLData: data => textResponse(() => JSON.stringify({
|
|
131
166
|
data
|
|
167
|
+
})),
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Response with body that will not parse as JSON and status code 200.
|
|
171
|
+
*/
|
|
172
|
+
unparseableBody: () => textResponse("INVALID JSON"),
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Rejects with an AbortError to simulate an aborted request.
|
|
176
|
+
*/
|
|
177
|
+
abortedRequest: () => rejectResponse(() => {
|
|
178
|
+
const abortError = new Error("Mock request aborted");
|
|
179
|
+
abortError.name = "AbortError";
|
|
180
|
+
return abortError;
|
|
132
181
|
}),
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Rejects with the given error.
|
|
185
|
+
*/
|
|
186
|
+
reject: error => rejectResponse(error),
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* A non-200 status code with empty text body.
|
|
190
|
+
* Equivalent to calling `ResponseWith.text("", statusCode)`.
|
|
191
|
+
*/
|
|
139
192
|
errorStatusCode: statusCode => {
|
|
140
193
|
if (statusCode < 300) {
|
|
141
194
|
throw new Error(`${statusCode} is not a valid error status code`);
|
|
142
195
|
}
|
|
143
196
|
|
|
144
|
-
return {
|
|
145
|
-
type: "status",
|
|
146
|
-
statusCode
|
|
147
|
-
};
|
|
197
|
+
return textResponse("{}", statusCode);
|
|
148
198
|
},
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Response body that is valid JSON but not a valid GraphQL response.
|
|
202
|
+
*/
|
|
203
|
+
nonGraphQLBody: () => textResponse(() => JSON.stringify({
|
|
204
|
+
valid: "json",
|
|
205
|
+
that: "is not a valid graphql response"
|
|
206
|
+
})),
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Response that is a GraphQL errors response with status code 200.
|
|
210
|
+
*/
|
|
211
|
+
graphQLErrors: errorMessages => textResponse(() => JSON.stringify({
|
|
212
|
+
errors: errorMessages.map(e => ({
|
|
213
|
+
message: e
|
|
214
|
+
}))
|
|
215
|
+
}))
|
|
156
216
|
});
|
|
157
217
|
/**
|
|
158
|
-
* Turns
|
|
159
|
-
* that error.
|
|
218
|
+
* Turns a MockResponse value to an actual Response that represents the mock.
|
|
160
219
|
*/
|
|
161
220
|
|
|
162
|
-
const
|
|
221
|
+
const makeMockResponse = response => {
|
|
163
222
|
switch (response.type) {
|
|
164
|
-
case "
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return Promise.resolve({
|
|
174
|
-
status: 200,
|
|
175
|
-
text: () => Promise.resolve("INVALID JSON")
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
case "abort":
|
|
179
|
-
const abortError = new Error("Mock request aborted");
|
|
180
|
-
abortError.name = "AbortError";
|
|
181
|
-
return Promise.reject(abortError);
|
|
182
|
-
|
|
183
|
-
case "status":
|
|
184
|
-
return Promise.resolve({
|
|
185
|
-
status: response.statusCode,
|
|
186
|
-
text: () => Promise.resolve(JSON.stringify({}))
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
case "invalid":
|
|
190
|
-
return Promise.resolve({
|
|
191
|
-
status: 200,
|
|
192
|
-
text: () => Promise.resolve(JSON.stringify({
|
|
193
|
-
valid: "json",
|
|
194
|
-
that: "is not a valid graphql response"
|
|
195
|
-
}))
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
case "graphql":
|
|
199
|
-
return Promise.resolve({
|
|
200
|
-
status: 200,
|
|
201
|
-
text: () => Promise.resolve(JSON.stringify({
|
|
202
|
-
errors: response.errors.map(e => ({
|
|
203
|
-
message: e
|
|
204
|
-
}))
|
|
205
|
-
}))
|
|
206
|
-
});
|
|
223
|
+
case "text":
|
|
224
|
+
const text = typeof response.text === "function" ? response.text() : response.text;
|
|
225
|
+
return Promise.resolve(new _response_impl_js__WEBPACK_IMPORTED_MODULE_0__[/* ResponseImpl */ "a"](text, {
|
|
226
|
+
status: response.statusCode
|
|
227
|
+
}));
|
|
228
|
+
|
|
229
|
+
case "reject":
|
|
230
|
+
const error = response.error instanceof Error ? response.error : response.error();
|
|
231
|
+
return Promise.reject(error);
|
|
207
232
|
|
|
208
233
|
default:
|
|
209
234
|
throw new Error(`Unknown response type: ${response.type}`);
|
|
@@ -220,24 +245,82 @@ module.exports = require("react");
|
|
|
220
245
|
/* 3 */
|
|
221
246
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
222
247
|
|
|
248
|
+
"use strict";
|
|
249
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return mockRequester; });
|
|
250
|
+
/* harmony import */ var _make_mock_response_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* A generic mock request function for using when mocking fetch or gqlFetch.
|
|
255
|
+
*/
|
|
256
|
+
const mockRequester = (operationMatcher, operationToString) => {
|
|
257
|
+
// We want this to work in jest and in fixtures to make life easy for folks.
|
|
258
|
+
// This is the array of mocked operations that we will traverse and
|
|
259
|
+
// manipulate.
|
|
260
|
+
const mocks = []; // What we return has to be a drop in for the fetch function that is
|
|
261
|
+
// provided to `GqlRouter` which is how folks will then use this mock.
|
|
262
|
+
|
|
263
|
+
const mockFn = (...args) => {
|
|
264
|
+
// Iterate our mocked operations and find the first one that matches.
|
|
265
|
+
for (const mock of mocks) {
|
|
266
|
+
if (mock.onceOnly && mock.used) {
|
|
267
|
+
// This is a once-only mock and it has been used, so skip it.
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (operationMatcher.apply(void 0, [mock.operation].concat(args))) {
|
|
272
|
+
mock.used = true;
|
|
273
|
+
return mock.response();
|
|
274
|
+
}
|
|
275
|
+
} // Default is to reject with some helpful info on what request
|
|
276
|
+
// we rejected.
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
return Promise.reject(new Error(`No matching mock response found for request:
|
|
280
|
+
${operationToString.apply(void 0, args)}`));
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const addMockedOperation = (operation, response, onceOnly) => {
|
|
284
|
+
const mockResponse = () => Object(_make_mock_response_js__WEBPACK_IMPORTED_MODULE_0__[/* makeMockResponse */ "b"])(response);
|
|
285
|
+
|
|
286
|
+
mocks.push({
|
|
287
|
+
operation,
|
|
288
|
+
response: mockResponse,
|
|
289
|
+
onceOnly,
|
|
290
|
+
used: false
|
|
291
|
+
});
|
|
292
|
+
return mockFn;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
mockFn.mockOperation = (operation, response) => addMockedOperation(operation, response, false);
|
|
296
|
+
|
|
297
|
+
mockFn.mockOperationOnce = (operation, response) => addMockedOperation(operation, response, true);
|
|
298
|
+
|
|
299
|
+
return mockFn;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
/***/ }),
|
|
303
|
+
/* 4 */
|
|
304
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
305
|
+
|
|
223
306
|
"use strict";
|
|
224
307
|
__webpack_require__.r(__webpack_exports__);
|
|
225
|
-
/* harmony import */ var _storybook_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
308
|
+
/* harmony import */ var _storybook_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5);
|
|
226
309
|
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "storybook", function() { return _storybook_js__WEBPACK_IMPORTED_MODULE_0__["a"]; });
|
|
227
310
|
|
|
228
311
|
|
|
229
312
|
|
|
230
313
|
/***/ }),
|
|
231
|
-
/*
|
|
314
|
+
/* 5 */
|
|
232
315
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
233
316
|
|
|
234
317
|
"use strict";
|
|
235
318
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return getAdapter; });
|
|
236
319
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
|
237
320
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
238
|
-
/* harmony import */ var _storybook_addon_actions__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
|
|
321
|
+
/* harmony import */ var _storybook_addon_actions__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9);
|
|
239
322
|
/* harmony import */ var _storybook_addon_actions__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_storybook_addon_actions__WEBPACK_IMPORTED_MODULE_1__);
|
|
240
|
-
/* harmony import */ var _adapter_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(
|
|
323
|
+
/* harmony import */ var _adapter_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(10);
|
|
241
324
|
|
|
242
325
|
|
|
243
326
|
|
|
@@ -247,7 +330,10 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
247
330
|
*/
|
|
248
331
|
const getAdapter = (MountingComponent = null) => new _adapter_js__WEBPACK_IMPORTED_MODULE_2__[/* Adapter */ "a"]("storybook", ({
|
|
249
332
|
title,
|
|
250
|
-
description: groupDescription
|
|
333
|
+
description: groupDescription,
|
|
334
|
+
// We don't use the default title in Storybook as storybook
|
|
335
|
+
// will generate titles for us if we pass a nullish title.
|
|
336
|
+
getDefaultTitle: _
|
|
251
337
|
}, adapterOptions, declaredFixtures) => {
|
|
252
338
|
const templateMap = new WeakMap();
|
|
253
339
|
|
|
@@ -310,7 +396,7 @@ const getAdapter = (MountingComponent = null) => new _adapter_js__WEBPACK_IMPORT
|
|
|
310
396
|
});
|
|
311
397
|
|
|
312
398
|
/***/ }),
|
|
313
|
-
/*
|
|
399
|
+
/* 6 */
|
|
314
400
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
315
401
|
|
|
316
402
|
"use strict";
|
|
@@ -318,11 +404,43 @@ const getAdapter = (MountingComponent = null) => new _adapter_js__WEBPACK_IMPORT
|
|
|
318
404
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
|
319
405
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
320
406
|
/* harmony import */ var _setup_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
|
|
321
|
-
/* harmony import */ var _combine_options_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(
|
|
322
|
-
|
|
323
|
-
|
|
407
|
+
/* harmony import */ var _combine_options_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(12);
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
const normalizeOptions = componentOrOptions => {
|
|
413
|
+
// To differentiate between a React component and a FixturesOptions object,
|
|
414
|
+
// we have to do some type checking.
|
|
415
|
+
//
|
|
416
|
+
// Alternatives I considered were:
|
|
417
|
+
// - Use an additional parameter for the options and then do an arg number
|
|
418
|
+
// check, but that always makes typing a function harder and often breaks
|
|
419
|
+
// types. I didn't want that battle today.
|
|
420
|
+
// - Use a tuple when providing component and options with the first element
|
|
421
|
+
// being the component and the second being the options. However that
|
|
422
|
+
// feels like an obscure API even though it's really easy to do the
|
|
423
|
+
// typing.
|
|
424
|
+
if ( // Most React components, whether functional or class-based, are
|
|
425
|
+
// inherently functions in JavaScript, so a check for functions is
|
|
426
|
+
// usually sufficient.
|
|
427
|
+
typeof componentOrOptions === "function" || // However, the return of React.forwardRef is not a function,
|
|
428
|
+
// so we also have to cope with that.
|
|
429
|
+
// A forwardRef has $$typeof = Symbol(react.forward_ref) and a
|
|
430
|
+
// render function.
|
|
431
|
+
// $FlowIgnore[prop-missing]
|
|
432
|
+
typeof componentOrOptions.render === "function") {
|
|
433
|
+
return {
|
|
434
|
+
// $FlowIgnore[incompatible-return]
|
|
435
|
+
component: componentOrOptions
|
|
436
|
+
};
|
|
437
|
+
} // We can't test for React.ComponentType at runtime.
|
|
438
|
+
// Let's assume our simple heuristic above is sufficient.
|
|
439
|
+
// $FlowIgnore[incompatible-return]
|
|
324
440
|
|
|
325
441
|
|
|
442
|
+
return componentOrOptions;
|
|
443
|
+
};
|
|
326
444
|
/**
|
|
327
445
|
* Describe a group of fixtures for a given component.
|
|
328
446
|
*
|
|
@@ -341,7 +459,9 @@ const getAdapter = (MountingComponent = null) => new _adapter_js__WEBPACK_IMPORT
|
|
|
341
459
|
* storybook, the popular framework, uses both default and named exports for
|
|
342
460
|
* its interface.
|
|
343
461
|
*/
|
|
344
|
-
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
const fixtures = (componentOrOptions, fn) => {
|
|
345
465
|
var _additionalAdapterOpt;
|
|
346
466
|
|
|
347
467
|
const {
|
|
@@ -354,11 +474,12 @@ const fixtures = (options, fn) => {
|
|
|
354
474
|
description: groupDescription,
|
|
355
475
|
defaultWrapper,
|
|
356
476
|
additionalAdapterOptions
|
|
357
|
-
} =
|
|
477
|
+
} = normalizeOptions(componentOrOptions); // 1. Create a new adapter group.
|
|
358
478
|
|
|
359
479
|
const group = adapter.declareGroup({
|
|
360
|
-
title
|
|
361
|
-
description: groupDescription
|
|
480
|
+
title,
|
|
481
|
+
description: groupDescription,
|
|
482
|
+
getDefaultTitle: () => component.displayName || component.name || "Component"
|
|
362
483
|
}); // 2. Invoke fn with a function that can add a new fixture.
|
|
363
484
|
|
|
364
485
|
const addFixture = (description, props, wrapper = null) => {
|
|
@@ -381,80 +502,53 @@ const fixtures = (options, fn) => {
|
|
|
381
502
|
};
|
|
382
503
|
|
|
383
504
|
/***/ }),
|
|
384
|
-
/*
|
|
505
|
+
/* 7 */
|
|
385
506
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
386
507
|
|
|
387
508
|
"use strict";
|
|
388
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return
|
|
389
|
-
/* harmony import */ var
|
|
390
|
-
/* harmony import */ var
|
|
509
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return mockFetch; });
|
|
510
|
+
/* harmony import */ var _fetch_request_matches_mock_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(16);
|
|
511
|
+
/* harmony import */ var _mock_requester_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
|
|
391
512
|
|
|
392
513
|
|
|
393
514
|
|
|
394
515
|
/**
|
|
395
516
|
* A mock for the fetch function passed to GqlRouter.
|
|
396
517
|
*/
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
// This is the array of mocked operations that we will traverse and
|
|
400
|
-
// manipulate.
|
|
401
|
-
const mocks = []; // What we return has to be a drop in for the fetch function that is
|
|
402
|
-
// provided to `GqlRouter` which is how folks will then use this mock.
|
|
403
|
-
|
|
404
|
-
const gqlFetchMock = (operation, variables, context) => {
|
|
405
|
-
// Iterate our mocked operations and find the first one that matches.
|
|
406
|
-
for (const mock of mocks) {
|
|
407
|
-
if (mock.onceOnly && mock.used) {
|
|
408
|
-
// This is a once-only mock and it has been used, so skip it.
|
|
409
|
-
continue;
|
|
410
|
-
}
|
|
518
|
+
const mockFetch = () => Object(_mock_requester_js__WEBPACK_IMPORTED_MODULE_1__[/* mockRequester */ "a"])(_fetch_request_matches_mock_js__WEBPACK_IMPORTED_MODULE_0__[/* fetchRequestMatchesMock */ "a"], (input, init) => `Input: ${typeof input === "string" ? input : JSON.stringify(input, null, 2)}
|
|
519
|
+
Options: ${init == null ? "None" : JSON.stringify(init, null, 2)}`);
|
|
411
520
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
}
|
|
416
|
-
} // Default is to reject with some helpful info on what request
|
|
417
|
-
// we rejected.
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
return Promise.reject(new Error(`No matching GraphQL mock response found for request:
|
|
421
|
-
Operation: ${operation.type} ${operation.id}
|
|
422
|
-
Variables: ${variables == null ? "None" : JSON.stringify(variables, null, 2)}
|
|
423
|
-
Context: ${JSON.stringify(context, null, 2)}`));
|
|
424
|
-
};
|
|
425
|
-
|
|
426
|
-
const addMockedOperation = (operation, response, onceOnly) => {
|
|
427
|
-
const mockResponse = () => Object(_make_gql_mock_response_js__WEBPACK_IMPORTED_MODULE_1__[/* makeGqlMockResponse */ "b"])(response);
|
|
521
|
+
/***/ }),
|
|
522
|
+
/* 8 */
|
|
523
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
428
524
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
used: false
|
|
434
|
-
});
|
|
435
|
-
return gqlFetchMock;
|
|
436
|
-
};
|
|
525
|
+
"use strict";
|
|
526
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return mockGqlFetch; });
|
|
527
|
+
/* harmony import */ var _gql_request_matches_mock_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(17);
|
|
528
|
+
/* harmony import */ var _mock_requester_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
|
|
437
529
|
|
|
438
|
-
gqlFetchMock.mockOperation = (operation, response) => addMockedOperation(operation, response, false);
|
|
439
530
|
|
|
440
|
-
gqlFetchMock.mockOperationOnce = (operation, response) => addMockedOperation(operation, response, true);
|
|
441
531
|
|
|
442
|
-
|
|
443
|
-
|
|
532
|
+
/**
|
|
533
|
+
* A mock for the fetch function passed to GqlRouter.
|
|
534
|
+
*/
|
|
535
|
+
const mockGqlFetch = () => Object(_mock_requester_js__WEBPACK_IMPORTED_MODULE_1__[/* mockRequester */ "a"])(_gql_request_matches_mock_js__WEBPACK_IMPORTED_MODULE_0__[/* gqlRequestMatchesMock */ "a"], (operation, variables, context) => `Operation: ${operation.type} ${operation.id}
|
|
536
|
+
Variables: ${variables == null ? "None" : JSON.stringify(variables, null, 2)}
|
|
537
|
+
Context: ${JSON.stringify(context, null, 2)}`);
|
|
444
538
|
|
|
445
539
|
/***/ }),
|
|
446
|
-
/*
|
|
540
|
+
/* 9 */
|
|
447
541
|
/***/ (function(module, exports) {
|
|
448
542
|
|
|
449
543
|
module.exports = require("@storybook/addon-actions");
|
|
450
544
|
|
|
451
545
|
/***/ }),
|
|
452
|
-
/*
|
|
546
|
+
/* 10 */
|
|
453
547
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
454
548
|
|
|
455
549
|
"use strict";
|
|
456
550
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Adapter; });
|
|
457
|
-
/* harmony import */ var _adapter_group_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
551
|
+
/* harmony import */ var _adapter_group_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(11);
|
|
458
552
|
|
|
459
553
|
|
|
460
554
|
/**
|
|
@@ -509,7 +603,7 @@ class Adapter {
|
|
|
509
603
|
}
|
|
510
604
|
|
|
511
605
|
/***/ }),
|
|
512
|
-
/*
|
|
606
|
+
/* 11 */
|
|
513
607
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
514
608
|
|
|
515
609
|
"use strict";
|
|
@@ -574,12 +668,12 @@ class AdapterGroup {
|
|
|
574
668
|
}
|
|
575
669
|
|
|
576
670
|
/***/ }),
|
|
577
|
-
/*
|
|
671
|
+
/* 12 */
|
|
578
672
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
579
673
|
|
|
580
674
|
"use strict";
|
|
581
675
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return combineOptions; });
|
|
582
|
-
/* harmony import */ var _combine_top_level_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
676
|
+
/* harmony import */ var _combine_top_level_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(13);
|
|
583
677
|
|
|
584
678
|
/**
|
|
585
679
|
* Combine one or more objects into a single object.
|
|
@@ -604,12 +698,12 @@ const combineOptions = (...toBeCombined) => {
|
|
|
604
698
|
};
|
|
605
699
|
|
|
606
700
|
/***/ }),
|
|
607
|
-
/*
|
|
701
|
+
/* 13 */
|
|
608
702
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
609
703
|
|
|
610
704
|
"use strict";
|
|
611
705
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return combineTopLevel; });
|
|
612
|
-
/* harmony import */ var _khanacademy_wonder_stuff_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
706
|
+
/* harmony import */ var _khanacademy_wonder_stuff_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(14);
|
|
613
707
|
/* harmony import */ var _khanacademy_wonder_stuff_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_stuff_core__WEBPACK_IMPORTED_MODULE_0__);
|
|
614
708
|
|
|
615
709
|
/**
|
|
@@ -650,13 +744,69 @@ const combineTopLevel = (val1, val2) => {
|
|
|
650
744
|
};
|
|
651
745
|
|
|
652
746
|
/***/ }),
|
|
653
|
-
/*
|
|
747
|
+
/* 14 */
|
|
654
748
|
/***/ (function(module, exports) {
|
|
655
749
|
|
|
656
750
|
module.exports = require("@khanacademy/wonder-stuff-core");
|
|
657
751
|
|
|
658
752
|
/***/ }),
|
|
659
|
-
/*
|
|
753
|
+
/* 15 */
|
|
754
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
755
|
+
|
|
756
|
+
"use strict";
|
|
757
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ResponseImpl; });
|
|
758
|
+
// We need a version of Response. When we're in Jest JSDOM environment or a
|
|
759
|
+
// version of Node that supports the fetch API (17 and up, possibly with
|
|
760
|
+
// --experimental-fetch flag), then we're good, but otherwise we need an
|
|
761
|
+
// implementation, so this uses node-fetch as a peer dependency and uses that
|
|
762
|
+
// to provide the implementation if we don't already have one.
|
|
763
|
+
const ResponseImpl = typeof Response === "undefined" ? __webpack_require__(19).Response : Response;
|
|
764
|
+
|
|
765
|
+
/***/ }),
|
|
766
|
+
/* 16 */
|
|
767
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
768
|
+
|
|
769
|
+
"use strict";
|
|
770
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return fetchRequestMatchesMock; });
|
|
771
|
+
/**
|
|
772
|
+
* Get the URL from the given RequestInfo.
|
|
773
|
+
*
|
|
774
|
+
* Since we could be running in Node or in JSDOM, we don't check instance
|
|
775
|
+
* types, but just use a heuristic so that this works without knowing what
|
|
776
|
+
* was polyfilling things.
|
|
777
|
+
*/
|
|
778
|
+
const getHref = input => {
|
|
779
|
+
if (typeof input === "string") {
|
|
780
|
+
return input;
|
|
781
|
+
} else if (typeof input.url === "string") {
|
|
782
|
+
return input.url;
|
|
783
|
+
} else if (typeof input.href === "string") {
|
|
784
|
+
return input.href;
|
|
785
|
+
} else {
|
|
786
|
+
throw new Error(`Unsupported input type`);
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
/**
|
|
790
|
+
* Determines if a given fetch invocation matches the given mock.
|
|
791
|
+
*/
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
const fetchRequestMatchesMock = (mock, input, init) => {
|
|
795
|
+
// Currently, we only match on the input portion.
|
|
796
|
+
// This can be a Request, a URL, or a string.
|
|
797
|
+
const href = getHref(input); // Our mock operation is either a string for an exact match, or a regex.
|
|
798
|
+
|
|
799
|
+
if (typeof mock === "string") {
|
|
800
|
+
return href === mock;
|
|
801
|
+
} else if (mock instanceof RegExp) {
|
|
802
|
+
return mock.test(href);
|
|
803
|
+
} else {
|
|
804
|
+
throw new Error(`Unsupported mock operation: ${JSON.stringify(mock)}`);
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
/***/ }),
|
|
809
|
+
/* 17 */
|
|
660
810
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
661
811
|
|
|
662
812
|
"use strict";
|
|
@@ -731,33 +881,42 @@ const gqlRequestMatchesMock = (mock, operation, variables, context) => {
|
|
|
731
881
|
};
|
|
732
882
|
|
|
733
883
|
/***/ }),
|
|
734
|
-
/*
|
|
884
|
+
/* 18 */
|
|
735
885
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
736
886
|
|
|
737
887
|
"use strict";
|
|
738
888
|
__webpack_require__.r(__webpack_exports__);
|
|
739
|
-
/* harmony import */ var _fixtures_adapters_adapters_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
889
|
+
/* harmony import */ var _fixtures_adapters_adapters_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
|
|
740
890
|
/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "adapters", function() { return _fixtures_adapters_adapters_js__WEBPACK_IMPORTED_MODULE_0__; });
|
|
741
|
-
/* harmony import */ var _fixtures_fixtures_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
|
|
891
|
+
/* harmony import */ var _fixtures_fixtures_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6);
|
|
742
892
|
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "fixtures", function() { return _fixtures_fixtures_js__WEBPACK_IMPORTED_MODULE_1__["a"]; });
|
|
743
893
|
|
|
744
894
|
/* harmony import */ var _fixtures_setup_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(0);
|
|
745
895
|
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "setupFixtures", function() { return _fixtures_setup_js__WEBPACK_IMPORTED_MODULE_2__["b"]; });
|
|
746
896
|
|
|
747
|
-
/* harmony import */ var
|
|
748
|
-
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "
|
|
897
|
+
/* harmony import */ var _make_mock_response_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(1);
|
|
898
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "RespondWith", function() { return _make_mock_response_js__WEBPACK_IMPORTED_MODULE_3__["a"]; });
|
|
899
|
+
|
|
900
|
+
/* harmony import */ var _fetch_mock_fetch_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(7);
|
|
901
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mockFetch", function() { return _fetch_mock_fetch_js__WEBPACK_IMPORTED_MODULE_4__["a"]; });
|
|
749
902
|
|
|
750
|
-
/* harmony import */ var
|
|
751
|
-
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "
|
|
903
|
+
/* harmony import */ var _gql_mock_gql_fetch_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(8);
|
|
904
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mockGqlFetch", function() { return _gql_mock_gql_fetch_js__WEBPACK_IMPORTED_MODULE_5__["a"]; });
|
|
752
905
|
|
|
753
906
|
// Fixtures framework
|
|
754
907
|
|
|
755
908
|
|
|
756
909
|
|
|
757
910
|
|
|
758
|
-
// GraphQL framework
|
|
759
911
|
|
|
760
912
|
|
|
761
913
|
|
|
914
|
+
|
|
915
|
+
/***/ }),
|
|
916
|
+
/* 19 */
|
|
917
|
+
/***/ (function(module, exports) {
|
|
918
|
+
|
|
919
|
+
module.exports = require("node-fetch");
|
|
920
|
+
|
|
762
921
|
/***/ })
|
|
763
922
|
/******/ ]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-testing",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"design": "v1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"@khanacademy/wonder-stuff-core": "^0.1.2",
|
|
21
21
|
"@khanacademy/wonder-stuff-testing": "^0.0.2",
|
|
22
22
|
"@storybook/addon-actions": "^6.4.8",
|
|
23
|
+
"node-fetch": "^2.6.7",
|
|
23
24
|
"react": "16.14.0"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|