@khanacademy/wonder-blocks-testing 4.0.2 → 5.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 +21 -0
- package/dist/es/index.js +212 -26
- package/dist/index.js +589 -62
- package/package.json +5 -3
- package/src/__docs__/_overview_.stories.mdx +3 -4
- package/src/__docs__/_overview_fixtures.stories.mdx +22 -0
- package/src/__docs__/_overview_mocking.stories.mdx +14 -0
- package/src/__docs__/_overview_test_harness.stories.mdx +18 -0
- package/src/__docs__/exports.fixture-adapters.stories.mdx +49 -0
- package/src/__docs__/exports.fixtures.stories.mdx +53 -0
- package/src/__docs__/exports.harness-adapters.stories.mdx +187 -0
- package/src/__docs__/exports.hook-harness.stories.mdx +22 -0
- package/src/__docs__/exports.make-hook-harness.stories.mdx +25 -0
- package/src/__docs__/exports.make-test-harness.stories.mdx +28 -0
- package/src/__docs__/exports.mock-fetch.stories.mdx +40 -0
- package/src/__docs__/exports.mock-gql-fetch.stories.mdx +13 -8
- package/src/__docs__/exports.respond-with.stories.mdx +54 -8
- package/src/__docs__/exports.setup-fixtures.stories.mdx +22 -0
- package/src/__docs__/exports.test-harness.stories.mdx +23 -0
- package/src/__docs__/types.custom-mount-props.stories.mdx +35 -0
- package/src/__docs__/types.fetch-mock-fn.stories.mdx +22 -0
- package/src/__docs__/types.fetch-mock-operation.stories.mdx +18 -0
- package/src/__docs__/types.fixtures-adapter-factory.stories.mdx +23 -0
- package/src/__docs__/types.fixtures-adapter-fixture-options.stories.mdx +35 -0
- package/src/__docs__/types.fixtures-adapter-group-options.stories.mdx +37 -0
- package/src/__docs__/types.fixtures-adapter-group.stories.mdx +43 -0
- package/src/__docs__/types.fixtures-adapter-options.stories.mdx +21 -0
- package/src/__docs__/types.fixtures-adapter.stories.mdx +35 -0
- package/src/__docs__/types.fixtures-configuration.stories.mdx +35 -0
- package/src/__docs__/types.fixtures-options.stories.mdx +51 -0
- package/src/__docs__/types.get-props-options.stories.mdx +25 -0
- package/src/__docs__/types.gql-fetch-mock-fn.stories.mdx +27 -0
- package/src/__docs__/types.gql-mock-operation.stories.mdx +26 -0
- package/src/__docs__/types.mock-response.stories.mdx +18 -0
- package/src/__docs__/types.test-harness-adapter.stories.mdx +21 -0
- package/src/__docs__/types.test-harness-adapters.stories.mdx +46 -0
- package/src/__docs__/types.test-harness-config.stories.mdx +18 -0
- package/src/__docs__/types.test-harness-configs.stories.mdx +59 -0
- package/src/fetch/types.js +0 -3
- package/src/fixtures/adapters/adapter-group.js +11 -11
- package/src/fixtures/adapters/adapter.js +8 -8
- package/src/fixtures/adapters/storybook.js +11 -8
- package/src/fixtures/fixtures.basic.stories.js +6 -2
- package/src/fixtures/fixtures.defaultwrapper.stories.js +6 -2
- package/src/fixtures/setup.js +8 -4
- package/src/fixtures/types.js +27 -16
- package/src/gql/types.js +1 -3
- package/src/harness/__tests__/hook-harness.test.js +72 -0
- package/src/harness/__tests__/make-hook-harness.test.js +94 -0
- package/src/harness/__tests__/make-test-harness.test.js +190 -0
- package/src/harness/__tests__/render-adapters.test.js +88 -0
- package/src/harness/__tests__/test-harness.test.js +74 -0
- package/src/harness/adapters/__tests__/__snapshots__/router.test.js.snap +5 -0
- package/src/harness/adapters/__tests__/css.test.js +96 -0
- package/src/harness/adapters/__tests__/data.test.js +66 -0
- package/src/harness/adapters/__tests__/portal.test.js +31 -0
- package/src/harness/adapters/__tests__/router.test.js +233 -0
- package/src/harness/adapters/adapters.js +33 -0
- package/src/harness/adapters/css.js +65 -0
- package/src/harness/adapters/data.js +46 -0
- package/src/harness/adapters/portal.js +26 -0
- package/src/harness/adapters/router.js +206 -0
- package/src/harness/hook-harness.js +23 -0
- package/src/harness/make-hook-harness.js +39 -0
- package/src/harness/make-test-harness.js +68 -0
- package/src/harness/render-adapters.js +27 -0
- package/src/harness/test-harness.js +24 -0
- package/src/harness/types.js +57 -0
- package/src/index.js +22 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-testing
|
|
2
2
|
|
|
3
|
+
## 5.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 217b2c7b: Add test harness framework
|
|
8
|
+
- a8d9a825: Adapters for fixture framework now exported as `fixtureAdapters`, adapters for test harness framework now exported as `harnessAdapters`. Various types renamed for disambiguation. `FetchMock` and `GqlMock` export types removed.
|
|
9
|
+
|
|
10
|
+
## 4.0.4
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [580141ed]
|
|
15
|
+
- @khanacademy/wonder-blocks-data@8.0.2
|
|
16
|
+
|
|
17
|
+
## 4.0.3
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [e5fa4d9e]
|
|
22
|
+
- @khanacademy/wonder-blocks-data@8.0.1
|
|
23
|
+
|
|
3
24
|
## 4.0.2
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
package/dist/es/index.js
CHANGED
|
@@ -2,6 +2,8 @@ import _extends from '@babel/runtime/helpers/extends';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { action } from '@storybook/addon-actions';
|
|
4
4
|
import { clone } from '@khanacademy/wonder-stuff-core';
|
|
5
|
+
import { InterceptRequests } from '@khanacademy/wonder-blocks-data';
|
|
6
|
+
import { StaticRouter, MemoryRouter, Switch, Route } from 'react-router-dom';
|
|
5
7
|
|
|
6
8
|
class AdapterGroup {
|
|
7
9
|
constructor(closeGroupFn, _options) {
|
|
@@ -113,7 +115,7 @@ const getAdapter = (MountingComponent = null) => new Adapter("storybook", ({
|
|
|
113
115
|
return Object.freeze(exports);
|
|
114
116
|
});
|
|
115
117
|
|
|
116
|
-
var adapters = /*#__PURE__*/Object.freeze({
|
|
118
|
+
var adapters$1 = /*#__PURE__*/Object.freeze({
|
|
117
119
|
__proto__: null,
|
|
118
120
|
storybook: getAdapter
|
|
119
121
|
});
|
|
@@ -204,6 +206,30 @@ const fixtures = (componentOrOptions, fn) => {
|
|
|
204
206
|
return group.closeGroup(combinedAdapterOptions);
|
|
205
207
|
};
|
|
206
208
|
|
|
209
|
+
const getHref = input => {
|
|
210
|
+
if (typeof input === "string") {
|
|
211
|
+
return input;
|
|
212
|
+
} else if (typeof input.url === "string") {
|
|
213
|
+
return input.url;
|
|
214
|
+
} else if (typeof input.href === "string") {
|
|
215
|
+
return input.href;
|
|
216
|
+
} else {
|
|
217
|
+
throw new Error(`Unsupported input type`);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const fetchRequestMatchesMock = (mock, input, init) => {
|
|
222
|
+
const href = getHref(input);
|
|
223
|
+
|
|
224
|
+
if (typeof mock === "string") {
|
|
225
|
+
return href === mock;
|
|
226
|
+
} else if (mock instanceof RegExp) {
|
|
227
|
+
return mock.test(href);
|
|
228
|
+
} else {
|
|
229
|
+
throw new Error(`Unsupported mock operation: ${JSON.stringify(mock)}`);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
207
233
|
const ResponseImpl = typeof Response === "undefined" ? require("node-fetch").Response : Response;
|
|
208
234
|
|
|
209
235
|
const textResponse = (text, statusCode = 200) => ({
|
|
@@ -264,30 +290,6 @@ const makeMockResponse = response => {
|
|
|
264
290
|
}
|
|
265
291
|
};
|
|
266
292
|
|
|
267
|
-
const getHref = input => {
|
|
268
|
-
if (typeof input === "string") {
|
|
269
|
-
return input;
|
|
270
|
-
} else if (typeof input.url === "string") {
|
|
271
|
-
return input.url;
|
|
272
|
-
} else if (typeof input.href === "string") {
|
|
273
|
-
return input.href;
|
|
274
|
-
} else {
|
|
275
|
-
throw new Error(`Unsupported input type`);
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
const fetchRequestMatchesMock = (mock, input, init) => {
|
|
280
|
-
const href = getHref(input);
|
|
281
|
-
|
|
282
|
-
if (typeof mock === "string") {
|
|
283
|
-
return href === mock;
|
|
284
|
-
} else if (mock instanceof RegExp) {
|
|
285
|
-
return mock.test(href);
|
|
286
|
-
} else {
|
|
287
|
-
throw new Error(`Unsupported mock operation: ${JSON.stringify(mock)}`);
|
|
288
|
-
}
|
|
289
|
-
};
|
|
290
|
-
|
|
291
293
|
const mockRequester = (operationMatcher, operationToString) => {
|
|
292
294
|
const mocks = [];
|
|
293
295
|
|
|
@@ -386,4 +388,188 @@ const mockGqlFetch = () => mockRequester(gqlRequestMatchesMock, (operation, vari
|
|
|
386
388
|
Variables: ${variables == null ? "None" : JSON.stringify(variables, null, 2)}
|
|
387
389
|
Context: ${JSON.stringify(context, null, 2)}`);
|
|
388
390
|
|
|
389
|
-
|
|
391
|
+
const defaultConfig$3 = null;
|
|
392
|
+
|
|
393
|
+
const normalizeConfig = config => {
|
|
394
|
+
if (typeof config === "string") {
|
|
395
|
+
return {
|
|
396
|
+
classes: [config],
|
|
397
|
+
style: {}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (Array.isArray(config)) {
|
|
402
|
+
return {
|
|
403
|
+
classes: config,
|
|
404
|
+
style: {}
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (typeof config === "object") {
|
|
409
|
+
if (config.classes != null && config.style != null) {
|
|
410
|
+
return config;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return {
|
|
414
|
+
classes: [],
|
|
415
|
+
style: config
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
throw new Error(`Invalid config: ${config}`);
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
const adapter$3 = (children, config) => {
|
|
423
|
+
const {
|
|
424
|
+
classes,
|
|
425
|
+
style
|
|
426
|
+
} = normalizeConfig(config);
|
|
427
|
+
return React.createElement("div", {
|
|
428
|
+
"data-test-id": "css-adapter-container",
|
|
429
|
+
className: classes.join(" "),
|
|
430
|
+
style: style
|
|
431
|
+
}, children);
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
const defaultConfig$2 = [];
|
|
435
|
+
const adapter$2 = (children, config) => {
|
|
436
|
+
let currentChildren = children;
|
|
437
|
+
const interceptors = Array.isArray(config) ? config : [config];
|
|
438
|
+
|
|
439
|
+
for (const interceptor of interceptors) {
|
|
440
|
+
currentChildren = React.createElement(InterceptRequests, {
|
|
441
|
+
interceptor: interceptor
|
|
442
|
+
}, currentChildren);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return React.createElement(React.Fragment, null, currentChildren);
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
const defaultConfig$1 = null;
|
|
449
|
+
const adapter$1 = (children, config) => React.createElement(React.Fragment, null, React.createElement("div", {
|
|
450
|
+
id: config,
|
|
451
|
+
"data-test-id": config
|
|
452
|
+
}), children);
|
|
453
|
+
|
|
454
|
+
const defaultConfig = {
|
|
455
|
+
location: "/"
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
const maybeWithRoute = (children, path) => {
|
|
459
|
+
if (path == null) {
|
|
460
|
+
return children;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return React.createElement(Switch, null, React.createElement(Route, {
|
|
464
|
+
exact: true,
|
|
465
|
+
path: path
|
|
466
|
+
}, children), React.createElement(Route, {
|
|
467
|
+
path: "*",
|
|
468
|
+
render: () => {
|
|
469
|
+
throw new Error("The configured path must match the configured location or your harnessed component will not render.");
|
|
470
|
+
}
|
|
471
|
+
}));
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const adapter = (children, config) => {
|
|
475
|
+
if (typeof config === "string") {
|
|
476
|
+
config = {
|
|
477
|
+
location: config
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const wrappedWithRoute = maybeWithRoute(children, config.path);
|
|
482
|
+
|
|
483
|
+
if (config.forceStatic) {
|
|
484
|
+
return React.createElement(StaticRouter, {
|
|
485
|
+
location: config.location,
|
|
486
|
+
context: {}
|
|
487
|
+
}, wrappedWithRoute);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (typeof config.location !== "undefined") {
|
|
491
|
+
return React.createElement(MemoryRouter, {
|
|
492
|
+
initialEntries: [config.location]
|
|
493
|
+
}, wrappedWithRoute);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (typeof config.initialEntries === "undefined") {
|
|
497
|
+
throw new Error("A location or initial history entries must be provided.");
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const entries = config.initialEntries.length === 0 ? [defaultConfig.location] : config.initialEntries;
|
|
501
|
+
const routerProps = {
|
|
502
|
+
initialEntries: entries
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
if (config.initialIndex != null) {
|
|
506
|
+
routerProps.initialIndex = config.initialIndex;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (config.getUserConfirmation != null) {
|
|
510
|
+
routerProps.getUserConfirmation = config.getUserConfirmation;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return React.createElement(MemoryRouter, routerProps, wrappedWithRoute);
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
const DefaultAdapters = {
|
|
517
|
+
css: adapter$3,
|
|
518
|
+
data: adapter$2,
|
|
519
|
+
portal: adapter$1,
|
|
520
|
+
router: adapter
|
|
521
|
+
};
|
|
522
|
+
const DefaultConfigs = {
|
|
523
|
+
css: defaultConfig$3,
|
|
524
|
+
data: defaultConfig$2,
|
|
525
|
+
portal: defaultConfig$1,
|
|
526
|
+
router: defaultConfig
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
var adapters = /*#__PURE__*/Object.freeze({
|
|
530
|
+
__proto__: null,
|
|
531
|
+
DefaultAdapters: DefaultAdapters,
|
|
532
|
+
DefaultConfigs: DefaultConfigs
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
const renderAdapters = (adapters, configs, children) => {
|
|
536
|
+
let currentChildren = children;
|
|
537
|
+
|
|
538
|
+
for (const adapterName of Object.keys(adapters)) {
|
|
539
|
+
const adapter = adapters[adapterName];
|
|
540
|
+
const config = configs[adapterName];
|
|
541
|
+
|
|
542
|
+
if (config != null) {
|
|
543
|
+
currentChildren = adapter(currentChildren, config);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
return currentChildren;
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
const makeTestHarness = (adapters, defaultConfigs) => {
|
|
551
|
+
return (Component, configs) => {
|
|
552
|
+
const fullConfig = _extends({}, defaultConfigs, configs);
|
|
553
|
+
|
|
554
|
+
const harnessedComponent = React.forwardRef((props, ref) => renderAdapters(adapters, fullConfig, React.createElement(Component, _extends({}, props, {
|
|
555
|
+
ref: ref
|
|
556
|
+
}))));
|
|
557
|
+
harnessedComponent.displayName = `testHarness(${Component.displayName || Component.name || "Component"})`;
|
|
558
|
+
return harnessedComponent;
|
|
559
|
+
};
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
const HookHarness = ({
|
|
563
|
+
children
|
|
564
|
+
}) => children;
|
|
565
|
+
|
|
566
|
+
const makeHookHarness = (adapters, defaultConfigs) => {
|
|
567
|
+
const testHarness = makeTestHarness(adapters, defaultConfigs);
|
|
568
|
+
return configs => testHarness(HookHarness, configs);
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
const hookHarness = makeHookHarness(DefaultAdapters, DefaultConfigs);
|
|
572
|
+
|
|
573
|
+
const testHarness = makeTestHarness(DefaultAdapters, DefaultConfigs);
|
|
574
|
+
|
|
575
|
+
export { RespondWith, adapters$1 as fixtureAdapters, fixtures, adapters as harnessAdapters, hookHarness, makeHookHarness, makeTestHarness, mockFetch, mockGqlFetch, setup as setupFixtures, testHarness };
|