@khanacademy/wonder-blocks-testing 6.1.0 → 7.0.2

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 (40) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/es/index.js +17 -187
  3. package/dist/index.js +90 -463
  4. package/package.json +2 -2
  5. package/src/__docs__/_overview_fixtures.stories.mdx +2 -6
  6. package/src/__docs__/exports.fixtures.stories.mdx +9 -31
  7. package/src/__docs__/types.fixture-fn.stories.mdx +46 -0
  8. package/src/__docs__/types.fixture-props.stories.mdx +20 -0
  9. package/src/fixtures/__tests__/fixtures.test.js +89 -466
  10. package/src/fixtures/fixtures.basic.stories.js +30 -50
  11. package/src/fixtures/fixtures.defaultwrapper.stories.js +26 -40
  12. package/src/fixtures/fixtures.js +50 -103
  13. package/src/fixtures/types.js +15 -181
  14. package/src/index.js +2 -11
  15. package/src/__docs__/exports.fixture-adapters.stories.mdx +0 -49
  16. package/src/__docs__/exports.setup-fixtures.stories.mdx +0 -22
  17. package/src/__docs__/types.custom-mount-props.stories.mdx +0 -35
  18. package/src/__docs__/types.fixtures-adapter-factory.stories.mdx +0 -23
  19. package/src/__docs__/types.fixtures-adapter-fixture-options.stories.mdx +0 -35
  20. package/src/__docs__/types.fixtures-adapter-group-options.stories.mdx +0 -37
  21. package/src/__docs__/types.fixtures-adapter-group.stories.mdx +0 -43
  22. package/src/__docs__/types.fixtures-adapter-options.stories.mdx +0 -21
  23. package/src/__docs__/types.fixtures-adapter.stories.mdx +0 -35
  24. package/src/__docs__/types.fixtures-configuration.stories.mdx +0 -35
  25. package/src/__docs__/types.fixtures-options.stories.mdx +0 -51
  26. package/src/fixtures/__tests__/combine-options.test.js +0 -65
  27. package/src/fixtures/__tests__/combine-top-level.test.js +0 -100
  28. package/src/fixtures/__tests__/setup.test.js +0 -71
  29. package/src/fixtures/adapters/__tests__/__snapshots__/adapter-group.test.js.snap +0 -9
  30. package/src/fixtures/adapters/__tests__/__snapshots__/adapter.test.js.snap +0 -13
  31. package/src/fixtures/adapters/__tests__/adapter-group.test.js +0 -223
  32. package/src/fixtures/adapters/__tests__/adapter.test.js +0 -97
  33. package/src/fixtures/adapters/__tests__/storybook.test.js +0 -369
  34. package/src/fixtures/adapters/adapter-group.js +0 -88
  35. package/src/fixtures/adapters/adapter.js +0 -63
  36. package/src/fixtures/adapters/adapters.js +0 -2
  37. package/src/fixtures/adapters/storybook.js +0 -128
  38. package/src/fixtures/combine-options.js +0 -25
  39. package/src/fixtures/combine-top-level.js +0 -44
  40. package/src/fixtures/setup.js +0 -30
