@khanacademy/wonder-blocks-testing 2.0.3 → 2.0.6
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 +26 -0
- package/package.json +2 -2
- package/src/__docs__/_overview_.stories.mdx +19 -0
- package/src/__docs__/exports.mock-gql-fetch.stories.mdx +59 -0
- package/src/__docs__/exports.respond-with.stories.mdx +27 -0
- package/src/gql/__tests__/mock-gql-fetch.test.js +6 -6
- package/src/gql/__tests__/wb-data-integration.test.js +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-testing
|
|
2
2
|
|
|
3
|
+
## 2.0.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [1f34c4e8]
|
|
8
|
+
- Updated dependencies [885fe62b]
|
|
9
|
+
- Updated dependencies [5c852025]
|
|
10
|
+
- Updated dependencies [c91f3959]
|
|
11
|
+
- Updated dependencies [5d614ed4]
|
|
12
|
+
- Updated dependencies [753220a4]
|
|
13
|
+
- @khanacademy/wonder-blocks-data@6.0.0
|
|
14
|
+
|
|
15
|
+
## 2.0.5
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies [c9922b34]
|
|
20
|
+
- @khanacademy/wonder-blocks-data@5.0.1
|
|
21
|
+
|
|
22
|
+
## 2.0.4
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- Updated dependencies [5b5f85ac]
|
|
27
|
+
- @khanacademy/wonder-blocks-data@5.0.0
|
|
28
|
+
|
|
3
29
|
## 2.0.3
|
|
4
30
|
|
|
5
31
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-testing",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"design": "v1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@babel/runtime": "^7.16.3",
|
|
17
|
-
"@khanacademy/wonder-blocks-data": "^
|
|
17
|
+
"@khanacademy/wonder-blocks-data": "^6.0.0"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"@khanacademy/wonder-stuff-core": "^0.1.2",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {Meta} from "@storybook/addon-docs";
|
|
2
|
+
|
|
3
|
+
<Meta
|
|
4
|
+
title="Testing / Overview"
|
|
5
|
+
parameters={{
|
|
6
|
+
chromatic: {
|
|
7
|
+
disableSnapshot: true,
|
|
8
|
+
},
|
|
9
|
+
}}
|
|
10
|
+
/>
|
|
11
|
+
|
|
12
|
+
# Wonder Blocks Testing
|
|
13
|
+
|
|
14
|
+
Wonder Blocks Testing provides various utilities to support testing of React components and Wonder Blocks features.
|
|
15
|
+
|
|
16
|
+
* [Fixtures Framework](/docs/testing-fixtures-basic--f-1)
|
|
17
|
+
* Testing Wonder Blocks Data GraphQL
|
|
18
|
+
* [`mockGqlFetch`](/docs/testing-exports-mockgqlfetch--page)
|
|
19
|
+
* [`RespondWith`](/docs/testing-exports-respondwith--page)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {Meta} from "@storybook/addon-docs";
|
|
2
|
+
|
|
3
|
+
<Meta
|
|
4
|
+
title="Testing / Exports / mockGqlFetch()"
|
|
5
|
+
parameters={{
|
|
6
|
+
chromatic: {
|
|
7
|
+
disableSnapshot: true,
|
|
8
|
+
},
|
|
9
|
+
}}
|
|
10
|
+
/>
|
|
11
|
+
|
|
12
|
+
# mockGqlFetch()
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
mockGqlFetch(): GqlFetchMockFn;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The `mockGqlFetch` function provides an API to easily mock GraphQL responses for use with the [Wonder Blocks Data GraphQL API](/docs/data-graphql--page). It follows the similar patterns of `jest.fn()` and jest mocks whereby the returned value is both a proxy for the fetch function that is used by [`GqlRouter`](/docs/data-exports-gqlrouter--page) as well as an API for modifying the behavior of that function.
|
|
19
|
+
|
|
20
|
+
# API
|
|
21
|
+
|
|
22
|
+
Besides being a function that fits the [`GqlFetchFn`](/docs/data-types-gqlfetchfn--page) signature, the return value of `mockGqlFetch()` has an API to customize the behavior of that function. Used in conjunction with the [`RespondWith`](/docs/testing-exports-respondwith--page) API, this can create a variety of GraphQL responses for testing and stories.
|
|
23
|
+
|
|
24
|
+
| Function | Purpose |
|
|
25
|
+
| -------- | ------- |
|
|
26
|
+
| `mockOperation` | When called, any GraphQL operation that matches the defined mock operation will respond with the given response. |
|
|
27
|
+
| `mockOperationOnce` | When called, the first GraphQL operation that matches the defined mock operation will respond with the given response. The mock is only used by once. |
|
|
28
|
+
|
|
29
|
+
Both of these functions have the same signature:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
type GqlMockOperationFn = <TData, TVariables: {...}, TContext: GqlContext>(
|
|
33
|
+
matchOperation: GqlMockOperation<TData, TVariables, TContext>,
|
|
34
|
+
response: GqlMockResponse<TData>,
|
|
35
|
+
) => GqlFetchMockFn;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
# Operation Matching
|
|
39
|
+
|
|
40
|
+
The `matchOperation` parameter given to a `mockOperation` or `mockOperationOnce` function is a `GqlMockOperation` defining the actual GraphQL operation to be matched by the mock. The variables and context of the mocked operation change how the mock is matched against requests.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
type GqlMockOperation<
|
|
44
|
+
TData,
|
|
45
|
+
TVariables: {...},
|
|
46
|
+
TContext: GqlContext,
|
|
47
|
+
> = {|
|
|
48
|
+
operation: GqlOperation<TData, TVariables>,
|
|
49
|
+
variables?: TVariables,
|
|
50
|
+
context?: TContext,
|
|
51
|
+
|};
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
1. When `matchOperation.operation` is present but `matchOperation.variables` and `matchOperation.context` are not, the mock will match any request for the
|
|
55
|
+
same operation, regardless of variables or context on the request.
|
|
56
|
+
2. When `matchOperation.variables` is present but `matchOperation.context` is not, the mock will match any request for the same operation with matching variables, regardless of context on the request.
|
|
57
|
+
3. When `matchOperation.context` is present but `matchOperation.variables` is not, the mock will match any request for the same operation with matching context, regardless of variables on the request.
|
|
58
|
+
4. When `matchOperation.variables` and `matchOperation.context` are present, the mock will match any request for the same operation with matching variables and context.
|
|
59
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {Meta} from "@storybook/addon-docs";
|
|
2
|
+
|
|
3
|
+
<Meta
|
|
4
|
+
title="Testing / Exports / RespondWith"
|
|
5
|
+
parameters={{
|
|
6
|
+
chromatic: {
|
|
7
|
+
disableSnapshot: true,
|
|
8
|
+
},
|
|
9
|
+
}}
|
|
10
|
+
/>
|
|
11
|
+
|
|
12
|
+
# RespondWith
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
interface RespondWith {
|
|
16
|
+
data: <TData>(data: TData) => GqlMockResponse<TData>;
|
|
17
|
+
unparseableBody: () => GqlMockResponse<any>;
|
|
18
|
+
abortedRequest: () => GqlMockResponse<any>;
|
|
19
|
+
errorStatusCode: (statusCode: number) => GqlMockResponse<any>,
|
|
20
|
+
nonGraphQLBody: () => GqlMockResponse<any>,
|
|
21
|
+
graphQLErrors: (
|
|
22
|
+
errorMessages: $ReadOnlyArray<string>,
|
|
23
|
+
) => GqlMockResponse<any>,
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The `RespondWith` object is a helper for defining mock responses to use with the [`mockGqlFetch`](/docs/testing-exports-mockgqlfetch--page) API.
|
|
@@ -50,7 +50,7 @@ describe("#mockGqlFetch", () => {
|
|
|
50
50
|
id: "getMyStuff",
|
|
51
51
|
};
|
|
52
52
|
const data = {myStuff: "stuff"};
|
|
53
|
-
const
|
|
53
|
+
const RenderData = () => {
|
|
54
54
|
const [result, setResult] = React.useState(null);
|
|
55
55
|
const gqlFetch = useGql();
|
|
56
56
|
React.useEffect(() => {
|
|
@@ -68,7 +68,7 @@ describe("#mockGqlFetch", () => {
|
|
|
68
68
|
mockFetch.mockOperation({operation: query}, RespondWith.data(data));
|
|
69
69
|
render(
|
|
70
70
|
<GqlRouter defaultContext={{}} fetch={mockFetch}>
|
|
71
|
-
<
|
|
71
|
+
<RenderData />
|
|
72
72
|
</GqlRouter>,
|
|
73
73
|
);
|
|
74
74
|
const result = screen.getByTestId("result");
|
|
@@ -79,7 +79,7 @@ describe("#mockGqlFetch", () => {
|
|
|
79
79
|
);
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
it("should
|
|
82
|
+
it("should reject when request aborted", async () => {
|
|
83
83
|
// Arrange
|
|
84
84
|
const mockFetch = mockGqlFetch();
|
|
85
85
|
const query = {
|
|
@@ -91,8 +91,8 @@ describe("#mockGqlFetch", () => {
|
|
|
91
91
|
const gqlFetch = useGql();
|
|
92
92
|
React.useEffect(() => {
|
|
93
93
|
// eslint-disable-next-line promise/catch-or-return
|
|
94
|
-
gqlFetch(query).
|
|
95
|
-
setResult(
|
|
94
|
+
gqlFetch(query).catch((e) => {
|
|
95
|
+
setResult(e.message);
|
|
96
96
|
return;
|
|
97
97
|
});
|
|
98
98
|
}, [gqlFetch]);
|
|
@@ -113,7 +113,7 @@ describe("#mockGqlFetch", () => {
|
|
|
113
113
|
const result = screen.getByTestId("result");
|
|
114
114
|
|
|
115
115
|
// Assert
|
|
116
|
-
await waitFor(() => expect(result).toHaveTextContent(
|
|
116
|
+
await waitFor(() => expect(result).toHaveTextContent("aborted"));
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
it("should reject when request gives failed error code", async () => {
|
|
@@ -49,7 +49,7 @@ describe("integrating mockGqlFetch, RespondWith, GqlRouter and useGql", () => {
|
|
|
49
49
|
id: "getMyStuff",
|
|
50
50
|
};
|
|
51
51
|
const data = {myStuff: "stuff"};
|
|
52
|
-
const
|
|
52
|
+
const RenderData = () => {
|
|
53
53
|
const [result, setResult] = React.useState(null);
|
|
54
54
|
const gqlFetch = useGql();
|
|
55
55
|
React.useEffect(() => {
|
|
@@ -67,7 +67,7 @@ describe("integrating mockGqlFetch, RespondWith, GqlRouter and useGql", () => {
|
|
|
67
67
|
mockFetch.mockOperation({operation: query}, RespondWith.data(data));
|
|
68
68
|
render(
|
|
69
69
|
<GqlRouter defaultContext={{}} fetch={mockFetch}>
|
|
70
|
-
<
|
|
70
|
+
<RenderData />
|
|
71
71
|
</GqlRouter>,
|
|
72
72
|
);
|
|
73
73
|
const result = screen.getByTestId("result");
|
|
@@ -78,7 +78,7 @@ describe("integrating mockGqlFetch, RespondWith, GqlRouter and useGql", () => {
|
|
|
78
78
|
);
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
it("should
|
|
81
|
+
it("should reject with AbortError for RespondWith.abortedRequest", async () => {
|
|
82
82
|
// Arrange
|
|
83
83
|
const mockFetch = mockGqlFetch();
|
|
84
84
|
const query = {
|
|
@@ -90,8 +90,8 @@ describe("integrating mockGqlFetch, RespondWith, GqlRouter and useGql", () => {
|
|
|
90
90
|
const gqlFetch = useGql();
|
|
91
91
|
React.useEffect(() => {
|
|
92
92
|
// eslint-disable-next-line promise/catch-or-return
|
|
93
|
-
gqlFetch(query).
|
|
94
|
-
setResult(
|
|
93
|
+
gqlFetch(query).catch((e) => {
|
|
94
|
+
setResult(e.message);
|
|
95
95
|
return;
|
|
96
96
|
});
|
|
97
97
|
}, [gqlFetch]);
|
|
@@ -112,7 +112,7 @@ describe("integrating mockGqlFetch, RespondWith, GqlRouter and useGql", () => {
|
|
|
112
112
|
const result = screen.getByTestId("result");
|
|
113
113
|
|
|
114
114
|
// Assert
|
|
115
|
-
await waitFor(() => expect(result).toHaveTextContent(
|
|
115
|
+
await waitFor(() => expect(result).toHaveTextContent("aborted"));
|
|
116
116
|
});
|
|
117
117
|
|
|
118
118
|
it("should reject with unsuccessful response error for RespondWith.errorStatusCode", async () => {
|