@khanacademy/wonder-blocks-testing 2.0.4 → 2.0.7

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 CHANGED
@@ -1,5 +1,31 @@
1
1
  # @khanacademy/wonder-blocks-testing
2
2
 
3
+ ## 2.0.7
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [5ad01891]
8
+ - @khanacademy/wonder-blocks-data@6.0.1
9
+
10
+ ## 2.0.6
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies [1f34c4e8]
15
+ - Updated dependencies [885fe62b]
16
+ - Updated dependencies [5c852025]
17
+ - Updated dependencies [c91f3959]
18
+ - Updated dependencies [5d614ed4]
19
+ - Updated dependencies [753220a4]
20
+ - @khanacademy/wonder-blocks-data@6.0.0
21
+
22
+ ## 2.0.5
23
+
24
+ ### Patch Changes
25
+
26
+ - Updated dependencies [c9922b34]
27
+ - @khanacademy/wonder-blocks-data@5.0.1
28
+
3
29
  ## 2.0.4
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.4",
3
+ "version": "2.0.7",
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": "^5.0.0"
17
+ "@khanacademy/wonder-blocks-data": "^6.0.1"
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 RenderError = () => {
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
- <RenderError />
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 provide null data if aborted response", async () => {
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).then((r) => {
95
- setResult(JSON.stringify(r ?? "(null)"));
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('"(null)"'));
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 RenderError = () => {
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
- <RenderError />
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 respond with null data for RespondWith.abortedRequest", async () => {
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).then((r) => {
94
- setResult(JSON.stringify(r ?? "(null)"));
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('"(null)"'));
115
+ await waitFor(() => expect(result).toHaveTextContent("aborted"));
116
116
  });
117
117
 
118
118
  it("should reject with unsuccessful response error for RespondWith.errorStatusCode", async () => {