@khanacademy/wonder-blocks-testing 4.0.3 → 5.0.1

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 (70) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/es/index.js +212 -26
  3. package/dist/index.js +589 -62
  4. package/package.json +5 -3
  5. package/src/__docs__/_overview_.stories.mdx +3 -4
  6. package/src/__docs__/_overview_fixtures.stories.mdx +22 -0
  7. package/src/__docs__/_overview_mocking.stories.mdx +14 -0
  8. package/src/__docs__/_overview_test_harness.stories.mdx +18 -0
  9. package/src/__docs__/exports.fixture-adapters.stories.mdx +49 -0
  10. package/src/__docs__/exports.fixtures.stories.mdx +53 -0
  11. package/src/__docs__/exports.harness-adapters.stories.mdx +187 -0
  12. package/src/__docs__/exports.hook-harness.stories.mdx +22 -0
  13. package/src/__docs__/exports.make-hook-harness.stories.mdx +25 -0
  14. package/src/__docs__/exports.make-test-harness.stories.mdx +28 -0
  15. package/src/__docs__/exports.mock-fetch.stories.mdx +40 -0
  16. package/src/__docs__/exports.mock-gql-fetch.stories.mdx +13 -8
  17. package/src/__docs__/exports.respond-with.stories.mdx +54 -8
  18. package/src/__docs__/exports.setup-fixtures.stories.mdx +22 -0
  19. package/src/__docs__/exports.test-harness.stories.mdx +23 -0
  20. package/src/__docs__/types.custom-mount-props.stories.mdx +35 -0
  21. package/src/__docs__/types.fetch-mock-fn.stories.mdx +22 -0
  22. package/src/__docs__/types.fetch-mock-operation.stories.mdx +18 -0
  23. package/src/__docs__/types.fixtures-adapter-factory.stories.mdx +23 -0
  24. package/src/__docs__/types.fixtures-adapter-fixture-options.stories.mdx +35 -0
  25. package/src/__docs__/types.fixtures-adapter-group-options.stories.mdx +37 -0
  26. package/src/__docs__/types.fixtures-adapter-group.stories.mdx +43 -0
  27. package/src/__docs__/types.fixtures-adapter-options.stories.mdx +21 -0
  28. package/src/__docs__/types.fixtures-adapter.stories.mdx +35 -0
  29. package/src/__docs__/types.fixtures-configuration.stories.mdx +35 -0
  30. package/src/__docs__/types.fixtures-options.stories.mdx +51 -0
  31. package/src/__docs__/types.get-props-options.stories.mdx +25 -0
  32. package/src/__docs__/types.gql-fetch-mock-fn.stories.mdx +27 -0
  33. package/src/__docs__/types.gql-mock-operation.stories.mdx +26 -0
  34. package/src/__docs__/types.mock-response.stories.mdx +18 -0
  35. package/src/__docs__/types.test-harness-adapter.stories.mdx +21 -0
  36. package/src/__docs__/types.test-harness-adapters.stories.mdx +46 -0
  37. package/src/__docs__/types.test-harness-config.stories.mdx +18 -0
  38. package/src/__docs__/types.test-harness-configs.stories.mdx +59 -0
  39. package/src/fetch/types.js +0 -3
  40. package/src/fixtures/adapters/adapter-group.js +11 -11
  41. package/src/fixtures/adapters/adapter.js +8 -8
  42. package/src/fixtures/adapters/storybook.js +11 -8
  43. package/src/fixtures/fixtures.basic.stories.js +6 -2
  44. package/src/fixtures/fixtures.defaultwrapper.stories.js +6 -2
  45. package/src/fixtures/setup.js +8 -4
  46. package/src/fixtures/types.js +27 -16
  47. package/src/gql/types.js +1 -3
  48. package/src/harness/__tests__/hook-harness.test.js +72 -0
  49. package/src/harness/__tests__/make-hook-harness.test.js +94 -0
  50. package/src/harness/__tests__/make-test-harness.test.js +190 -0
  51. package/src/harness/__tests__/render-adapters.test.js +88 -0
  52. package/src/harness/__tests__/test-harness.test.js +74 -0
  53. package/src/harness/__tests__/types.flowtest.js +115 -0
  54. package/src/harness/adapters/__tests__/__snapshots__/router.test.js.snap +5 -0
  55. package/src/harness/adapters/__tests__/css.test.js +96 -0
  56. package/src/harness/adapters/__tests__/data.test.js +66 -0
  57. package/src/harness/adapters/__tests__/portal.test.js +31 -0
  58. package/src/harness/adapters/__tests__/router.test.js +233 -0
  59. package/src/harness/adapters/adapters.js +33 -0
  60. package/src/harness/adapters/css.js +65 -0
  61. package/src/harness/adapters/data.js +46 -0
  62. package/src/harness/adapters/portal.js +26 -0
  63. package/src/harness/adapters/router.js +206 -0
  64. package/src/harness/hook-harness.js +23 -0
  65. package/src/harness/make-hook-harness.js +39 -0
  66. package/src/harness/make-test-harness.js +68 -0
  67. package/src/harness/render-adapters.js +27 -0
  68. package/src/harness/test-harness.js +24 -0
  69. package/src/harness/types.js +57 -0
  70. package/src/index.js +22 -18
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @khanacademy/wonder-blocks-testing
2
2
 
3
+ ## 5.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 5b1c80d2: Fix test harness types
8
+
9
+ ## 5.0.0
10
+
11
+ ### Major Changes
12
+
13
+ - 217b2c7b: Add test harness framework
14
+ - 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.
15
+
16
+ ## 4.0.4
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies [580141ed]
21
+ - @khanacademy/wonder-blocks-data@8.0.2
22
+
3
23
  ## 4.0.3
4
24
 
5
25
  ### 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
- export { RespondWith, adapters, fixtures, mockFetch, mockGqlFetch, setup as setupFixtures };
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 };