@khanacademy/wonder-blocks-testing 10.1.1 → 11.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 +17 -0
- package/dist/es/index.js +25 -386
- package/dist/gql/types.d.ts +1 -2
- package/dist/harness/adapters/data.d.ts +1 -1
- package/dist/harness/adapters/index.d.ts +41 -0
- package/dist/harness/adapters/ssr.d.ts +1 -1
- package/dist/index.d.ts +8 -13
- package/dist/index.js +61 -395
- package/package.json +8 -6
- package/src/gql/__tests__/mock-gql-fetch.test.tsx +1 -1
- package/src/gql/__tests__/types.typestest.ts +1 -1
- package/src/gql/__tests__/wb-data-integration.test.tsx +1 -1
- package/src/gql/mock-gql-fetch.ts +1 -1
- package/src/gql/types.ts +4 -2
- package/src/harness/adapters/__tests__/ssr.test.tsx +1 -1
- package/src/harness/adapters/data.tsx +1 -1
- package/src/harness/adapters/{adapters.ts → index.ts} +10 -11
- package/src/harness/adapters/ssr.tsx +1 -1
- package/src/index.ts +32 -13
- package/tsconfig-build.json +1 -0
- package/tsconfig-build.tsbuildinfo +1 -1
- package/dist/fetch/fetch-request-matches-mock.d.ts +0 -5
- package/dist/fetch/mock-fetch.d.ts +0 -5
- package/dist/fetch/types.d.ts +0 -9
- package/dist/fixtures/fixtures.basic.stories.d.ts +0 -13
- package/dist/fixtures/fixtures.d.ts +0 -13
- package/dist/fixtures/fixtures.defaultwrapper.stories.d.ts +0 -9
- package/dist/fixtures/types.d.ts +0 -36
- package/dist/harness/adapt.d.ts +0 -17
- package/dist/harness/adapters/adapters.d.ts +0 -36
- package/dist/harness/adapters/css.d.ts +0 -12
- package/dist/harness/adapters/portal.d.ts +0 -12
- package/dist/harness/adapters/router.d.ts +0 -94
- package/dist/harness/get-named-adapter-component.d.ts +0 -16
- package/dist/harness/hook-harness.d.ts +0 -13
- package/dist/harness/make-hook-harness.d.ts +0 -17
- package/dist/harness/make-test-harness.d.ts +0 -15
- package/dist/harness/test-harness.d.ts +0 -33
- package/dist/harness/types.d.ts +0 -36
- package/dist/mock-requester.d.ts +0 -5
- package/dist/respond-with.d.ts +0 -75
- package/dist/response-impl.d.ts +0 -1
- package/dist/settle-controller.d.ts +0 -19
- package/dist/settle-signal.d.ts +0 -18
- package/dist/types.d.ts +0 -25
- package/src/__tests__/mock-requester.test.ts +0 -212
- 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__/portal.test.tsx +0 -30
- package/src/harness/adapters/__tests__/router.test.tsx +0 -252
- package/src/harness/adapters/css.tsx +0 -66
- 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/mock-requester.ts +0 -68
- 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
|
@@ -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,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,66 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import type {CSSProperties} from "aphrodite";
|
|
4
|
-
|
|
5
|
-
import type {TestHarnessAdapter} from "../types";
|
|
6
|
-
|
|
7
|
-
type Config =
|
|
8
|
-
| string
|
|
9
|
-
| Array<string>
|
|
10
|
-
| CSSProperties
|
|
11
|
-
| {
|
|
12
|
-
classes: Array<string>;
|
|
13
|
-
style: CSSProperties;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
// The default configuration is to omit this adapter.
|
|
17
|
-
export const defaultConfig: Config | null | undefined = null;
|
|
18
|
-
|
|
19
|
-
const normalizeConfig = (
|
|
20
|
-
config: Config,
|
|
21
|
-
): {
|
|
22
|
-
classes: Array<string>;
|
|
23
|
-
style: CSSProperties;
|
|
24
|
-
} => {
|
|
25
|
-
if (typeof config === "string") {
|
|
26
|
-
return {classes: [config], style: {} as Partial<CSSProperties>};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (Array.isArray(config)) {
|
|
30
|
-
return {classes: config, style: {} as Partial<CSSProperties>};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (typeof config === "object") {
|
|
34
|
-
if (
|
|
35
|
-
"classes" in config &&
|
|
36
|
-
config.classes != null &&
|
|
37
|
-
"style" in config &&
|
|
38
|
-
config.style != null
|
|
39
|
-
) {
|
|
40
|
-
return config;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return {classes: [], style: config as CSSProperties};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
throw new Error(`Invalid config: ${config}`);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Test harness adapter for adding CSS to the harnessed component wrapper.
|
|
51
|
-
*/
|
|
52
|
-
export const adapter: TestHarnessAdapter<Config> = (
|
|
53
|
-
children: React.ReactNode,
|
|
54
|
-
config: Config,
|
|
55
|
-
): React.ReactElement<any> => {
|
|
56
|
-
const {classes, style} = normalizeConfig(config);
|
|
57
|
-
return (
|
|
58
|
-
<div
|
|
59
|
-
data-testid="css-adapter-container"
|
|
60
|
-
className={classes.join(" ")}
|
|
61
|
-
style={style}
|
|
62
|
-
>
|
|
63
|
-
{children}
|
|
64
|
-
</div>
|
|
65
|
-
);
|
|
66
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import type {TestHarnessAdapter} from "../types";
|
|
4
|
-
|
|
5
|
-
type Config = string;
|
|
6
|
-
|
|
7
|
-
// The default configuration is to omit this adapter.
|
|
8
|
-
export const defaultConfig: Config | null | undefined = null;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Test harness adapter for supporting portals.
|
|
12
|
-
*
|
|
13
|
-
* Some components rely on rendering with a React Portal. This adapter ensures
|
|
14
|
-
* that the DOM contains a mounting point for the portal with the expected
|
|
15
|
-
* identifier.
|
|
16
|
-
*/
|
|
17
|
-
export const adapter: TestHarnessAdapter<Config> = (
|
|
18
|
-
children: React.ReactNode,
|
|
19
|
-
config: Config,
|
|
20
|
-
): React.ReactElement<any> => (
|
|
21
|
-
<>
|
|
22
|
-
<div id={config} data-testid={config} />
|
|
23
|
-
{children}
|
|
24
|
-
</>
|
|
25
|
-
);
|