@@ -1,35 +0,0 @@
1
- import {Meta} from "@storybook/addon-docs";
2
-
3
- <Meta
4
- title="Testing / Fixtures / Types / CustomMountProps<>"
5
- parameters={{
6
- chromatic: {
7
- disableSnapshot: true,
8
- },
9
- }}
10
- />
11
-
12
- # CustomMountProps&lt;&gt;
13
-
14
- ```ts
15
- type CustomMountProps<TProps: {...}> = {|
16
- /**
17
- * The fixture props for the component to be rendered.
18
- */
19
- props: TProps,
20
-
21
- /**
22
- * The component to render.
23
- */
24
- component: React.ComponentType<TProps>,
25
-
26
- /**
27
- * The log callback for logging information.
28
- */
29
- log: (message: string, ...args: Array<any>) => mixed,
30
- |};
31
- ```
32
-
33
- When creating a new adapter instance, the [`FixtureAdapterFactory`](/docs/testing-fixtures-types-fixtureadapterfactory--page) can take an optional component to be used as the root component for each fixture, also know as the mounting component.
34
-
35
- The `CustomMountProps<>` type defines the props that will be applied to that mounting component. It includes the `component` to be rendered as the fixture, the `props` to pass to that component, and the `log` callback, which the mounting component can use for any logging it may require.
@@ -1,23 +0,0 @@
1
- import {Meta} from "@storybook/addon-docs";
2
-
3
- <Meta
4
- title="Testing / Fixtures / Types / FixturesAdapterFactory<>"
5
- parameters={{
6
- chromatic: {
7
- disableSnapshot: true,
8
- },
9
- }}
10
- />
11
-
12
- # FixturesAdapterFactory&lt;&gt;
13
-
14
- ```ts
15
- type FixturesAdapterFactory<
16
- TAdapterOptions: {...},
17
- TAdapterExports: {...},
18
- > = (
19
- MountingComponent: ?React.ComponentType<CustomWrapperProps<any>>,
20
- ) => FixturesAdapter<TAdapterOptions, TAdapterExports>;
21
- ```
22
-
23
- When implementing a custom [`FixturesAdapter<>`](/docs/testing-fixtures-types-fixturesadapter--page), you should provide a factory function for producing instances of the adapter. This type describes the signature of the factory function.
@@ -1,35 +0,0 @@
1
- import {Meta} from "@storybook/addon-docs";
2
-
3
- <Meta
4
- title="Testing / Fixtures / Types / FixturesAdapterFixtureOptions<>"
5
- parameters={{
6
- chromatic: {
7
- disableSnapshot: true,
8
- },
9
- }}
10
- />
11
-
12
- # FixturesAdapterFixtureOptions&lt;&gt;
13
-
14
- ```ts
15
- type FixturesAdapterFixtureOptions<TProps: {...}> = {|
16
- /**
17
- * Description of the fixture.
18
- */
19
- +description: string,
20
-
21
- /**
22
- * Method to obtain props for the fixture.
23
- */
24
- +getProps: (options: $ReadOnly<GetPropsOptions>) => $ReadOnly<TProps>,
25
-
26
- /**
27
- * The component to render for this fixture.
28
- */
29
- +component: React.ComponentType<TProps>,
30
- |};
31
- ```
32
-
33
- These options are passed to the `declareFixture()` function of a [`FixturesAdapterGroup<>`](/docs/testing-fixtures-types-fixturesadaptergroup--page).
34
-
35
- The `description` property is used to describe the fixture, the `component` is the component that renders the fixture, and the `getProps` method is used to obtain the props for that component.
@@ -1,37 +0,0 @@
1
- import {Meta} from "@storybook/addon-docs";
2
-
3
- <Meta
4
- title="Testing / Fixtures / Types / FixturesAdapterGroupOptions"
5
- parameters={{
6
- chromatic: {
7
- disableSnapshot: true,
8
- },
9
- }}
10
- />
11
-
12
- # FixturesAdapterGroupOptions
13
-
14
- ```ts
15
- type FixturesAdapterGroupOptions = {|
16
- /**
17
- * The title of the group.
18
- *
19
- * If omitted, the adapter is free to generate a default or ask for one
20
- * using the passed getDefaultTitle() function.
21
- */
22
- +title: ?string,
23
-
24
- /**
25
- * Description of the group.
26
- */
27
- +description: ?string,
28
-
29
- /**
30
- * Function that will generate a default title if an adapter cannot
31
- * generate its own.
32
- */
33
- +getDefaultTitle: () => string,
34
- |};
35
- ```
36
-
37
- These are options that the fixtures framework provides when `declareGroup()` is called on the configured adapter to create a new [`FixturesAdapterGroup<>`](/docs/testing-fixtures-types-fixturesadaptergroup--page).
@@ -1,43 +0,0 @@
1
- import {Meta} from "@storybook/addon-docs";
2
-
3
- <Meta
4
- title="Testing / Fixtures / Types / FixturesAdapterGroup<>"
5
- parameters={{
6
- chromatic: {
7
- disableSnapshot: true,
8
- },
9
- }}
10
- />
11
-
12
- # FixturesAdapterGroup&lt;&gt;
13
-
14
- ```ts
15
- interface FixturesAdapterGroup<
16
- TProps: {...},
17
- TAdapterOptions: {...},
18
- TAdapterExports: {...},
19
- > {
20
- /**
21
- * Declare a fixture.
22
- */
23
- declareFixture(
24
- options: $ReadOnly<FixturesAdapterFixtureOptions<TProps>>,
25
- ): void;
26
-
27
- /**
28
- * Close the group and obtain the exports, if the adapter requires any.
29
- *
30
- * @param {Options} adapterOptions Some options to pass to the adapter.
31
- * Allows callers to tailor things to a specific adapter. How these options
32
- * are used is adapter-specific.
33
- *
34
- * @returns {?Exports} The exports that the adapter requires fixture files
35
- * to export.
36
- */
37
- closeGroup(
38
- adapterOptions: $ReadOnly<Partial<TAdapterOptions>>,
39
- ): ?$ReadOnly<TAdapterExports>;
40
- }
41
- ```
42
-
43
- Each call to the [`fixtures()`](/docs/testing-fixtures-exports-fixtures--page) function invokes the `declareGroup()` method on the [`FixturesAdapter<>`](/docs/testing-fixtures-types-fixturesadapter--page) instance that has been configured using [`setupFixtures()`](/docs/testing-fixtures-exports-setupfixtures--page). The group that is returned by `declareGroup()` must match this interface.
@@ -1,21 +0,0 @@
1
- import {Meta} from "@storybook/addon-docs";
2
-
3
- <Meta
4
- title="Testing / Fixtures / Types / FixturesAdapterOptions"
5
- parameters={{
6
- chromatic: {
7
- disableSnapshot: true,
8
- },
9
- }}
10
- />
11
-
12
- # FixturesAdapterOptions
13
-
14
- ```ts
15
- type FixturesAdapterOptions = {|
16
- storybook?: StorybookOptions,
17
- [adapterName: string]: {...},
18
- |};
19
- ```
20
-
21
- Defines adapter-specific options. These are used with fixtures when needing to configure them for specific adapters.
@@ -1,35 +0,0 @@
1
- import {Meta} from "@storybook/addon-docs";
2
-
3
- <Meta
4
- title="Testing / Fixtures / Types / FixturesAdapter<>"
5
- parameters={{
6
- chromatic: {
7
- disableSnapshot: true,
8
- },
9
- }}
10
- />
11
-
12
- # FixturesAdapter&lt;&gt;
13
-
14
- ```ts
15
- interface FixturesAdapter<TAdapterOptions: {...}, TAdapterExports: {...}> {
16
- /**
17
- * The name of the adapter.
18
- */
19
- get name(): string;
20
-
21
- /**
22
- * Declare a fixture group.
23
- *
24
- * @returns {FixturesAdapterGroup<TProps, TAdapterOptions, TAdapterExports>} The
25
- * declared group.
26
- */
27
- declareGroup<TProps: {...}>(
28
- options: $ReadOnly<AdapterGroupOptions>,
29
- ): FixturesAdapterGroup<TProps, TAdapterOptions, TAdapterExports>;
30
- }
31
- ```
32
-
33
- This type describes an adapter for use with our fixtures framework.
34
-
35
-
@@ -1,35 +0,0 @@
1
- import {Meta} from "@storybook/addon-docs";
2
-
3
- <Meta
4
- title="Testing / Fixtures / Types / FixturesConfiguration<>"
5
- parameters={{
6
- chromatic: {
7
- disableSnapshot: true,
8
- },
9
- }}
10
- />
11
-
12
- # FixturesConfiguration&lt;&gt;
13
-
14
- ```ts
15
- type FixturesConfiguration<
16
- TAdapterOptions: {...},
17
- TAdapterExports: {...},
18
- > = {|
19
- /**
20
- * The adapter to use for declaring fixtures.
21
- */
22
- +adapter: FixturesAdapter<TAdapterOptions, TAdapterExports>,
23
-
24
- /**
25
- * Default options to apply to every fixture group.
26
- *
27
- * Each top-level option in this object will be merged with the equivalent
28
- * top-level option that a specific fixture requests. Where collisions
29
- * occur, the fixture options win.
30
- */
31
- +defaultAdapterOptions?: $ReadOnly<Partial<TAdapterOptions>>,
32
- |};
33
- ```
34
-
35
- The configuration type passed to [`setupFixtures()`](/docs/testing-fixtures-exports-setupfixtures--page).
@@ -1,51 +0,0 @@
1
- import {Meta} from "@storybook/addon-docs";
2
-
3
- <Meta
4
- title="Testing / Fixtures / Types / FixturesOptions<>"
5
- parameters={{
6
- chromatic: {
7
- disableSnapshot: true,
8
- },
9
- }}
10
- />
11
-
12
- # FixturesOptions
13
-
14
- ```ts
15
- type FixturesOptions<TProps: {...}> = {|
16
- /**
17
- * The component being tested by the fixtures.
18
- */
19
- component: React.ComponentType<TProps>,
20
-
21
- /**
22
- * Optional title of the fixture collection.
23
- *
24
- * Adapters may enforce a title, otherwise the component name is used.
25
- */
26
- title?: string,
27
-
28
- /**
29
- * Optional description of the fixture collection.
30
- */
31
- description?: string,
32
-
33
- /**
34
- * Optional default wrapper to apply around the component under test.
35
- */
36
- defaultWrapper?: React.ComponentType<TProps>,
37
-
38
- /**
39
- * Additional options to apply to specific adapters.
40
- */
41
- additionalAdapterOptions?: FixturesAdapterOptions,
42
- |};
43
- ```
44
-
45
- This type is used to pass options to the [`fixtures()`](/docs/testing-fixtures-types-fixturesoptions--page) method when describing fixtures for a specific component.
46
-
47
- It specifies the `component` being rendered and tested by each fixtures. Optionally, it can also specify a `title` and `description` for the fixtures, as well as a `defaultWrapper` component to use by default to wrap the component under test for each fixture, and an `additionalAdapterOptions` object that allows each adapter type to be individually configured for the fixtures.
48
-
49
- If the `title` is omitted, the adapter can either request a default title, which will be based off the name of the `component` React component, or it can provide its own title based as necessary. For example, Storybook has a default title based off the file location of the component when the `title` is omitted.
50
-
51
- Some adapters may ignore the `description` field.
@@ -1,65 +0,0 @@
1
- // @flow
2
- import * as CombineTopLevelModule from "../combine-top-level.js";
3
-
4
- import {combineOptions} from "../combine-options.js";
5
-
6
- jest.mock("../combine-top-level.js");
7
-
8
- describe("#combineOptions", () => {
9
- beforeEach(() => {
10
- jest.clearAllMocks();
11
- });
12
-
13
- it("should call combine once per property per object", () => {
14
- // Arrange
15
- const toBeCombined = [
16
- {a: "test1", b: "test1"},
17
- {b: "test2"},
18
- {a: "test3", c: "test3"},
19
- ];
20
- const combineSpy = jest.spyOn(CombineTopLevelModule, "combineTopLevel");
21
-
22
- // Act
23
- combineOptions(...toBeCombined);
24
-
25
- // Assert
26
- expect(combineSpy).toHaveBeenCalledTimes(5);
27
- });
28
-
29
- it("should ignore falsy args", () => {
30
- // Arrange
31
- const toBeCombined = [null, {a: "test"}, {b: "test"}, 0, undefined];
32
- const combineSpy = jest.spyOn(CombineTopLevelModule, "combineTopLevel");
33
-
34
- // Act
35
- combineOptions(...toBeCombined);
36
-
37
- // Assert
38
- expect(combineSpy).toHaveBeenCalledTimes(2);
39
- });
40
-
41
- it("should return the combined object", () => {
42
- // Arrange
43
- const toBeCombined = [
44
- {a: "test1", b: "test1"},
45
- {b: "test2"},
46
- {a: "test3", c: "test3"},
47
- ];
48
- jest.spyOn(CombineTopLevelModule, "combineTopLevel").mockImplementation(
49
- // Just for testing, we know the values are strings, so let's
50
- // combine them with concatenation so we see the order of
51
- // combination in the result.
52
- (v1, v2) => `${v1 === undefined ? "" : v1}${v2}`,
53
- );
54
-
55
- // Act
56
- const result = combineOptions(...toBeCombined);
57
-
58
- // Assert
59
- expect(result).toEqual({
60
- a: "test1test3",
61
- b: "test1test2",
62
- c: "test3",
63
- });
64
- });
65
- });
@@ -1,100 +0,0 @@
1
- // @flow
2
- import * as WonderStuffCoreModule from "@khanacademy/wonder-stuff-core";
3
-
4
- import {combineTopLevel} from "../combine-top-level.js";
5
-
6
- jest.mock("@khanacademy/wonder-stuff-core");
7
-
8
- describe("#combine", () => {
9
- beforeEach(() => {
10
- jest.resetAllMocks();
11
- });
12
-
13
- it.each([undefined, null, 42, "test", true])(
14
- "should return a clone of val2 if val1 is %s",
15
- (val1) => {
16
- // Arrange
17
- jest.spyOn(WonderStuffCoreModule, "clone").mockImplementation(
18
- (v) => `CLONED: ${v}`,
19
- );
20
- const val2 = "VALUE2";
21
-
22
- // Act
23
- const result = combineTopLevel(val1, val2);
24
-
25
- // Assert
26
- expect(result).toEqual(`CLONED: VALUE2`);
27
- },
28
- );
29
-
30
- it("should return a deduplicated array including values from val1 and val2, with val2 values first if both are arrays", () => {
31
- // Arrange
32
- jest.spyOn(WonderStuffCoreModule, "clone").mockImplementation((v) => v);
33
- const val1 = ["VALUE1", "VALUE2", "VALUE2"];
34
- const val2 = ["VALUE2", "VALUE3", "VALUE3"];
35
-
36
- // Act
37
- const result = combineTopLevel(val1, val2);
38
-
39
- // Assert
40
- expect(result).toEqual(["VALUE1", "VALUE2", "VALUE3"]);
41
- });
42
-
43
- it("should return a clone of val2 if val2 is an array but val1 is not", () => {
44
- // Arrange
45
- jest.spyOn(WonderStuffCoreModule, "clone").mockImplementation(
46
- (v) => `CLONED: ${v}`,
47
- );
48
- const val1 = "VALUE1";
49
- const val2 = ["VALUE1", "VALUE2", "VALUE3"];
50
-
51
- // Act
52
- const result = combineTopLevel(val1, val2);
53
-
54
- // Assert
55
- expect(result).toEqual("CLONED: VALUE1,VALUE2,VALUE3");
56
- });
57
-
58
- it("should return a clone of val2 if val2 is not an array but val1 is", () => {
59
- // Arrange
60
- jest.spyOn(WonderStuffCoreModule, "clone").mockImplementation(
61
- (v) => `CLONED: ${JSON.stringify(v)}`,
62
- );
63
- const val1 = ["VALUE1", "VALUE2", "VALUE3"];
64
- const val2 = {
65
- key1: "VALUE1",
66
- };
67
-
68
- // Act
69
- const result = combineTopLevel(val1, val2);
70
-
71
- // Assert
72
- expect(result).toEqual('CLONED: {"key1":"VALUE1"}');
73
- });
74
-
75
- it("should return a combination of val1 and val2 (cloned) properties with val2 overriding val1 when both are non-array objects", () => {
76
- // Arrange
77
- jest.spyOn(WonderStuffCoreModule, "clone").mockImplementation((v) => v);
78
- const val1 = {
79
- a: "val1_VALUE1",
80
- b: "val1_VALUE2",
81
- c: "val1_VALUE3",
82
- };
83
- const val2 = {
84
- b: "val2_VALUE2",
85
- c: "val2_VALUE3",
86
- d: "val2_VALUE4",
87
- };
88
-
89
- // Act
90
- const result = combineTopLevel(val1, val2);
91
-
92
- // Assert
93
- expect(result).toEqual({
94
- a: "val1_VALUE1",
95
- b: "val2_VALUE2",
96
- c: "val2_VALUE3",
97
- d: "val2_VALUE4",
98
- });
99
- });
100
- });
@@ -1,71 +0,0 @@
1
- // @flow
2
- import {jest as wst} from "@khanacademy/wonder-stuff-testing";
3
-
4
- describe("#getConfiguration", () => {
5
- it("should return the configuration passed during setup", () => {
6
- // Arrange
7
- const {setup, getConfiguration} = wst.isolateModules(() =>
8
- require("../setup.js"),
9
- );
10
- const configuration = {
11
- adapter: {
12
- name: "mytestadapter",
13
- declareGroup: jest.fn(),
14
- },
15
- defaultAdapterOptions: {},
16
- };
17
- setup(configuration);
18
-
19
- // Act
20
- const result = getConfiguration();
21
-
22
- // Assert
23
- expect(result).toBe(configuration);
24
- });
25
-
26
- it("should throw if setup has not been performed", () => {
27
- // Arrange
28
- const {getConfiguration} = wst.isolateModules(() =>
29
- require("../setup.js"),
30
- );
31
-
32
- // Act
33
- const underTest = () => getConfiguration();
34
-
35
- // Assert
36
- expect(underTest).toThrowErrorMatchingInlineSnapshot(
37
- `"Not configured"`,
38
- );
39
- });
40
- });
41
-
42
- describe("#setup", () => {
43
- it("should set the configuration returned by getConfiguration", () => {
44
- // Arrange
45
- const {setup, getConfiguration} = wst.isolateModules(() =>
46
- require("../setup.js"),
47
- );
48
- const configuration1 = {
49
- adapter: {
50
- name: "mytestadapter1",
51
- declareGroup: jest.fn(),
52
- },
53
- defaultAdapterOptions: {},
54
- };
55
- const configuration2 = {
56
- adapter: {
57
- name: "mytestadapter2",
58
- declareGroup: jest.fn(),
59
- },
60
- defaultAdapterOptions: {},
61
- };
62
-
63
- // Act
64
- setup(configuration1);
65
- setup(configuration2);
66
- const result = getConfiguration();
67
-
68
- // Assert
69
- expect(result).toBe(configuration2);
70
- });
71
- });
@@ -1,9 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`AdapterGroup #constructor should throw if options are not valid (a string) 1`] = `"options must be an object"`;
4
-
5
- exports[`AdapterGroup #constructor should throw if options are not valid (null) 1`] = `"options must be an object"`;
6
-
7
- exports[`AdapterGroup #declareFixture should throw if options are not valid (a string) 1`] = `"options must be an object"`;
8
-
9
- exports[`AdapterGroup #declareFixture should throw if options are not valid (null) 1`] = `"options must be an object"`;
@@ -1,13 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`Adapter #constructor should throw if closeGroupFn is invalid 1`] = `"closeGroupFn must be a function"`;
4
-
5
- exports[`Adapter #constructor should throw if closeGroupFn is invalid 2`] = `"closeGroupFn must be a function"`;
6
-
7
- exports[`Adapter #constructor should throw if the name is invalid ( ) 1`] = `"name must be a non-empty string"`;
8
-
9
- exports[`Adapter #constructor should throw if the name is invalid () 1`] = `"name must be a non-empty string"`;
10
-
11
- exports[`Adapter #constructor should throw if the name is invalid (8) 1`] = `"name must be a string"`;
12
-
13
- exports[`Adapter #constructor should throw if the name is invalid (null) 1`] = `"name must be a string"`;