@khanacademy/wonder-blocks-testing-core 1.0.0 → 1.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.
- package/CHANGELOG.md +13 -0
- package/dist/es/index.js +3 -22
- package/dist/index.js +9 -24
- package/package.json +32 -32
- package/src/__tests__/mock-requester.test.ts +0 -212
- package/src/__tests__/render-hook-static.test.ts +0 -48
- package/src/__tests__/respond-with.test.ts +0 -524
- package/src/__tests__/response-impl.test.js +0 -47
- package/src/__tests__/settle-controller.test.ts +0 -28
- package/src/__tests__/settle-signal.test.ts +0 -104
- package/src/fetch/__tests__/__snapshots__/mock-fetch.test.ts.snap +0 -29
- package/src/fetch/__tests__/fetch-request-matches-mock.test.ts +0 -98
- package/src/fetch/__tests__/mock-fetch.test.ts +0 -83
- package/src/fetch/fetch-request-matches-mock.ts +0 -42
- package/src/fetch/mock-fetch.ts +0 -20
- package/src/fetch/types.ts +0 -14
- package/src/fixtures/__tests__/fixtures.test.tsx +0 -147
- package/src/fixtures/fixtures.basic.stories.tsx +0 -62
- package/src/fixtures/fixtures.defaultwrapper.stories.tsx +0 -49
- package/src/fixtures/fixtures.tsx +0 -72
- package/src/fixtures/types.ts +0 -42
- package/src/harness/__tests__/adapt.test.tsx +0 -248
- package/src/harness/__tests__/hook-harness.test.ts +0 -73
- package/src/harness/__tests__/make-hook-harness.test.tsx +0 -93
- package/src/harness/__tests__/make-test-harness.test.tsx +0 -195
- package/src/harness/__tests__/test-harness.test.ts +0 -75
- package/src/harness/__tests__/types.typestest.tsx +0 -103
- package/src/harness/adapt.tsx +0 -41
- package/src/harness/adapters/__tests__/__snapshots__/router.test.tsx.snap +0 -5
- package/src/harness/adapters/__tests__/css.test.tsx +0 -95
- package/src/harness/adapters/__tests__/error-boundary.test.tsx +0 -121
- package/src/harness/adapters/__tests__/portal.test.tsx +0 -30
- package/src/harness/adapters/__tests__/router.test.tsx +0 -252
- package/src/harness/adapters/adapters.ts +0 -35
- package/src/harness/adapters/css.tsx +0 -66
- package/src/harness/adapters/error-boundary.tsx +0 -56
- package/src/harness/adapters/portal.tsx +0 -25
- package/src/harness/adapters/router.tsx +0 -205
- package/src/harness/get-named-adapter-component.tsx +0 -36
- package/src/harness/hook-harness.ts +0 -22
- package/src/harness/make-hook-harness.tsx +0 -40
- package/src/harness/make-test-harness.tsx +0 -60
- package/src/harness/test-harness.ts +0 -13
- package/src/harness/types.ts +0 -47
- package/src/index.ts +0 -29
- package/src/mock-requester.ts +0 -68
- package/src/render-hook-static.tsx +0 -60
- package/src/respond-with.ts +0 -263
- package/src/response-impl.ts +0 -8
- package/src/settle-controller.ts +0 -34
- package/src/settle-signal.ts +0 -42
- package/src/types.ts +0 -40
- package/tsconfig-build.json +0 -10
- package/tsconfig-build.tsbuildinfo +0 -1
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import type {
|
|
4
|
-
TestHarnessAdapter,
|
|
5
|
-
TestHarnessAdapters,
|
|
6
|
-
TestHarnessConfig,
|
|
7
|
-
TestHarnessConfigs,
|
|
8
|
-
} from "../types";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* TestHarnessAdapter<TConfig>
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
//> should assert type of config.
|
|
15
|
-
// @ts-expect-error TConfig is string, but we typed config as a number
|
|
16
|
-
((children: React.ReactNode, config: number): React.ReactElement<any> => (
|
|
17
|
-
<div />
|
|
18
|
-
)) as TestHarnessAdapter<string>;
|
|
19
|
-
//<
|
|
20
|
-
|
|
21
|
-
//> should work for correct definition
|
|
22
|
-
((children: React.ReactNode, config: string): React.ReactElement<any> => (
|
|
23
|
-
<div />
|
|
24
|
-
)) as TestHarnessAdapter<string>;
|
|
25
|
-
//<
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* TestHarnessAdapters
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
//> should work for empty case
|
|
32
|
-
({} as TestHarnessAdapters);
|
|
33
|
-
//<
|
|
34
|
-
|
|
35
|
-
//> should assert if adapter is not Adapter<TConfig>
|
|
36
|
-
// @ts-expect-error String is not a adapter function
|
|
37
|
-
({
|
|
38
|
-
adapterString: "string",
|
|
39
|
-
} as TestHarnessAdapters);
|
|
40
|
-
//<
|
|
41
|
-
|
|
42
|
-
//> should work for a function matching Adapter<TConfig>
|
|
43
|
-
({
|
|
44
|
-
adapterA: (children, config) => <div>test</div>,
|
|
45
|
-
} as TestHarnessAdapters);
|
|
46
|
-
//<
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* TestHarnessConfig<TAdapter>
|
|
50
|
-
*/
|
|
51
|
-
//> should give the config type of an adapter
|
|
52
|
-
"string" as TestHarnessConfig<TestHarnessAdapter<string>>;
|
|
53
|
-
//<
|
|
54
|
-
|
|
55
|
-
//> should error if the config type is wrong
|
|
56
|
-
// 45 is not a string
|
|
57
|
-
// @ts-expect-error: Type '45' is not assignable to type 'string'.
|
|
58
|
-
45 as TestHarnessConfig<TestHarnessAdapter<string>>;
|
|
59
|
-
//<
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* TestHarnessConfigs<TAdapters>
|
|
63
|
-
*
|
|
64
|
-
* NOTE: This only works if the properties of the passed THarnasses type
|
|
65
|
-
* are explicitly typed as `TestHarnessAdapter<TConfig>` so if passing in a
|
|
66
|
-
* non-Adapters type (which we should be, to get strong TConfig types instead
|
|
67
|
-
* of `any`), then that object should make sure that each adapter is strongly
|
|
68
|
-
* marked as `TestHarnessAdapter<TConfig>`.
|
|
69
|
-
*/
|
|
70
|
-
const notadapters = "this is wrong";
|
|
71
|
-
const adapterA: TestHarnessAdapter<string> = (
|
|
72
|
-
children: React.ReactNode,
|
|
73
|
-
config?: string | null,
|
|
74
|
-
): React.ReactElement<any> => <div />;
|
|
75
|
-
const adapterB: TestHarnessAdapter<number> = (
|
|
76
|
-
children: React.ReactNode,
|
|
77
|
-
config?: number | null,
|
|
78
|
-
): React.ReactElement<any> => <div />;
|
|
79
|
-
const adapters = {
|
|
80
|
-
adapterA,
|
|
81
|
-
adapterB,
|
|
82
|
-
} as const;
|
|
83
|
-
|
|
84
|
-
//> should assert if parameterized type is not valid Adapters
|
|
85
|
-
// string is not a valid Adapter
|
|
86
|
-
// @ts-expect-error: Type 'string' does not satisfy the constraint 'TestHarnessAdapters'
|
|
87
|
-
({} as TestHarnessConfigs<typeof notadapters>);
|
|
88
|
-
//<
|
|
89
|
-
|
|
90
|
-
//> should expect one config per adapter
|
|
91
|
-
// both adapter configs missing
|
|
92
|
-
({} as TestHarnessConfigs<typeof adapters>);
|
|
93
|
-
// adapterB config missing
|
|
94
|
-
({adapterA: "test"} as TestHarnessConfigs<typeof adapters>);
|
|
95
|
-
//<
|
|
96
|
-
|
|
97
|
-
//> should assert if config does not match adapter config
|
|
98
|
-
// @ts-expect-error: the config type here is a number, not a string
|
|
99
|
-
({
|
|
100
|
-
adapterA: "a string, this is correct",
|
|
101
|
-
adapterB: "a string, but it should be a number",
|
|
102
|
-
} as TestHarnessConfigs<typeof adapters>);
|
|
103
|
-
//<
|
package/src/harness/adapt.tsx
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import {getNamedAdapterComponent} from "./get-named-adapter-component";
|
|
4
|
-
|
|
5
|
-
import type {TestHarnessConfigs, TestHarnessAdapters} from "./types";
|
|
6
|
-
|
|
7
|
-
type Props<TAdapters extends TestHarnessAdapters> = {
|
|
8
|
-
children: React.ReactNode;
|
|
9
|
-
adapters: TAdapters;
|
|
10
|
-
configs: TestHarnessConfigs<TAdapters>;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Render a set of adapters around the given children.
|
|
15
|
-
*
|
|
16
|
-
* Adapters are rendered with the last adapter being the outermost and the first
|
|
17
|
-
* adapter being the innermost, with children being the innermost of all. This
|
|
18
|
-
* ensures that we are backwards compatible with previous releases of the
|
|
19
|
-
* test harness.
|
|
20
|
-
*/
|
|
21
|
-
export const Adapt = <TAdapters extends TestHarnessAdapters>({
|
|
22
|
-
children,
|
|
23
|
-
adapters,
|
|
24
|
-
configs,
|
|
25
|
-
}: Props<TAdapters>): React.ReactElement => {
|
|
26
|
-
// Here we reduce the adapters in order, such that each one becomes the
|
|
27
|
-
// child of the next, that way the first adapter in the list is the
|
|
28
|
-
// innermost and the last is the outermost.
|
|
29
|
-
return Object.entries(adapters).reduce((newChildren, [name, adapter]) => {
|
|
30
|
-
const theConfig = configs[name];
|
|
31
|
-
if (theConfig == null) {
|
|
32
|
-
return newChildren;
|
|
33
|
-
}
|
|
34
|
-
const Adapter = getNamedAdapterComponent(name);
|
|
35
|
-
return (
|
|
36
|
-
<Adapter key={name} adapter={adapter} config={theConfig}>
|
|
37
|
-
{newChildren}
|
|
38
|
-
</Adapter>
|
|
39
|
-
);
|
|
40
|
-
}, <>{children}</>);
|
|
41
|
-
};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`Router.adapter with full config including path should throw if the path does not match the location 1`] = `"The configured path must match the configured location or your harnessed component will not render."`;
|
|
4
|
-
|
|
5
|
-
exports[`Router.adapter with location config including path should throw if the path does not match the location 1`] = `"The configured path must match the configured location or your harnessed component will not render."`;
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {render, screen} from "@testing-library/react";
|
|
3
|
-
|
|
4
|
-
import * as Css from "../css";
|
|
5
|
-
|
|
6
|
-
describe("Css.adapter", () => {
|
|
7
|
-
it("should throw if the config is invalid", () => {
|
|
8
|
-
// Arrange
|
|
9
|
-
const badConfig: any = 42;
|
|
10
|
-
|
|
11
|
-
// Act
|
|
12
|
-
const underTest = () => Css.adapter("CHILDREN", badConfig);
|
|
13
|
-
|
|
14
|
-
// Assert
|
|
15
|
-
expect(underTest).toThrowErrorMatchingInlineSnapshot(
|
|
16
|
-
`"Invalid config: 42"`,
|
|
17
|
-
);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it("should render the children", () => {
|
|
21
|
-
// Arrange
|
|
22
|
-
const children = <div data-testid="children">CHILDREN!</div>;
|
|
23
|
-
|
|
24
|
-
// Act
|
|
25
|
-
render(Css.adapter(children, "test"));
|
|
26
|
-
const result = screen.getByTestId("children");
|
|
27
|
-
|
|
28
|
-
// Assert
|
|
29
|
-
expect(result).toBeInTheDocument();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("should render a container element", () => {
|
|
33
|
-
// Arrange
|
|
34
|
-
const children = <div data-testid="children">CHILDREN!</div>;
|
|
35
|
-
|
|
36
|
-
// Act
|
|
37
|
-
render(Css.adapter(children, "test"));
|
|
38
|
-
const result = screen.getByTestId("css-adapter-container");
|
|
39
|
-
|
|
40
|
-
// Assert
|
|
41
|
-
expect(result).toBeInTheDocument();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it("should render children as a child of the container element", () => {
|
|
45
|
-
// Arrange
|
|
46
|
-
const children = <div data-testid="children">CHILDREN!</div>;
|
|
47
|
-
|
|
48
|
-
// Act
|
|
49
|
-
render(Css.adapter(children, "test"));
|
|
50
|
-
const renderedContainer = screen.getByTestId("css-adapter-container");
|
|
51
|
-
const renderedChildren = screen.getByTestId("children");
|
|
52
|
-
|
|
53
|
-
// Assert
|
|
54
|
-
expect(renderedContainer).toContainElement(renderedChildren);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it.each`
|
|
58
|
-
config | expectation
|
|
59
|
-
${"class1"} | ${"class1"}
|
|
60
|
-
${["class1", "class2"]} | ${"class1 class2"}
|
|
61
|
-
${{classes: ["class1", "class2"], style: {backgroundColor: "red"}}} | ${"class1 class2"}
|
|
62
|
-
`(
|
|
63
|
-
"should apply the given class names from $config to the container element",
|
|
64
|
-
({config, expectation}: any) => {
|
|
65
|
-
// Arrange
|
|
66
|
-
const children = <div data-testid="children">CHILDREN!</div>;
|
|
67
|
-
|
|
68
|
-
// Act
|
|
69
|
-
render(Css.adapter(children, config));
|
|
70
|
-
const result = screen.getByTestId("css-adapter-container");
|
|
71
|
-
|
|
72
|
-
// Assert
|
|
73
|
-
expect(result).toHaveClass(expectation);
|
|
74
|
-
},
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
it.each`
|
|
78
|
-
config | expectation
|
|
79
|
-
${{backgroundColor: "red"}} | ${{backgroundColor: "red"}}
|
|
80
|
-
${{style: {backgroundColor: "red"}, classes: []}} | ${{backgroundColor: "red"}}
|
|
81
|
-
`(
|
|
82
|
-
"should apply the given styles from $config to the container element",
|
|
83
|
-
({config, expectation}: any) => {
|
|
84
|
-
// Arrange
|
|
85
|
-
const children = <div data-testid="children">CHILDREN!</div>;
|
|
86
|
-
|
|
87
|
-
// Act
|
|
88
|
-
render(Css.adapter(children, config));
|
|
89
|
-
const result = screen.getByTestId("css-adapter-container");
|
|
90
|
-
|
|
91
|
-
// Assert
|
|
92
|
-
expect(result).toHaveStyle(expectation);
|
|
93
|
-
},
|
|
94
|
-
);
|
|
95
|
-
});
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {it, describe, expect} from "@jest/globals";
|
|
3
|
-
import {render} from "@testing-library/react";
|
|
4
|
-
import {renderHook} from "@testing-library/react-hooks";
|
|
5
|
-
|
|
6
|
-
import * as ErrorBoundary from "../error-boundary";
|
|
7
|
-
|
|
8
|
-
describe("ErrorBoundary.adapter", () => {
|
|
9
|
-
describe("when rendering components", () => {
|
|
10
|
-
it("should render the children when no error is thrown", () => {
|
|
11
|
-
// Arrange
|
|
12
|
-
const onError = jest.fn();
|
|
13
|
-
|
|
14
|
-
// Act
|
|
15
|
-
const {container} = render(
|
|
16
|
-
ErrorBoundary.adapter(<div>CHILDREN</div>, onError),
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
// Assert
|
|
20
|
-
expect(container).toHaveTextContent("CHILDREN");
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it("should not call the onError callback when no error is thrown during rendering", () => {
|
|
24
|
-
// Arrange
|
|
25
|
-
const onError = jest.fn();
|
|
26
|
-
const Component = () => <>SUCCESS</>;
|
|
27
|
-
|
|
28
|
-
// Act
|
|
29
|
-
render(ErrorBoundary.adapter(<Component />, onError));
|
|
30
|
-
|
|
31
|
-
// Assert
|
|
32
|
-
expect(onError).not.toHaveBeenCalled();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("should call the onError callback when an error is thrown during rendering", () => {
|
|
36
|
-
// Arrange
|
|
37
|
-
jest.spyOn(console, "error").mockImplementation(() => {});
|
|
38
|
-
const onError = jest.fn();
|
|
39
|
-
const error = new Error("ErrorComponent");
|
|
40
|
-
const ErrorComponent = () => {
|
|
41
|
-
throw error;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// Act
|
|
45
|
-
render(ErrorBoundary.adapter(<ErrorComponent />, onError));
|
|
46
|
-
|
|
47
|
-
// Assert
|
|
48
|
-
expect(onError).toHaveBeenCalledWith(error, expect.anything());
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("should render the error message returned by onError", () => {
|
|
52
|
-
// Arrange
|
|
53
|
-
jest.spyOn(console, "error").mockImplementation(() => {});
|
|
54
|
-
const onError = jest.fn(() => "ERROR");
|
|
55
|
-
const error = new Error("ErrorComponent");
|
|
56
|
-
const ErrorComponent = () => {
|
|
57
|
-
throw error;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
// Act
|
|
61
|
-
const {container} = render(
|
|
62
|
-
ErrorBoundary.adapter(<ErrorComponent />, onError),
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
// Assert
|
|
66
|
-
expect(container).toHaveTextContent("ERROR");
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("should render a default error message if onError does not return anything", () => {
|
|
70
|
-
// Arrange
|
|
71
|
-
jest.spyOn(console, "error").mockImplementation(() => {});
|
|
72
|
-
const onError = jest.fn();
|
|
73
|
-
const error = new Error("ErrorComponent");
|
|
74
|
-
const ErrorComponent = () => {
|
|
75
|
-
throw error;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
// Act
|
|
79
|
-
const {container} = render(
|
|
80
|
-
ErrorBoundary.adapter(<ErrorComponent />, onError),
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
// Assert
|
|
84
|
-
expect(container).toHaveTextContent("An error occurred");
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
describe("when rendering hooks", () => {
|
|
89
|
-
it("should call the onError callback when an error is thrown during rendering", () => {
|
|
90
|
-
// Arrange
|
|
91
|
-
jest.spyOn(console, "error").mockImplementation(() => {});
|
|
92
|
-
const onError = jest.fn();
|
|
93
|
-
const error = new Error("ErrorHook");
|
|
94
|
-
const hook = () => {
|
|
95
|
-
throw error;
|
|
96
|
-
};
|
|
97
|
-
const Component = ({children}: any) =>
|
|
98
|
-
ErrorBoundary.adapter(children, onError);
|
|
99
|
-
|
|
100
|
-
// Act
|
|
101
|
-
renderHook(hook, {wrapper: Component});
|
|
102
|
-
|
|
103
|
-
// Assert
|
|
104
|
-
expect(onError).toHaveBeenCalledWith(error, expect.anything());
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it("should not call the onError callback when no error is thrown during rendering", () => {
|
|
108
|
-
// Arrange
|
|
109
|
-
const onError = jest.fn();
|
|
110
|
-
const hook = () => "SUCCESS";
|
|
111
|
-
const Component = ({children}: any) =>
|
|
112
|
-
ErrorBoundary.adapter(children, onError);
|
|
113
|
-
|
|
114
|
-
// Act
|
|
115
|
-
renderHook(hook, {wrapper: Component});
|
|
116
|
-
|
|
117
|
-
// Assert
|
|
118
|
-
expect(onError).not.toHaveBeenCalled();
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {render, screen} from "@testing-library/react";
|
|
3
|
-
|
|
4
|
-
import * as Portal from "../portal";
|
|
5
|
-
|
|
6
|
-
describe("Portal.adapter", () => {
|
|
7
|
-
it("should render a portal root element", () => {
|
|
8
|
-
// Arrange
|
|
9
|
-
const children = <div>CHILDREN!</div>;
|
|
10
|
-
const portalId = "portal-test-id";
|
|
11
|
-
|
|
12
|
-
// Act
|
|
13
|
-
render(Portal.adapter(children, portalId));
|
|
14
|
-
|
|
15
|
-
// Assert
|
|
16
|
-
expect(screen.getByTestId(portalId)).toBeInTheDocument();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it("should render the children correctly", () => {
|
|
20
|
-
// Arrange
|
|
21
|
-
const portalId = "portal-test-id";
|
|
22
|
-
const children = <div>CHILDREN!</div>;
|
|
23
|
-
|
|
24
|
-
// Act
|
|
25
|
-
render(Portal.adapter(children, portalId));
|
|
26
|
-
|
|
27
|
-
// Assert
|
|
28
|
-
expect(screen.getByText("CHILDREN!")).toBeInTheDocument();
|
|
29
|
-
});
|
|
30
|
-
});
|
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {withRouter, Prompt} from "react-router-dom";
|
|
3
|
-
import {render} from "@testing-library/react";
|
|
4
|
-
import * as Router from "../router";
|
|
5
|
-
|
|
6
|
-
describe("Router.adapter", () => {
|
|
7
|
-
it("should throw if the config does not match any expecations", () => {
|
|
8
|
-
// Arrange
|
|
9
|
-
const badConfig: any = {
|
|
10
|
-
bad: "config",
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// Act
|
|
14
|
-
const underTest = () => Router.adapter("CHILDREN", badConfig);
|
|
15
|
-
|
|
16
|
-
// Assert
|
|
17
|
-
expect(underTest).toThrowErrorMatchingInlineSnapshot(
|
|
18
|
-
`"A location or initial history entries must be provided."`,
|
|
19
|
-
);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
describe.each`
|
|
23
|
-
type | config
|
|
24
|
-
${"string"} | ${"/math"}
|
|
25
|
-
${"location"} | ${{location: "/math"}}
|
|
26
|
-
${"full"} | ${{initialEntries: ["/math"]}}
|
|
27
|
-
`("with $type config", ({config}: any) => {
|
|
28
|
-
it("should allow navigation", () => {
|
|
29
|
-
// Arrange
|
|
30
|
-
const historyListen = jest.fn();
|
|
31
|
-
const HistoryListener = withRouter(
|
|
32
|
-
({history}: any): React.ReactElement | null => {
|
|
33
|
-
React.useEffect(
|
|
34
|
-
() => history.listen(historyListen),
|
|
35
|
-
[history],
|
|
36
|
-
);
|
|
37
|
-
if (history.location.pathname === "/math") {
|
|
38
|
-
history.push("/math/calculator");
|
|
39
|
-
}
|
|
40
|
-
return null;
|
|
41
|
-
},
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
// Act
|
|
45
|
-
render(Router.adapter(<HistoryListener />, config));
|
|
46
|
-
|
|
47
|
-
// Assert
|
|
48
|
-
expect(historyListen).not.toHaveBeenCalled();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("should have default route match of root /", () => {
|
|
52
|
-
// Arrange
|
|
53
|
-
const matchCatcherFn = jest.fn();
|
|
54
|
-
const MatchCatcher = withRouter(
|
|
55
|
-
({match, history}: any): React.ReactElement | null => {
|
|
56
|
-
React.useEffect(() => {
|
|
57
|
-
if (history.location.pathname === "/math") {
|
|
58
|
-
history.push("/math/calculator");
|
|
59
|
-
}
|
|
60
|
-
matchCatcherFn(match);
|
|
61
|
-
}, [match, history]);
|
|
62
|
-
return null;
|
|
63
|
-
},
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
// Act
|
|
67
|
-
render(Router.adapter(<MatchCatcher />, config));
|
|
68
|
-
|
|
69
|
-
// Assert
|
|
70
|
-
expect(matchCatcherFn).toHaveBeenLastCalledWith(
|
|
71
|
-
expect.objectContaining({
|
|
72
|
-
path: "/",
|
|
73
|
-
url: "/",
|
|
74
|
-
}),
|
|
75
|
-
);
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
describe.each`
|
|
80
|
-
type | config
|
|
81
|
-
${"location"} | ${{location: "/math/calculator", path: "/math/*"}}
|
|
82
|
-
${"full"} | ${{initialEntries: ["/math/calculator"], path: "/math/*"}}
|
|
83
|
-
`("with $type config including path", ({config}: any) => {
|
|
84
|
-
it("should include routing for the given path", () => {
|
|
85
|
-
// Arrange
|
|
86
|
-
const matchCatcherFn = jest.fn();
|
|
87
|
-
const MatchCatcher = withRouter(
|
|
88
|
-
({match}: any): React.ReactElement | null => {
|
|
89
|
-
React.useEffect(() => {
|
|
90
|
-
matchCatcherFn(match);
|
|
91
|
-
}, [match]);
|
|
92
|
-
return null;
|
|
93
|
-
},
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
// Act
|
|
97
|
-
render(Router.adapter(<MatchCatcher />, config));
|
|
98
|
-
|
|
99
|
-
// Assert
|
|
100
|
-
expect(matchCatcherFn).toHaveBeenLastCalledWith(
|
|
101
|
-
expect.objectContaining({
|
|
102
|
-
isExact: true,
|
|
103
|
-
path: "/math/*",
|
|
104
|
-
url: "/math/calculator",
|
|
105
|
-
}),
|
|
106
|
-
);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it("should throw if the path does not match the location", () => {
|
|
110
|
-
// Arrange
|
|
111
|
-
// This is going to cause an error to be logged, so let's silence
|
|
112
|
-
// that.
|
|
113
|
-
jest.spyOn(console, "error").mockImplementation(() => {});
|
|
114
|
-
const badConfig = {
|
|
115
|
-
...config,
|
|
116
|
-
path: "/something/else/entirely",
|
|
117
|
-
} as const;
|
|
118
|
-
|
|
119
|
-
// Act
|
|
120
|
-
const underTest = () =>
|
|
121
|
-
render(Router.adapter("CHILDREN", badConfig));
|
|
122
|
-
|
|
123
|
-
// Assert
|
|
124
|
-
expect(underTest).toThrowErrorMatchingSnapshot();
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
describe("with forceStatic", () => {
|
|
129
|
-
it("should not navigate", () => {
|
|
130
|
-
// Arrange
|
|
131
|
-
const historyListen = jest.fn();
|
|
132
|
-
const HistoryListener = withRouter(
|
|
133
|
-
({history}: any): React.ReactElement | null => {
|
|
134
|
-
React.useEffect(
|
|
135
|
-
() => history.listen(historyListen),
|
|
136
|
-
[history],
|
|
137
|
-
);
|
|
138
|
-
if (history.location.pathname === "/math") {
|
|
139
|
-
history.push("/math/calculator");
|
|
140
|
-
}
|
|
141
|
-
return null;
|
|
142
|
-
},
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
// Act
|
|
146
|
-
render(
|
|
147
|
-
Router.adapter(<HistoryListener />, {
|
|
148
|
-
location: "/math",
|
|
149
|
-
forceStatic: true,
|
|
150
|
-
}),
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
// Assert
|
|
154
|
-
expect(historyListen).not.toHaveBeenCalled();
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
describe("with initialEntries", () => {
|
|
159
|
-
it("should use the defaultConfig location if initialEntries is empty", () => {
|
|
160
|
-
// Arrange
|
|
161
|
-
const matchCatcherFn = jest.fn();
|
|
162
|
-
const MatchCatcher = withRouter(
|
|
163
|
-
({match, history}: any): React.ReactElement | null => {
|
|
164
|
-
React.useEffect(() => {
|
|
165
|
-
matchCatcherFn(match);
|
|
166
|
-
}, [match, history]);
|
|
167
|
-
return null;
|
|
168
|
-
},
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
// Act
|
|
172
|
-
render(
|
|
173
|
-
Router.adapter(<MatchCatcher />, {
|
|
174
|
-
initialEntries: [],
|
|
175
|
-
}),
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
// Assert
|
|
179
|
-
expect(matchCatcherFn).toHaveBeenLastCalledWith(
|
|
180
|
-
expect.objectContaining({
|
|
181
|
-
url: Router.defaultConfig.location,
|
|
182
|
-
}),
|
|
183
|
-
);
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it("should set initialIndex prop on MemoryRouter if given in configuration", () => {
|
|
187
|
-
// Arrange
|
|
188
|
-
const matchCatcherFn = jest.fn();
|
|
189
|
-
const MatchCatcher = withRouter(
|
|
190
|
-
({match}: any): React.ReactElement | null => {
|
|
191
|
-
React.useEffect(() => {
|
|
192
|
-
matchCatcherFn(match);
|
|
193
|
-
}, [match]);
|
|
194
|
-
return null;
|
|
195
|
-
},
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
// Act
|
|
199
|
-
render(
|
|
200
|
-
Router.adapter(<MatchCatcher />, {
|
|
201
|
-
initialEntries: ["/location/old", "/location/current"],
|
|
202
|
-
initialIndex: 1,
|
|
203
|
-
path: "/location/*",
|
|
204
|
-
}),
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
// Assert
|
|
208
|
-
expect(matchCatcherFn).toHaveBeenLastCalledWith(
|
|
209
|
-
expect.objectContaining({
|
|
210
|
-
url: "/location/current",
|
|
211
|
-
}),
|
|
212
|
-
);
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it("should set getUserConfirmation prop on MemoryRouter if given in configuration", () => {
|
|
216
|
-
// Arrange
|
|
217
|
-
const getUserConfirmationSpy = jest
|
|
218
|
-
.fn()
|
|
219
|
-
.mockImplementation((message: any, cb: any) => {
|
|
220
|
-
cb(true);
|
|
221
|
-
});
|
|
222
|
-
const matchCatcherFn = jest.fn();
|
|
223
|
-
const MatchCatcher = withRouter(
|
|
224
|
-
({match, history}: any): React.ReactElement => {
|
|
225
|
-
React.useEffect(() => {
|
|
226
|
-
if (history.location.pathname === "/location/old") {
|
|
227
|
-
// Fire off a location change.
|
|
228
|
-
history.goForward();
|
|
229
|
-
}
|
|
230
|
-
matchCatcherFn(match);
|
|
231
|
-
}, [match, history]);
|
|
232
|
-
return <Prompt message="Are you sure?" />;
|
|
233
|
-
},
|
|
234
|
-
);
|
|
235
|
-
|
|
236
|
-
// Act
|
|
237
|
-
render(
|
|
238
|
-
Router.adapter(<MatchCatcher />, {
|
|
239
|
-
initialEntries: ["/location/old", "/location/current"],
|
|
240
|
-
getUserConfirmation: getUserConfirmationSpy,
|
|
241
|
-
path: "/location/*",
|
|
242
|
-
}),
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
// Assert
|
|
246
|
-
expect(getUserConfirmationSpy).toHaveBeenCalledWith(
|
|
247
|
-
"Are you sure?",
|
|
248
|
-
expect.any(Function),
|
|
249
|
-
);
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
});
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import * as css from "./css";
|
|
2
|
-
import * as errorBoundary from "./error-boundary";
|
|
3
|
-
import * as portal from "./portal";
|
|
4
|
-
import * as router from "./router";
|
|
5
|
-
|
|
6
|
-
import type {TestHarnessConfigs} from "../types";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* NOTE: We do not type `DefaultAdapters` with `Adapters` here because we want
|
|
10
|
-
* the individual config types of each adapter to remain intact rather than
|
|
11
|
-
* getting changed to `any`.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* The default adapters provided by Wonder Blocks.
|
|
16
|
-
*/
|
|
17
|
-
export const DefaultAdapters = {
|
|
18
|
-
// The error boundary is as close to the component under test as possible,
|
|
19
|
-
// so that other adapters don't soil it with their own errors, if that
|
|
20
|
-
// should happen.
|
|
21
|
-
boundary: errorBoundary.adapter,
|
|
22
|
-
css: css.adapter,
|
|
23
|
-
portal: portal.adapter,
|
|
24
|
-
router: router.adapter,
|
|
25
|
-
} as const;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* The default configurations to use with the `DefaultAdapters`.
|
|
29
|
-
*/
|
|
30
|
-
export const DefaultConfigs: TestHarnessConfigs<typeof DefaultAdapters> = {
|
|
31
|
-
boundary: errorBoundary.defaultConfig,
|
|
32
|
-
css: css.defaultConfig,
|
|
33
|
-
portal: portal.defaultConfig,
|
|
34
|
-
router: router.defaultConfig,
|
|
35
|
-
} as const;
|