@khanacademy/wonder-blocks-testing 0.0.2 → 2.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 +39 -2
- package/dist/es/index.js +200 -24
- package/dist/index.js +249 -52
- package/package.json +6 -4
- package/src/fixtures/__tests__/setup.test.js +6 -4
- package/src/gql/__tests__/gql-request-matches-mock.test.js +235 -0
- package/src/gql/__tests__/make-gql-mock-response.test.js +298 -0
- package/src/gql/__tests__/mock-gql-fetch.test.js +469 -0
- package/src/gql/__tests__/wb-data-integration.test.js +267 -0
- package/src/gql/gql-request-matches-mock.js +74 -0
- package/src/gql/make-gql-mock-response.js +124 -0
- package/src/gql/mock-gql-fetch.js +89 -0
- package/src/gql/types.js +35 -0
- package/src/index.js +17 -3
- package/src/jest/isolate-modules.js +0 -31
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import {gqlRequestMatchesMock} from "../gql-request-matches-mock.js";
|
|
3
|
+
|
|
4
|
+
describe("#gqlRequestMatchesMock", () => {
|
|
5
|
+
it("should return false if operation types don't match", () => {
|
|
6
|
+
// Arrange
|
|
7
|
+
const mock = {
|
|
8
|
+
operation: {
|
|
9
|
+
id: "foo",
|
|
10
|
+
type: "query",
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
const operation = {
|
|
14
|
+
id: "foo",
|
|
15
|
+
type: "mutation",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Act
|
|
19
|
+
const result = gqlRequestMatchesMock(mock, operation, null, {});
|
|
20
|
+
|
|
21
|
+
// Assert
|
|
22
|
+
expect(result).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should return false if operation ids don't match", () => {
|
|
26
|
+
// Arrange
|
|
27
|
+
const mock = {
|
|
28
|
+
operation: {
|
|
29
|
+
id: "foo",
|
|
30
|
+
type: "query",
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Act
|
|
35
|
+
const result = gqlRequestMatchesMock(
|
|
36
|
+
mock,
|
|
37
|
+
{
|
|
38
|
+
id: "bar",
|
|
39
|
+
type: "query",
|
|
40
|
+
},
|
|
41
|
+
null,
|
|
42
|
+
{},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// Assert
|
|
46
|
+
expect(result).toBe(false);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it.each([{foo: "bar"}, {foo: "baz", anExtra: "property"}, null])(
|
|
50
|
+
"should return false if variables don't match",
|
|
51
|
+
(variables) => {
|
|
52
|
+
// Arrange
|
|
53
|
+
const mock = {
|
|
54
|
+
operation: {
|
|
55
|
+
id: "foo",
|
|
56
|
+
type: "query",
|
|
57
|
+
},
|
|
58
|
+
variables: {
|
|
59
|
+
foo: "baz",
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
const operation = {
|
|
63
|
+
id: "foo",
|
|
64
|
+
type: "query",
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Act
|
|
68
|
+
const result = gqlRequestMatchesMock(
|
|
69
|
+
mock,
|
|
70
|
+
operation,
|
|
71
|
+
variables,
|
|
72
|
+
{},
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// Assert
|
|
76
|
+
expect(result).toBe(false);
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
it.each([{a: "context"}, null])(
|
|
81
|
+
"should return false if contexts don't match",
|
|
82
|
+
(context) => {
|
|
83
|
+
// Arrange
|
|
84
|
+
const mock = {
|
|
85
|
+
operation: {
|
|
86
|
+
id: "foo",
|
|
87
|
+
type: "query",
|
|
88
|
+
},
|
|
89
|
+
variables: {
|
|
90
|
+
foo: "bar",
|
|
91
|
+
},
|
|
92
|
+
context: {
|
|
93
|
+
mock: "context",
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
const operation = {
|
|
97
|
+
id: "foo",
|
|
98
|
+
type: "query",
|
|
99
|
+
};
|
|
100
|
+
const variables = {
|
|
101
|
+
foo: "bar",
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Act
|
|
105
|
+
const result = gqlRequestMatchesMock(
|
|
106
|
+
mock,
|
|
107
|
+
operation,
|
|
108
|
+
variables,
|
|
109
|
+
context,
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
// Assert
|
|
113
|
+
expect(result).toBe(false);
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
it("should return true if operation matches and mock does not include context nor variables, regardless of comparison operation variables and context", () => {
|
|
118
|
+
// Arrange
|
|
119
|
+
const mock = {
|
|
120
|
+
operation: {
|
|
121
|
+
id: "foo",
|
|
122
|
+
type: "query",
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Act
|
|
127
|
+
const result = gqlRequestMatchesMock(
|
|
128
|
+
mock,
|
|
129
|
+
{
|
|
130
|
+
id: "foo",
|
|
131
|
+
type: "query",
|
|
132
|
+
},
|
|
133
|
+
{a: "variable"},
|
|
134
|
+
{my: "context"},
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// Assert
|
|
138
|
+
expect(result).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("should return true if operation and variables match and there is no mock context", () => {
|
|
142
|
+
// Arrange
|
|
143
|
+
const mock = {
|
|
144
|
+
operation: {
|
|
145
|
+
id: "foo",
|
|
146
|
+
type: "query",
|
|
147
|
+
},
|
|
148
|
+
variables: {
|
|
149
|
+
foo: "bar",
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// Act
|
|
154
|
+
const result = gqlRequestMatchesMock(
|
|
155
|
+
mock,
|
|
156
|
+
{
|
|
157
|
+
id: "foo",
|
|
158
|
+
type: "query",
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
foo: "bar",
|
|
162
|
+
},
|
|
163
|
+
{my: "context"},
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Assert
|
|
167
|
+
expect(result).toBe(true);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should return true if operation and context match and there are no mock variables", () => {
|
|
171
|
+
// Arrange
|
|
172
|
+
const mock = {
|
|
173
|
+
operation: {
|
|
174
|
+
id: "foo",
|
|
175
|
+
type: "query",
|
|
176
|
+
},
|
|
177
|
+
context: {
|
|
178
|
+
foo: "bar",
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Act
|
|
183
|
+
const result = gqlRequestMatchesMock(
|
|
184
|
+
mock,
|
|
185
|
+
{
|
|
186
|
+
id: "foo",
|
|
187
|
+
type: "query",
|
|
188
|
+
},
|
|
189
|
+
{a: "variable"},
|
|
190
|
+
{
|
|
191
|
+
foo: "bar",
|
|
192
|
+
},
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
// Assert
|
|
196
|
+
expect(result).toBe(true);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("should return true if everything matches", () => {
|
|
200
|
+
// Arrange
|
|
201
|
+
const mock = {
|
|
202
|
+
operation: {
|
|
203
|
+
id: "foo",
|
|
204
|
+
type: "query",
|
|
205
|
+
},
|
|
206
|
+
variables: {
|
|
207
|
+
foo: "bar",
|
|
208
|
+
},
|
|
209
|
+
context: {
|
|
210
|
+
foo: "bar",
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
const operation = {
|
|
214
|
+
id: "foo",
|
|
215
|
+
type: "query",
|
|
216
|
+
};
|
|
217
|
+
const variables = {
|
|
218
|
+
foo: "bar",
|
|
219
|
+
};
|
|
220
|
+
const context = {
|
|
221
|
+
foo: "bar",
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// Act
|
|
225
|
+
const result = gqlRequestMatchesMock(
|
|
226
|
+
mock,
|
|
227
|
+
operation,
|
|
228
|
+
{...variables},
|
|
229
|
+
{...context},
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
// Assert
|
|
233
|
+
expect(result).toBe(true);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import {RespondWith, makeGqlMockResponse} from "../make-gql-mock-response.js";
|
|
3
|
+
|
|
4
|
+
describe("RespondWith", () => {
|
|
5
|
+
describe("#data", () => {
|
|
6
|
+
it("should have type data", () => {
|
|
7
|
+
// Arrange
|
|
8
|
+
|
|
9
|
+
// Act
|
|
10
|
+
const result = RespondWith.data({});
|
|
11
|
+
|
|
12
|
+
// Assert
|
|
13
|
+
expect(result).toHaveProperty("type", "data");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should include the given data", () => {
|
|
17
|
+
// Arrange
|
|
18
|
+
const data = {
|
|
19
|
+
foo: "bar",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Act
|
|
23
|
+
const result = RespondWith.data(data);
|
|
24
|
+
|
|
25
|
+
// Assert
|
|
26
|
+
expect(result).toHaveProperty("data", data);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("#unparseableBody", () => {
|
|
31
|
+
it("should have type parse", () => {
|
|
32
|
+
// Arrange
|
|
33
|
+
|
|
34
|
+
// Act
|
|
35
|
+
const result = RespondWith.unparseableBody();
|
|
36
|
+
|
|
37
|
+
// Assert
|
|
38
|
+
expect(result).toHaveProperty("type", "parse");
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("#abortedRequest", () => {
|
|
43
|
+
it("should have type abort", () => {
|
|
44
|
+
// Arrange
|
|
45
|
+
|
|
46
|
+
// Act
|
|
47
|
+
const result = RespondWith.abortedRequest();
|
|
48
|
+
|
|
49
|
+
// Assert
|
|
50
|
+
expect(result).toHaveProperty("type", "abort");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("#errorStatusCode", () => {
|
|
55
|
+
it("should have type status", () => {
|
|
56
|
+
// Arrange
|
|
57
|
+
|
|
58
|
+
// Act
|
|
59
|
+
const result = RespondWith.errorStatusCode(400);
|
|
60
|
+
|
|
61
|
+
// Assert
|
|
62
|
+
expect(result).toHaveProperty("type", "status");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("should include the given status code", () => {
|
|
66
|
+
// Arrange
|
|
67
|
+
|
|
68
|
+
// Act
|
|
69
|
+
const result = RespondWith.errorStatusCode(400);
|
|
70
|
+
|
|
71
|
+
// Assert
|
|
72
|
+
expect(result).toHaveProperty("statusCode", 400);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should throw if the status code represents success", () => {
|
|
76
|
+
// Arrange
|
|
77
|
+
|
|
78
|
+
// Act
|
|
79
|
+
const result = () => RespondWith.errorStatusCode(200);
|
|
80
|
+
|
|
81
|
+
// Assert
|
|
82
|
+
expect(result).toThrowErrorMatchingInlineSnapshot(
|
|
83
|
+
`"200 is not a valid error status code"`,
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe("#nonGraphQLBody", () => {
|
|
89
|
+
it("should have type invalid", () => {
|
|
90
|
+
// Arrange
|
|
91
|
+
|
|
92
|
+
// Act
|
|
93
|
+
const result = RespondWith.nonGraphQLBody();
|
|
94
|
+
|
|
95
|
+
// Assert
|
|
96
|
+
expect(result).toHaveProperty("type", "invalid");
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe("#graphQLErrors", () => {
|
|
101
|
+
it("should have type graphql", () => {
|
|
102
|
+
// Arrange
|
|
103
|
+
|
|
104
|
+
// Act
|
|
105
|
+
const result = RespondWith.graphQLErrors([]);
|
|
106
|
+
|
|
107
|
+
// Assert
|
|
108
|
+
expect(result).toHaveProperty("type", "graphql");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("should include the given error messages", () => {
|
|
112
|
+
// Arrange
|
|
113
|
+
const errorMessages = ["foo", "bar"];
|
|
114
|
+
|
|
115
|
+
// Act
|
|
116
|
+
const result = RespondWith.graphQLErrors(errorMessages);
|
|
117
|
+
|
|
118
|
+
// Assert
|
|
119
|
+
expect(result).toHaveProperty("errors", errorMessages);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe("#makeGqlErrorResponse", () => {
|
|
125
|
+
it("should throw for unknown response type", () => {
|
|
126
|
+
// Arrange
|
|
127
|
+
|
|
128
|
+
// Act
|
|
129
|
+
const result = () =>
|
|
130
|
+
makeGqlMockResponse(({type: "NOT A VALID TYPE"}: any));
|
|
131
|
+
|
|
132
|
+
// Assert
|
|
133
|
+
expect(result).toThrowErrorMatchingInlineSnapshot(
|
|
134
|
+
`"Unknown response type: NOT A VALID TYPE"`,
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe("data response", () => {
|
|
139
|
+
it("should resolve to have a successful status code", async () => {
|
|
140
|
+
// Arrange
|
|
141
|
+
const mockResponse = RespondWith.data({});
|
|
142
|
+
|
|
143
|
+
// Act
|
|
144
|
+
const result = await makeGqlMockResponse(mockResponse);
|
|
145
|
+
|
|
146
|
+
// Assert
|
|
147
|
+
expect(result.status).toBe(200);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("should resolve to response with text() function that resolves to GraphQL data result", async () => {
|
|
151
|
+
// Arrange
|
|
152
|
+
const data = {
|
|
153
|
+
foo: "bar",
|
|
154
|
+
};
|
|
155
|
+
const mockResponse = RespondWith.data(data);
|
|
156
|
+
|
|
157
|
+
// Act
|
|
158
|
+
const response = await makeGqlMockResponse(mockResponse);
|
|
159
|
+
const result = await response.text();
|
|
160
|
+
|
|
161
|
+
// Assert
|
|
162
|
+
expect(result).toEqual(JSON.stringify({data}));
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe("unparseable body response", () => {
|
|
167
|
+
it("should resolve to have a successful status code", async () => {
|
|
168
|
+
// Arrange
|
|
169
|
+
const mockResponse = RespondWith.unparseableBody();
|
|
170
|
+
|
|
171
|
+
// Act
|
|
172
|
+
const result = await makeGqlMockResponse(mockResponse);
|
|
173
|
+
|
|
174
|
+
// Assert
|
|
175
|
+
expect(result.status).toBe(200);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("should resolve to response with text() function that resolves to non-JSON text", async () => {
|
|
179
|
+
// Arrange
|
|
180
|
+
const mockResponse = RespondWith.unparseableBody();
|
|
181
|
+
|
|
182
|
+
// Act
|
|
183
|
+
const response = await makeGqlMockResponse(mockResponse);
|
|
184
|
+
const text = await response.text();
|
|
185
|
+
const act = () => JSON.parse(text);
|
|
186
|
+
|
|
187
|
+
// Assert
|
|
188
|
+
expect(act).toThrowError();
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
describe("aborted request response", () => {
|
|
193
|
+
it("should reject with error", async () => {
|
|
194
|
+
// Arrange
|
|
195
|
+
const mockResponse = RespondWith.abortedRequest();
|
|
196
|
+
|
|
197
|
+
// Act
|
|
198
|
+
const act = () => makeGqlMockResponse(mockResponse);
|
|
199
|
+
|
|
200
|
+
// Assert
|
|
201
|
+
await expect(act).rejects.toBeInstanceOf(Error);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("should reject with an AbortError", async () => {
|
|
205
|
+
// Arrange
|
|
206
|
+
const mockResponse = RespondWith.abortedRequest();
|
|
207
|
+
|
|
208
|
+
// Act
|
|
209
|
+
const act = makeGqlMockResponse(mockResponse);
|
|
210
|
+
|
|
211
|
+
// Assert
|
|
212
|
+
await expect(act).rejects.toHaveProperty("name", "AbortError");
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
describe("error status code response", () => {
|
|
217
|
+
it("should resolve to have the given status code", async () => {
|
|
218
|
+
// Arrange
|
|
219
|
+
const mockResponse = RespondWith.errorStatusCode(400);
|
|
220
|
+
|
|
221
|
+
// Act
|
|
222
|
+
const result = await makeGqlMockResponse(mockResponse);
|
|
223
|
+
|
|
224
|
+
// Assert
|
|
225
|
+
expect(result.status).toBe(400);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("should resolve to response with text() function that resolves to some parseable JSON", async () => {
|
|
229
|
+
// Arrange
|
|
230
|
+
const mockResponse = RespondWith.errorStatusCode(400);
|
|
231
|
+
|
|
232
|
+
// Act
|
|
233
|
+
const response = await makeGqlMockResponse(mockResponse);
|
|
234
|
+
const text = await response.text();
|
|
235
|
+
const act = () => JSON.parse(text);
|
|
236
|
+
|
|
237
|
+
// Assert
|
|
238
|
+
expect(act).not.toThrowError();
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
describe("non-graphql body response", () => {
|
|
243
|
+
it("should resolve to have a successful status code", async () => {
|
|
244
|
+
// Arrange
|
|
245
|
+
const mockResponse = RespondWith.nonGraphQLBody();
|
|
246
|
+
|
|
247
|
+
// Act
|
|
248
|
+
const result = await makeGqlMockResponse(mockResponse);
|
|
249
|
+
|
|
250
|
+
// Assert
|
|
251
|
+
expect(result.status).toBe(200);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it("should resolve to response with text() function that resolves to JSON parseable text that is not a valid GraphQL response", async () => {
|
|
255
|
+
// Arrange
|
|
256
|
+
const mockResponse = RespondWith.nonGraphQLBody();
|
|
257
|
+
|
|
258
|
+
// Act
|
|
259
|
+
const response = await makeGqlMockResponse(mockResponse);
|
|
260
|
+
const text = await response.text();
|
|
261
|
+
const result = JSON.parse(text);
|
|
262
|
+
|
|
263
|
+
// Assert
|
|
264
|
+
expect(result).not.toHaveProperty("data");
|
|
265
|
+
expect(result).not.toHaveProperty("errors");
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe("graphql error response", () => {
|
|
270
|
+
it("should resolve to have a successful status code", async () => {
|
|
271
|
+
// Arrange
|
|
272
|
+
const mockResponse = RespondWith.graphQLErrors([]);
|
|
273
|
+
|
|
274
|
+
// Act
|
|
275
|
+
const result = await makeGqlMockResponse(mockResponse);
|
|
276
|
+
|
|
277
|
+
// Assert
|
|
278
|
+
expect(result.status).toBe(200);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("should resolve to response with text() function that resolves to GraphQL error result", async () => {
|
|
282
|
+
// Arrange
|
|
283
|
+
const errorMessages = ["foo", "bar"];
|
|
284
|
+
const mockResponse = RespondWith.graphQLErrors(errorMessages);
|
|
285
|
+
|
|
286
|
+
// Act
|
|
287
|
+
const response = await makeGqlMockResponse(mockResponse);
|
|
288
|
+
const text = await response.text();
|
|
289
|
+
const result = JSON.parse(text);
|
|
290
|
+
|
|
291
|
+
// Assert
|
|
292
|
+
expect(result).toHaveProperty("errors", [
|
|
293
|
+
{message: "foo"},
|
|
294
|
+
{message: "bar"},
|
|
295
|
+
]);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
});
|