@khanacademy/wonder-blocks-testing 12.0.0 → 13.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 +25 -0
- package/dist/es/index.js +6 -10
- package/dist/gql/types.d.ts +64 -4
- package/dist/index.js +6 -10
- package/package.json +35 -35
- package/src/gql/__tests__/gql-request-matches-mock.test.ts +0 -234
- package/src/gql/__tests__/mock-gql-fetch.test.tsx +0 -479
- package/src/gql/__tests__/types.typestest.ts +0 -97
- package/src/gql/__tests__/wb-data-integration.test.tsx +0 -269
- package/src/gql/gql-request-matches-mock.ts +0 -71
- package/src/gql/mock-gql-fetch.ts +0 -20
- package/src/gql/types.ts +0 -35
- package/src/harness/adapters/__tests__/__snapshots__/render-state.test.tsx.snap +0 -7
- package/src/harness/adapters/__tests__/data.test.tsx +0 -75
- package/src/harness/adapters/__tests__/render-state.test.tsx +0 -86
- package/src/harness/adapters/data.tsx +0 -48
- package/src/harness/adapters/index.ts +0 -34
- package/src/harness/adapters/render-state.tsx +0 -41
- package/src/index.ts +0 -39
- package/tsconfig-build.json +0 -13
- package/tsconfig-build.tsbuildinfo +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-testing
|
|
2
2
|
|
|
3
|
+
## 13.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- eb807af8: When mocking GraphQL, consider explicit undefined values in a request to be equivalent to missing keys in a mock
|
|
8
|
+
|
|
9
|
+
### Minor Changes
|
|
10
|
+
|
|
11
|
+
- 16565a85: Add support for hard fails to the request mocking features
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Updated dependencies [16565a85]
|
|
16
|
+
- @khanacademy/wonder-blocks-testing-core@1.1.0
|
|
17
|
+
|
|
18
|
+
## 12.0.1
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- 02a1b298: Make sure we don't package tsconfig and tsbuildinfo files
|
|
23
|
+
- Updated dependencies [02a1b298]
|
|
24
|
+
- @khanacademy/wonder-blocks-core@7.0.1
|
|
25
|
+
- @khanacademy/wonder-blocks-data@13.0.12
|
|
26
|
+
- @khanacademy/wonder-blocks-testing-core@1.0.2
|
|
27
|
+
|
|
3
28
|
## 12.0.0
|
|
4
29
|
|
|
5
30
|
### Major Changes
|
package/dist/es/index.js
CHANGED
|
@@ -6,8 +6,7 @@ import { InterceptRequests } from '@khanacademy/wonder-blocks-data';
|
|
|
6
6
|
import { KindError, Errors } from '@khanacademy/wonder-stuff-core';
|
|
7
7
|
import { RenderStateRoot } from '@khanacademy/wonder-blocks-core';
|
|
8
8
|
|
|
9
|
-
const
|
|
10
|
-
const areObjectsEqual = (a, b) => {
|
|
9
|
+
const areObjectsEquivalent = (a, b) => {
|
|
11
10
|
if (a === b) {
|
|
12
11
|
return true;
|
|
13
12
|
}
|
|
@@ -19,12 +18,9 @@ const areObjectsEqual = (a, b) => {
|
|
|
19
18
|
}
|
|
20
19
|
const aKeys = Object.keys(a);
|
|
21
20
|
const bKeys = Object.keys(b);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
for (let i = 0; i < aKeys.length; i++) {
|
|
26
|
-
const key = aKeys[i];
|
|
27
|
-
if (!safeHasOwnProperty(b, key) || !areObjectsEqual(a[key], b[key])) {
|
|
21
|
+
const allKeys = new Set([...aKeys, ...bKeys]);
|
|
22
|
+
for (const key of allKeys) {
|
|
23
|
+
if (!areObjectsEquivalent(a[key], b[key])) {
|
|
28
24
|
return false;
|
|
29
25
|
}
|
|
30
26
|
}
|
|
@@ -35,12 +31,12 @@ const gqlRequestMatchesMock = (mock, operation, variables, context) => {
|
|
|
35
31
|
return false;
|
|
36
32
|
}
|
|
37
33
|
if (mock.variables != null) {
|
|
38
|
-
if (!
|
|
34
|
+
if (!areObjectsEquivalent(mock.variables, variables)) {
|
|
39
35
|
return false;
|
|
40
36
|
}
|
|
41
37
|
}
|
|
42
38
|
if (mock.context != null) {
|
|
43
|
-
if (!
|
|
39
|
+
if (!areObjectsEquivalent(mock.context, context)) {
|
|
44
40
|
return false;
|
|
45
41
|
}
|
|
46
42
|
}
|
package/dist/gql/types.d.ts
CHANGED
|
@@ -1,14 +1,74 @@
|
|
|
1
1
|
import type { GqlOperation, GqlContext } from "@khanacademy/wonder-blocks-data";
|
|
2
|
-
import type { GraphQLJson, MockResponse } from "@khanacademy/wonder-blocks-testing-core";
|
|
2
|
+
import type { ConfigureFn, GraphQLJson, MockResponse } from "@khanacademy/wonder-blocks-testing-core";
|
|
3
|
+
/**
|
|
4
|
+
* A GraphQL operation to be mocked.
|
|
5
|
+
*
|
|
6
|
+
* This is used to specify what a request must match in order for a mock to
|
|
7
|
+
* be used.
|
|
8
|
+
*/
|
|
3
9
|
export type GqlMockOperation<TData extends Record<any, any>, TVariables extends Record<any, any>, TContext extends GqlContext> = {
|
|
4
10
|
operation: GqlOperation<TData, TVariables>;
|
|
5
11
|
variables?: TVariables;
|
|
6
12
|
context?: TContext;
|
|
7
13
|
};
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
interface GqlMockOperationFn {
|
|
15
|
+
<TData extends Record<any, any>, TVariables extends Record<any, any>, TContext extends GqlContext, TResponseData extends GraphQLJson<TData>>(
|
|
16
|
+
/**
|
|
17
|
+
* The operation to match.
|
|
18
|
+
*/
|
|
19
|
+
operation: GqlMockOperation<TData, TVariables, TContext>,
|
|
20
|
+
/**
|
|
21
|
+
* The response to return when the operation is matched.
|
|
22
|
+
*/
|
|
23
|
+
response: MockResponse<TResponseData>): GqlFetchMockFn;
|
|
24
|
+
}
|
|
25
|
+
export interface GqlFetchMockFn {
|
|
26
|
+
/**
|
|
27
|
+
* The mock fetch function.
|
|
28
|
+
*
|
|
29
|
+
* This function is a drop-in replacement for the gqlFetch function used
|
|
30
|
+
* by Wonder Blocks Data. You should not need to call this function
|
|
31
|
+
* directly. Just pass this in places where you would pass a gqlFetch
|
|
32
|
+
* function, as provided by the GqlRouter.
|
|
33
|
+
*/
|
|
10
34
|
(operation: GqlOperation<any, any>, variables: Record<any, any> | null | undefined, context: GqlContext): Promise<Response>;
|
|
35
|
+
/**
|
|
36
|
+
* Mock a fetch operation.
|
|
37
|
+
*
|
|
38
|
+
* This adds a response for a given mocked operation. Operations are
|
|
39
|
+
* matched greedily, so if only the GraphQL operation is provided, then
|
|
40
|
+
* all requests for that operation will be matched, regardless of
|
|
41
|
+
* variables or context.
|
|
42
|
+
*
|
|
43
|
+
* Regardless of how many times this mock is matched, it will be used.
|
|
44
|
+
*
|
|
45
|
+
* @returns The mock fetch function for chaining.
|
|
46
|
+
*/
|
|
11
47
|
mockOperation: GqlMockOperationFn;
|
|
48
|
+
/**
|
|
49
|
+
* Mock a fetch operation once.
|
|
50
|
+
*
|
|
51
|
+
* This adds a response for a given mocked operation. Operations are
|
|
52
|
+
* matched greedily, so if only the GraphQL operation is provided, then
|
|
53
|
+
* all requests for that operation will be matched, regardless of
|
|
54
|
+
* variables or context.
|
|
55
|
+
*
|
|
56
|
+
* Once the added mock is used, it will be discarded and no longer match
|
|
57
|
+
* any requests.
|
|
58
|
+
*
|
|
59
|
+
* @returns The mock fetch function for chaining.
|
|
60
|
+
*/
|
|
12
61
|
mockOperationOnce: GqlMockOperationFn;
|
|
13
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Configure the mock fetch function with the given configuration.
|
|
64
|
+
*
|
|
65
|
+
* This function is provided as a convenience to allow for configuring the
|
|
66
|
+
* mock fetch function in a fluent manner. The configuration is applied
|
|
67
|
+
* to all mocks for a given fetch function; the last configuration applied
|
|
68
|
+
* will be the one that is used for all mocked operations.
|
|
69
|
+
*
|
|
70
|
+
* @returns The mock fetch function for chaining.
|
|
71
|
+
*/
|
|
72
|
+
configure: ConfigureFn<GqlMockOperation<any, any, any>, GraphQLJson<any>>;
|
|
73
|
+
}
|
|
14
74
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -32,8 +32,7 @@ function _interopNamespace(e) {
|
|
|
32
32
|
var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
|
|
33
33
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
34
34
|
|
|
35
|
-
const
|
|
36
|
-
const areObjectsEqual = (a, b) => {
|
|
35
|
+
const areObjectsEquivalent = (a, b) => {
|
|
37
36
|
if (a === b) {
|
|
38
37
|
return true;
|
|
39
38
|
}
|
|
@@ -45,12 +44,9 @@ const areObjectsEqual = (a, b) => {
|
|
|
45
44
|
}
|
|
46
45
|
const aKeys = Object.keys(a);
|
|
47
46
|
const bKeys = Object.keys(b);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
for (let i = 0; i < aKeys.length; i++) {
|
|
52
|
-
const key = aKeys[i];
|
|
53
|
-
if (!safeHasOwnProperty(b, key) || !areObjectsEqual(a[key], b[key])) {
|
|
47
|
+
const allKeys = new Set([...aKeys, ...bKeys]);
|
|
48
|
+
for (const key of allKeys) {
|
|
49
|
+
if (!areObjectsEquivalent(a[key], b[key])) {
|
|
54
50
|
return false;
|
|
55
51
|
}
|
|
56
52
|
}
|
|
@@ -61,12 +57,12 @@ const gqlRequestMatchesMock = (mock, operation, variables, context) => {
|
|
|
61
57
|
return false;
|
|
62
58
|
}
|
|
63
59
|
if (mock.variables != null) {
|
|
64
|
-
if (!
|
|
60
|
+
if (!areObjectsEquivalent(mock.variables, variables)) {
|
|
65
61
|
return false;
|
|
66
62
|
}
|
|
67
63
|
}
|
|
68
64
|
if (mock.context != null) {
|
|
69
|
-
if (!
|
|
65
|
+
if (!areObjectsEquivalent(mock.context, context)) {
|
|
70
66
|
return false;
|
|
71
67
|
}
|
|
72
68
|
}
|
package/package.json
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
2
|
+
"name": "@khanacademy/wonder-blocks-testing",
|
|
3
|
+
"version": "13.0.0",
|
|
4
|
+
"design": "v1",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"description": "",
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"module": "dist/es/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@babel/runtime": "^7.18.6",
|
|
17
|
+
"@khanacademy/wonder-blocks-core": "^7.0.1",
|
|
18
|
+
"@khanacademy/wonder-blocks-data": "^13.0.12",
|
|
19
|
+
"@khanacademy/wonder-blocks-testing-core": "^1.1.0"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@khanacademy/wonder-stuff-core": "^1.2.2",
|
|
23
|
+
"@storybook/addon-actions": "^7.0.0",
|
|
24
|
+
"aphrodite": "^1.2.5",
|
|
25
|
+
"node-fetch": "^2.6.7",
|
|
26
|
+
"react": "16.14.0",
|
|
27
|
+
"react-dom": "16.14.0",
|
|
28
|
+
"react-router-dom": "5.3.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@khanacademy/wb-dev-build-settings": "^1.0.1",
|
|
32
|
+
"@khanacademy/wonder-stuff-testing": "^3.0.1"
|
|
33
|
+
},
|
|
34
|
+
"author": "",
|
|
35
|
+
"license": "MIT"
|
|
36
|
+
}
|
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
import {gqlRequestMatchesMock} from "../gql-request-matches-mock";
|
|
2
|
-
|
|
3
|
-
describe("#gqlRequestMatchesMock", () => {
|
|
4
|
-
it("should return false if operation types don't match", () => {
|
|
5
|
-
// Arrange
|
|
6
|
-
const mock = {
|
|
7
|
-
operation: {
|
|
8
|
-
id: "foo",
|
|
9
|
-
type: "query",
|
|
10
|
-
},
|
|
11
|
-
} as const;
|
|
12
|
-
const operation = {
|
|
13
|
-
id: "foo",
|
|
14
|
-
type: "mutation",
|
|
15
|
-
} as const;
|
|
16
|
-
|
|
17
|
-
// Act
|
|
18
|
-
const result = gqlRequestMatchesMock(mock, operation, null, {});
|
|
19
|
-
|
|
20
|
-
// Assert
|
|
21
|
-
expect(result).toBe(false);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it("should return false if operation ids don't match", () => {
|
|
25
|
-
// Arrange
|
|
26
|
-
const mock = {
|
|
27
|
-
operation: {
|
|
28
|
-
id: "foo",
|
|
29
|
-
type: "query",
|
|
30
|
-
},
|
|
31
|
-
} as const;
|
|
32
|
-
|
|
33
|
-
// Act
|
|
34
|
-
const result = gqlRequestMatchesMock(
|
|
35
|
-
mock,
|
|
36
|
-
{
|
|
37
|
-
id: "bar",
|
|
38
|
-
type: "query",
|
|
39
|
-
},
|
|
40
|
-
null,
|
|
41
|
-
{},
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
// Assert
|
|
45
|
-
expect(result).toBe(false);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it.each([{foo: "bar"}, {foo: "baz", anExtra: "property"}, null])(
|
|
49
|
-
"should return false if variables don't match",
|
|
50
|
-
(variables: any) => {
|
|
51
|
-
// Arrange
|
|
52
|
-
const mock = {
|
|
53
|
-
operation: {
|
|
54
|
-
id: "foo",
|
|
55
|
-
type: "query",
|
|
56
|
-
},
|
|
57
|
-
variables: {
|
|
58
|
-
foo: "baz",
|
|
59
|
-
},
|
|
60
|
-
} as const;
|
|
61
|
-
const operation = {
|
|
62
|
-
id: "foo",
|
|
63
|
-
type: "query",
|
|
64
|
-
} as const;
|
|
65
|
-
|
|
66
|
-
// Act
|
|
67
|
-
const result = gqlRequestMatchesMock(
|
|
68
|
-
mock,
|
|
69
|
-
operation,
|
|
70
|
-
variables,
|
|
71
|
-
{},
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
// Assert
|
|
75
|
-
expect(result).toBe(false);
|
|
76
|
-
},
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
it.each([{a: "context"}, null])(
|
|
80
|
-
"should return false if contexts don't match",
|
|
81
|
-
(context: any) => {
|
|
82
|
-
// Arrange
|
|
83
|
-
const mock = {
|
|
84
|
-
operation: {
|
|
85
|
-
id: "foo",
|
|
86
|
-
type: "query",
|
|
87
|
-
},
|
|
88
|
-
variables: {
|
|
89
|
-
foo: "bar",
|
|
90
|
-
},
|
|
91
|
-
context: {
|
|
92
|
-
mock: "context",
|
|
93
|
-
},
|
|
94
|
-
} as const;
|
|
95
|
-
const operation = {
|
|
96
|
-
id: "foo",
|
|
97
|
-
type: "query",
|
|
98
|
-
} as const;
|
|
99
|
-
const variables = {
|
|
100
|
-
foo: "bar",
|
|
101
|
-
} as const;
|
|
102
|
-
|
|
103
|
-
// Act
|
|
104
|
-
const result = gqlRequestMatchesMock(
|
|
105
|
-
mock,
|
|
106
|
-
operation,
|
|
107
|
-
variables,
|
|
108
|
-
context,
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
// Assert
|
|
112
|
-
expect(result).toBe(false);
|
|
113
|
-
},
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
it("should return true if operation matches and mock does not include context nor variables, regardless of comparison operation variables and context", () => {
|
|
117
|
-
// Arrange
|
|
118
|
-
const mock = {
|
|
119
|
-
operation: {
|
|
120
|
-
id: "foo",
|
|
121
|
-
type: "query",
|
|
122
|
-
},
|
|
123
|
-
} as const;
|
|
124
|
-
|
|
125
|
-
// Act
|
|
126
|
-
const result = gqlRequestMatchesMock(
|
|
127
|
-
mock,
|
|
128
|
-
{
|
|
129
|
-
id: "foo",
|
|
130
|
-
type: "query",
|
|
131
|
-
},
|
|
132
|
-
{a: "variable"},
|
|
133
|
-
{my: "context"},
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
// Assert
|
|
137
|
-
expect(result).toBe(true);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it("should return true if operation and variables match and there is no mock context", () => {
|
|
141
|
-
// Arrange
|
|
142
|
-
const mock = {
|
|
143
|
-
operation: {
|
|
144
|
-
id: "foo",
|
|
145
|
-
type: "query",
|
|
146
|
-
},
|
|
147
|
-
variables: {
|
|
148
|
-
foo: "bar",
|
|
149
|
-
},
|
|
150
|
-
} as const;
|
|
151
|
-
|
|
152
|
-
// Act
|
|
153
|
-
const result = gqlRequestMatchesMock(
|
|
154
|
-
mock,
|
|
155
|
-
{
|
|
156
|
-
id: "foo",
|
|
157
|
-
type: "query",
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
foo: "bar",
|
|
161
|
-
},
|
|
162
|
-
{my: "context"},
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
// Assert
|
|
166
|
-
expect(result).toBe(true);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it("should return true if operation and context match and there are no mock variables", () => {
|
|
170
|
-
// Arrange
|
|
171
|
-
const mock = {
|
|
172
|
-
operation: {
|
|
173
|
-
id: "foo",
|
|
174
|
-
type: "query",
|
|
175
|
-
},
|
|
176
|
-
context: {
|
|
177
|
-
foo: "bar",
|
|
178
|
-
},
|
|
179
|
-
} as const;
|
|
180
|
-
|
|
181
|
-
// Act
|
|
182
|
-
const result = gqlRequestMatchesMock(
|
|
183
|
-
mock,
|
|
184
|
-
{
|
|
185
|
-
id: "foo",
|
|
186
|
-
type: "query",
|
|
187
|
-
},
|
|
188
|
-
{a: "variable"},
|
|
189
|
-
{
|
|
190
|
-
foo: "bar",
|
|
191
|
-
},
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
// Assert
|
|
195
|
-
expect(result).toBe(true);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it("should return true if everything matches", () => {
|
|
199
|
-
// Arrange
|
|
200
|
-
const mock = {
|
|
201
|
-
operation: {
|
|
202
|
-
id: "foo",
|
|
203
|
-
type: "query",
|
|
204
|
-
},
|
|
205
|
-
variables: {
|
|
206
|
-
foo: "bar",
|
|
207
|
-
},
|
|
208
|
-
context: {
|
|
209
|
-
foo: "bar",
|
|
210
|
-
},
|
|
211
|
-
} as const;
|
|
212
|
-
const operation = {
|
|
213
|
-
id: "foo",
|
|
214
|
-
type: "query",
|
|
215
|
-
} as const;
|
|
216
|
-
const variables = {
|
|
217
|
-
foo: "bar",
|
|
218
|
-
} as const;
|
|
219
|
-
const context = {
|
|
220
|
-
foo: "bar",
|
|
221
|
-
} as const;
|
|
222
|
-
|
|
223
|
-
// Act
|
|
224
|
-
const result = gqlRequestMatchesMock(
|
|
225
|
-
mock,
|
|
226
|
-
operation,
|
|
227
|
-
{...variables},
|
|
228
|
-
{...context},
|
|
229
|
-
);
|
|
230
|
-
|
|
231
|
-
// Assert
|
|
232
|
-
expect(result).toBe(true);
|
|
233
|
-
});
|
|
234
|
-
});
|