@khanacademy/wonder-blocks-testing 7.0.5 → 7.1.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 -0
- package/dist/es/index.js +160 -62
- package/dist/index.js +326 -167
- package/package.json +1 -1
- package/src/__docs__/exports.respond-with.stories.mdx +17 -6
- package/src/__docs__/exports.settle-controller.stories.mdx +32 -0
- package/src/__docs__/types.mock-response.stories.mdx +6 -2
- package/src/__tests__/mock-requester.test.js +1 -1
- package/src/__tests__/respond-with.test.js +525 -0
- package/src/__tests__/settle-controller.test.js +29 -0
- package/src/__tests__/settle-signal.test.js +105 -0
- package/src/fetch/__tests__/mock-fetch.test.js +1 -1
- package/src/fetch/types.js +1 -1
- package/src/gql/__tests__/mock-gql-fetch.test.js +1 -1
- package/src/gql/__tests__/wb-data-integration.test.js +1 -1
- package/src/gql/types.js +1 -1
- package/src/index.js +3 -2
- package/src/mock-requester.js +2 -3
- package/src/respond-with.js +236 -0
- package/src/settle-controller.js +35 -0
- package/src/settle-signal.js +41 -0
- package/src/types.js +1 -1
- package/src/__tests__/make-mock-response.test.js +0 -460
- package/src/make-mock-response.js +0 -150
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-testing
|
|
2
2
|
|
|
3
|
+
## 7.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 17301778: Add `toPromise` method to mock responses
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- d5a13e6d: `RespondWith` API now supports a signal for controlling the settlement of the promise. Introduces `SettleController` to support this new feature.
|
|
12
|
+
|
|
3
13
|
## 7.0.5
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/dist/es/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { action } from '@storybook/addon-actions';
|
|
3
|
+
import _classPrivateFieldLooseBase from '@babel/runtime/helpers/classPrivateFieldLooseBase';
|
|
4
|
+
import _classPrivateFieldLooseKey from '@babel/runtime/helpers/classPrivateFieldLooseKey';
|
|
3
5
|
import { InterceptRequests } from '@khanacademy/wonder-blocks-data';
|
|
4
6
|
import { StaticRouter, MemoryRouter, Switch, Route } from 'react-router-dom';
|
|
5
7
|
import _extends from '@babel/runtime/helpers/extends';
|
|
@@ -59,66 +61,6 @@ const fetchRequestMatchesMock = (mock, input, init) => {
|
|
|
59
61
|
}
|
|
60
62
|
};
|
|
61
63
|
|
|
62
|
-
const ResponseImpl = typeof Response === "undefined" ? require("node-fetch").Response : Response;
|
|
63
|
-
|
|
64
|
-
const textResponse = (text, statusCode = 200) => ({
|
|
65
|
-
type: "text",
|
|
66
|
-
text,
|
|
67
|
-
statusCode
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
const rejectResponse = error => ({
|
|
71
|
-
type: "reject",
|
|
72
|
-
error
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const RespondWith = Object.freeze({
|
|
76
|
-
text: (text, statusCode = 200) => textResponse(text, statusCode),
|
|
77
|
-
json: json => textResponse(() => JSON.stringify(json)),
|
|
78
|
-
graphQLData: data => textResponse(() => JSON.stringify({
|
|
79
|
-
data
|
|
80
|
-
})),
|
|
81
|
-
unparseableBody: () => textResponse("INVALID JSON"),
|
|
82
|
-
abortedRequest: () => rejectResponse(() => {
|
|
83
|
-
const abortError = new Error("Mock request aborted");
|
|
84
|
-
abortError.name = "AbortError";
|
|
85
|
-
return abortError;
|
|
86
|
-
}),
|
|
87
|
-
reject: error => rejectResponse(error),
|
|
88
|
-
errorStatusCode: statusCode => {
|
|
89
|
-
if (statusCode < 300) {
|
|
90
|
-
throw new Error(`${statusCode} is not a valid error status code`);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return textResponse("{}", statusCode);
|
|
94
|
-
},
|
|
95
|
-
nonGraphQLBody: () => textResponse(() => JSON.stringify({
|
|
96
|
-
valid: "json",
|
|
97
|
-
that: "is not a valid graphql response"
|
|
98
|
-
})),
|
|
99
|
-
graphQLErrors: errorMessages => textResponse(() => JSON.stringify({
|
|
100
|
-
errors: errorMessages.map(e => ({
|
|
101
|
-
message: e
|
|
102
|
-
}))
|
|
103
|
-
}))
|
|
104
|
-
});
|
|
105
|
-
const makeMockResponse = response => {
|
|
106
|
-
switch (response.type) {
|
|
107
|
-
case "text":
|
|
108
|
-
const text = typeof response.text === "function" ? response.text() : response.text;
|
|
109
|
-
return Promise.resolve(new ResponseImpl(text, {
|
|
110
|
-
status: response.statusCode
|
|
111
|
-
}));
|
|
112
|
-
|
|
113
|
-
case "reject":
|
|
114
|
-
const error = response.error instanceof Error ? response.error : response.error();
|
|
115
|
-
return Promise.reject(error);
|
|
116
|
-
|
|
117
|
-
default:
|
|
118
|
-
throw new Error(`Unknown response type: ${response.type}`);
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
64
|
const mockRequester = (operationMatcher, operationToString) => {
|
|
123
65
|
const mocks = [];
|
|
124
66
|
|
|
@@ -139,7 +81,7 @@ const mockRequester = (operationMatcher, operationToString) => {
|
|
|
139
81
|
};
|
|
140
82
|
|
|
141
83
|
const addMockedOperation = (operation, response, onceOnly) => {
|
|
142
|
-
const mockResponse = () =>
|
|
84
|
+
const mockResponse = () => response.toPromise();
|
|
143
85
|
|
|
144
86
|
mocks.push({
|
|
145
87
|
operation,
|
|
@@ -217,6 +159,162 @@ const mockGqlFetch = () => mockRequester(gqlRequestMatchesMock, (operation, vari
|
|
|
217
159
|
Variables: ${variables == null ? "None" : JSON.stringify(variables, null, 2)}
|
|
218
160
|
Context: ${JSON.stringify(context, null, 2)}`);
|
|
219
161
|
|
|
162
|
+
var _settled = _classPrivateFieldLooseKey("settled");
|
|
163
|
+
|
|
164
|
+
class SettleSignal extends EventTarget {
|
|
165
|
+
constructor(setSettleFn = null) {
|
|
166
|
+
super();
|
|
167
|
+
Object.defineProperty(this, _settled, {
|
|
168
|
+
writable: true,
|
|
169
|
+
value: false
|
|
170
|
+
});
|
|
171
|
+
setSettleFn == null ? void 0 : setSettleFn(() => {
|
|
172
|
+
if (_classPrivateFieldLooseBase(this, _settled)[_settled]) {
|
|
173
|
+
throw new Error("SettleSignal already settled");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
_classPrivateFieldLooseBase(this, _settled)[_settled] = true;
|
|
177
|
+
this.dispatchEvent(new Event("settled"));
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
static settle() {
|
|
182
|
+
const signal = new SettleSignal();
|
|
183
|
+
_classPrivateFieldLooseBase(signal, _settled)[_settled] = true;
|
|
184
|
+
return signal;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
get settled() {
|
|
188
|
+
return _classPrivateFieldLooseBase(this, _settled)[_settled];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const ResponseImpl = typeof Response === "undefined" ? require("node-fetch").Response : Response;
|
|
194
|
+
|
|
195
|
+
const textResponse = (text, statusCode, signal) => ({
|
|
196
|
+
toPromise: () => makeMockResponse({
|
|
197
|
+
type: "text",
|
|
198
|
+
text,
|
|
199
|
+
statusCode,
|
|
200
|
+
signal
|
|
201
|
+
})
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const rejectResponse = (error, signal) => ({
|
|
205
|
+
toPromise: () => makeMockResponse({
|
|
206
|
+
type: "reject",
|
|
207
|
+
error,
|
|
208
|
+
signal
|
|
209
|
+
})
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
const RespondWith = Object.freeze({
|
|
213
|
+
text: (text, statusCode = 200, signal = null) => textResponse(text, statusCode, signal),
|
|
214
|
+
json: (json, signal = null) => textResponse(() => JSON.stringify(json), 200, signal),
|
|
215
|
+
graphQLData: (data, signal = null) => textResponse(() => JSON.stringify({
|
|
216
|
+
data
|
|
217
|
+
}), 200, signal),
|
|
218
|
+
unparseableBody: (signal = null) => textResponse("INVALID JSON", 200, signal),
|
|
219
|
+
abortedRequest: (signal = null) => rejectResponse(() => {
|
|
220
|
+
const abortError = new Error("Mock request aborted");
|
|
221
|
+
abortError.name = "AbortError";
|
|
222
|
+
return abortError;
|
|
223
|
+
}, signal),
|
|
224
|
+
reject: (error, signal = null) => rejectResponse(error, signal),
|
|
225
|
+
errorStatusCode: (statusCode, signal = null) => {
|
|
226
|
+
if (statusCode < 300) {
|
|
227
|
+
throw new Error(`${statusCode} is not a valid error status code`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return textResponse("{}", statusCode, signal);
|
|
231
|
+
},
|
|
232
|
+
nonGraphQLBody: (signal = null) => textResponse(() => JSON.stringify({
|
|
233
|
+
valid: "json",
|
|
234
|
+
that: "is not a valid graphql response"
|
|
235
|
+
}), 200, signal),
|
|
236
|
+
graphQLErrors: (errorMessages, signal = null) => textResponse(() => JSON.stringify({
|
|
237
|
+
errors: errorMessages.map(e => ({
|
|
238
|
+
message: e
|
|
239
|
+
}))
|
|
240
|
+
}), 200, signal)
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
const callOnSettled = (signal, fn) => {
|
|
244
|
+
if (signal == null || signal.settled) {
|
|
245
|
+
fn();
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const onSettled = () => {
|
|
250
|
+
signal.removeEventListener("settled", onSettled);
|
|
251
|
+
fn();
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
signal.addEventListener("settled", onSettled);
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const makeMockResponse = response => {
|
|
258
|
+
const {
|
|
259
|
+
signal
|
|
260
|
+
} = response;
|
|
261
|
+
|
|
262
|
+
switch (response.type) {
|
|
263
|
+
case "text":
|
|
264
|
+
return new Promise((resolve, reject) => {
|
|
265
|
+
callOnSettled(signal, () => {
|
|
266
|
+
const text = typeof response.text === "function" ? response.text() : response.text;
|
|
267
|
+
resolve(new ResponseImpl(text, {
|
|
268
|
+
status: response.statusCode
|
|
269
|
+
}));
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
case "reject":
|
|
274
|
+
return new Promise((resolve, reject) => {
|
|
275
|
+
callOnSettled(signal, () => reject(response.error instanceof Error ? response.error : response.error()));
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
default:
|
|
279
|
+
if (process.env.NODE_ENV !== "production") {
|
|
280
|
+
throw new Error(`Unknown response type: ${response.type}`);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return makeMockResponse({
|
|
284
|
+
type: "reject",
|
|
285
|
+
error: new Error("Unknown response type"),
|
|
286
|
+
signal
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
var _settleFn = _classPrivateFieldLooseKey("settleFn");
|
|
292
|
+
|
|
293
|
+
var _signal = _classPrivateFieldLooseKey("signal");
|
|
294
|
+
|
|
295
|
+
class SettleController {
|
|
296
|
+
constructor() {
|
|
297
|
+
Object.defineProperty(this, _settleFn, {
|
|
298
|
+
writable: true,
|
|
299
|
+
value: void 0
|
|
300
|
+
});
|
|
301
|
+
Object.defineProperty(this, _signal, {
|
|
302
|
+
writable: true,
|
|
303
|
+
value: void 0
|
|
304
|
+
});
|
|
305
|
+
_classPrivateFieldLooseBase(this, _signal)[_signal] = new SettleSignal(settleFn => _classPrivateFieldLooseBase(this, _settleFn)[_settleFn] = settleFn);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
get signal() {
|
|
309
|
+
return _classPrivateFieldLooseBase(this, _signal)[_signal];
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
settle() {
|
|
313
|
+
_classPrivateFieldLooseBase(this, _settleFn)[_settleFn]();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
}
|
|
317
|
+
|
|
220
318
|
const defaultConfig$3 = null;
|
|
221
319
|
|
|
222
320
|
const normalizeConfig = config => {
|
|
@@ -401,4 +499,4 @@ const hookHarness = makeHookHarness(DefaultAdapters, DefaultConfigs);
|
|
|
401
499
|
|
|
402
500
|
const testHarness = makeTestHarness(DefaultAdapters, DefaultConfigs);
|
|
403
501
|
|
|
404
|
-
export { RespondWith, fixtures, adapters as harnessAdapters, hookHarness, makeHookHarness, makeTestHarness, mockFetch, mockGqlFetch, testHarness };
|
|
502
|
+
export { RespondWith, SettleController, fixtures, adapters as harnessAdapters, hookHarness, makeHookHarness, makeTestHarness, mockFetch, mockGqlFetch, testHarness };
|