@khanacademy/wonder-blocks-testing 11.0.1 → 12.0.1

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.
@@ -1,479 +0,0 @@
1
- import * as React from "react";
2
- import {render, screen, waitFor} from "@testing-library/react";
3
-
4
- import {GqlRouter, useGql} from "@khanacademy/wonder-blocks-data";
5
- import {RespondWith} from "@khanacademy/wonder-blocks-testing-core";
6
- import {mockGqlFetch} from "../mock-gql-fetch";
7
-
8
- describe("#mockGqlFetch", () => {
9
- describe("with GqlRouter and useGql", () => {
10
- it("should reject when there are no mocks", async () => {
11
- // Arrange
12
- const mockFetch = mockGqlFetch();
13
- const RenderError = () => {
14
- const [result, setResult] = React.useState<any>(null);
15
- const gqlFetch = useGql();
16
- React.useEffect(() => {
17
- gqlFetch({
18
- type: "query",
19
- id: "getMyStuff",
20
- }).catch((e: any) => {
21
- setResult(e.message);
22
- });
23
- }, [gqlFetch]);
24
-
25
- return <div data-testid="result">{result}</div>;
26
- };
27
-
28
- // Act
29
- render(
30
- <GqlRouter defaultContext={{}} fetch={mockFetch}>
31
- <RenderError />
32
- </GqlRouter>,
33
- );
34
- const result = screen.getByTestId("result");
35
-
36
- // Assert
37
- await waitFor(() =>
38
- expect(result).toHaveTextContent(
39
- "No matching mock response found for request",
40
- ),
41
- );
42
- });
43
-
44
- it("should provide data when response gives data", async () => {
45
- // Arrange
46
- const mockFetch = mockGqlFetch();
47
- const query = {
48
- type: "query",
49
- id: "getMyStuff",
50
- } as const;
51
- const data = {myStuff: "stuff"} as const;
52
- const RenderData = () => {
53
- const [result, setResult] = React.useState<any>(null);
54
- const gqlFetch = useGql();
55
- React.useEffect(() => {
56
- // eslint-disable-next-line promise/catch-or-return
57
- gqlFetch(query).then((r: any) => {
58
- setResult(JSON.stringify(r ?? "(null)"));
59
- return;
60
- });
61
- }, [gqlFetch]);
62
-
63
- return <div data-testid="result">{result}</div>;
64
- };
65
-
66
- // Act
67
- mockFetch.mockOperation(
68
- {operation: query},
69
- RespondWith.graphQLData(data),
70
- );
71
- render(
72
- <GqlRouter defaultContext={{}} fetch={mockFetch}>
73
- <RenderData />
74
- </GqlRouter>,
75
- );
76
- const result = screen.getByTestId("result");
77
-
78
- // Assert
79
- await waitFor(() =>
80
- expect(result).toHaveTextContent(JSON.stringify(data)),
81
- );
82
- });
83
-
84
- it("should reject when request aborted", async () => {
85
- // Arrange
86
- const mockFetch = mockGqlFetch();
87
- const query = {
88
- type: "query",
89
- id: "getMyStuff",
90
- } as const;
91
- const RenderError = () => {
92
- const [result, setResult] = React.useState<any>(null);
93
- const gqlFetch = useGql();
94
- React.useEffect(() => {
95
- // eslint-disable-next-line promise/catch-or-return
96
- gqlFetch(query).catch((e: any) => {
97
- setResult(e.message);
98
- return;
99
- });
100
- }, [gqlFetch]);
101
-
102
- return <div data-testid="result">{result}</div>;
103
- };
104
-
105
- // Act
106
- mockFetch.mockOperation(
107
- {operation: query},
108
- RespondWith.abortedRequest(),
109
- );
110
- render(
111
- <GqlRouter defaultContext={{}} fetch={mockFetch}>
112
- <RenderError />
113
- </GqlRouter>,
114
- );
115
- const result = screen.getByTestId("result");
116
-
117
- // Assert
118
- await waitFor(() => expect(result).toHaveTextContent("aborted"));
119
- });
120
-
121
- it("should reject when request gives failed error code", async () => {
122
- // Arrange
123
- const mockFetch = mockGqlFetch();
124
- const query = {
125
- type: "query",
126
- id: "getMyStuff",
127
- } as const;
128
- const RenderError = () => {
129
- const [result, setResult] = React.useState<any>(null);
130
- const gqlFetch = useGql();
131
- React.useEffect(() => {
132
- // eslint-disable-next-line promise/catch-or-return
133
- gqlFetch(query).catch((e: any) => {
134
- setResult(e.message);
135
- });
136
- }, [gqlFetch]);
137
-
138
- return <div data-testid="result">{result}</div>;
139
- };
140
-
141
- // Act
142
- mockFetch.mockOperation(
143
- {operation: query},
144
- RespondWith.errorStatusCode(404),
145
- );
146
- render(
147
- <GqlRouter defaultContext={{}} fetch={mockFetch}>
148
- <RenderError />
149
- </GqlRouter>,
150
- );
151
- const result = screen.getByTestId("result");
152
-
153
- // Assert
154
- await waitFor(() =>
155
- expect(result).toHaveTextContent("Response unsuccessful"),
156
- );
157
- });
158
- });
159
-
160
- it("should reject with a useful error when there are no matching mocks", async () => {
161
- // Arrange
162
- const mockFetch = mockGqlFetch();
163
-
164
- // Act
165
- const result = mockFetch(
166
- {
167
- type: "query",
168
- id: "getMyStuff",
169
- },
170
- {a: "variable"},
171
- {my: "context"},
172
- );
173
-
174
- // Assert
175
- // The indentation on the lines for Operation, Variables, and Context
176
- // are expected.
177
- await expect(result).rejects.toThrowError(
178
- `No matching mock response found for request:
179
- Operation: query getMyStuff
180
- Variables: {
181
- "a": "variable"
182
- }
183
- Context: {
184
- "my": "context"
185
- }`,
186
- );
187
- });
188
-
189
- describe("mockOperation", () => {
190
- it("should match a similar operation when no variables or context in mock", async () => {
191
- // Arrange
192
- const mockFetch = mockGqlFetch();
193
- const operation = {
194
- type: "query",
195
- id: "getMyStuff",
196
- } as const;
197
- const data = {
198
- myStuff: "stuff",
199
- } as const;
200
-
201
- // Act
202
- mockFetch.mockOperation({operation}, RespondWith.graphQLData(data));
203
- const result = mockFetch(
204
- operation,
205
- {a: "variable"},
206
- {my: "context"},
207
- );
208
-
209
- // Assert
210
- await expect(result).resolves.toBeDefined();
211
- });
212
-
213
- it("should not match a different operation when no variables or context in mock", async () => {
214
- // Arrange
215
- const mockFetch = mockGqlFetch();
216
- const operation = {
217
- type: "query",
218
- id: "getMyStuff",
219
- } as const;
220
- const data = {
221
- myStuff: "stuff",
222
- } as const;
223
-
224
- // Act
225
- mockFetch.mockOperation({operation}, RespondWith.graphQLData(data));
226
- const result = mockFetch(
227
- {type: "mutation", id: "putMyStuff"},
228
- {a: "variable"},
229
- {my: "context"},
230
- );
231
-
232
- // Assert
233
- await expect(result).rejects.toThrowError();
234
- });
235
-
236
- it("should match a similar operation when variables also match and no context in mock", async () => {
237
- // Arrange
238
- const mockFetch = mockGqlFetch();
239
- const operation = {
240
- type: "query",
241
- id: "getMyStuff",
242
- } as const;
243
- const variables = {
244
- a: "variable",
245
- } as const;
246
- const data = {
247
- myStuff: "stuff",
248
- } as const;
249
-
250
- // Act
251
- mockFetch.mockOperation(
252
- {operation, variables},
253
- RespondWith.graphQLData(data),
254
- );
255
- const result = mockFetch(operation, variables, {my: "context"});
256
-
257
- // Assert
258
- await expect(result).resolves.toBeDefined();
259
- });
260
-
261
- it("should not match a similar operation when variables do not match and no context in mock", async () => {
262
- // Arrange
263
- const mockFetch = mockGqlFetch();
264
- const operation = {
265
- type: "query",
266
- id: "getMyStuff",
267
- } as const;
268
- const variables = {
269
- a: "variable",
270
- } as const;
271
- const data = {
272
- myStuff: "stuff",
273
- } as const;
274
-
275
- // Act
276
- mockFetch.mockOperation(
277
- {operation, variables},
278
- RespondWith.graphQLData(data),
279
- );
280
- const result = mockFetch(
281
- operation,
282
- {b: "different variable"},
283
- {my: "context"},
284
- );
285
-
286
- // Assert
287
- await expect(result).rejects.toThrowError();
288
- });
289
-
290
- it("should match any similar operation when context also matches and no variables in mock", async () => {
291
- // Arrange
292
- const mockFetch = mockGqlFetch();
293
- const operation = {
294
- type: "query",
295
- id: "getMyStuff",
296
- } as const;
297
- const context = {
298
- my: "context",
299
- } as const;
300
- const data = {
301
- myStuff: "stuff",
302
- } as const;
303
-
304
- // Act
305
- mockFetch.mockOperation(
306
- {operation, context},
307
- RespondWith.graphQLData(data),
308
- );
309
- const result = mockFetch(operation, {a: "variable"}, context);
310
-
311
- // Assert
312
- await expect(result).resolves.toBeDefined();
313
- });
314
-
315
- it("should not match any similar operation when context does not match and no variables in mock", async () => {
316
- // Arrange
317
- const mockFetch = mockGqlFetch();
318
- const operation = {
319
- type: "query",
320
- id: "getMyStuff",
321
- } as const;
322
- const context = {
323
- my: "context",
324
- } as const;
325
- const data = {
326
- myStuff: "stuff",
327
- } as const;
328
-
329
- // Act
330
- mockFetch.mockOperation(
331
- {operation, context},
332
- RespondWith.graphQLData(data),
333
- );
334
- const result = mockFetch(
335
- operation,
336
- {a: "variable"},
337
- {different: "context"},
338
- );
339
-
340
- // Assert
341
- await expect(result).rejects.toThrowError();
342
- });
343
-
344
- it("should match operation when variables and context match the mock", async () => {
345
- // Arrange
346
- const mockFetch = mockGqlFetch();
347
- const operation = {
348
- type: "query",
349
- id: "getMyStuff",
350
- } as const;
351
- const variables = {
352
- a: "variable",
353
- } as const;
354
- const context = {
355
- my: "context",
356
- } as const;
357
- const data = {
358
- myStuff: "stuff",
359
- } as const;
360
-
361
- // Act
362
- mockFetch.mockOperation(
363
- {operation, variables, context},
364
- RespondWith.graphQLData(data),
365
- );
366
- const result = mockFetch(operation, variables, context);
367
-
368
- // Assert
369
- await expect(result).resolves.toBeDefined();
370
- });
371
-
372
- it("should resolve to provide the matching data", async () => {
373
- // Arrange
374
- const mockFetch = mockGqlFetch();
375
- const operation = {
376
- type: "query",
377
- id: "getMyStuff",
378
- } as const;
379
- const variables = {
380
- a: "variable",
381
- } as const;
382
- const context = {
383
- my: "context",
384
- } as const;
385
- const data = {
386
- myStuff: "stuff",
387
- } as const;
388
-
389
- // Act
390
- mockFetch.mockOperation(
391
- {operation, variables, context},
392
- RespondWith.graphQLData(data),
393
- );
394
- const response = await mockFetch(operation, variables, context);
395
- const result = await response.text();
396
-
397
- // Assert
398
- expect(result).toBe(JSON.stringify({data}));
399
- });
400
-
401
- it("should match all call matches", async () => {
402
- // Arrange
403
- const mockFetch = mockGqlFetch();
404
- const operation = {
405
- type: "query",
406
- id: "getMyStuff",
407
- } as const;
408
- const data = {
409
- myStuff: "stuff",
410
- } as const;
411
-
412
- // Act
413
- mockFetch.mockOperation({operation}, RespondWith.graphQLData(data));
414
- const result = Promise.all([
415
- mockFetch(operation, {a: "variable"}, {my: "context"}),
416
- mockFetch(operation, {b: "variable"}, {another: "context"}),
417
- ]);
418
-
419
- // Assert
420
- await expect(result).resolves.toStrictEqual([
421
- expect.any(Object),
422
- expect.any(Object),
423
- ]);
424
- });
425
- });
426
-
427
- describe("mockOperationOnce", () => {
428
- it("should match once", async () => {
429
- // Arrange
430
- const mockFetch = mockGqlFetch();
431
- const operation = {
432
- type: "query",
433
- id: "getMyStuff",
434
- } as const;
435
- const data = {
436
- myStuff: "stuff",
437
- } as const;
438
-
439
- // Act
440
- mockFetch.mockOperationOnce(
441
- {operation},
442
- RespondWith.graphQLData(data),
443
- );
444
- const result = mockFetch(
445
- operation,
446
- {a: "variable"},
447
- {my: "context"},
448
- );
449
-
450
- // Assert
451
- await expect(result).resolves.toBeDefined();
452
- });
453
-
454
- it("should only match once", async () => {
455
- // Arrange
456
- const mockFetch = mockGqlFetch();
457
- const operation = {
458
- type: "query",
459
- id: "getMyStuff",
460
- } as const;
461
- const data = {
462
- myStuff: "stuff",
463
- } as const;
464
-
465
- // Act
466
- mockFetch.mockOperationOnce(
467
- {operation},
468
- RespondWith.graphQLData(data),
469
- );
470
- const result = Promise.all([
471
- mockFetch(operation, {a: "variable"}, {my: "context"}),
472
- mockFetch(operation, {b: "variable"}, {another: "context"}),
473
- ]);
474
-
475
- // Assert
476
- await expect(result).rejects.toThrowError();
477
- });
478
- });
479
- });
@@ -1,97 +0,0 @@
1
- import {GqlOperation} from "@khanacademy/wonder-blocks-data";
2
- import {RespondWith} from "@khanacademy/wonder-blocks-testing-core";
3
- import type {GqlFetchMockFn} from "../types";
4
-
5
- type SomeGqlData = {
6
- a: string;
7
- b: number;
8
- };
9
-
10
- type SomeGqlVariables = {
11
- a: string;
12
- b: number;
13
- };
14
-
15
- const fakeOperation: GqlOperation<SomeGqlData, SomeGqlVariables> = {} as any;
16
-
17
- const mockFetch: GqlFetchMockFn = (() => {}) as any;
18
-
19
- // should be ok, no variables
20
- mockFetch.mockOperation(
21
- {
22
- operation: fakeOperation,
23
- },
24
- RespondWith.graphQLData({
25
- a: "string",
26
- b: 42,
27
- }),
28
- );
29
-
30
- // should be ok, with variables
31
- mockFetch.mockOperation(
32
- {
33
- operation: fakeOperation,
34
- variables: {
35
- a: "string",
36
- b: 42,
37
- },
38
- },
39
- RespondWith.graphQLData({
40
- a: "string",
41
- b: 42,
42
- }),
43
- );
44
-
45
- // should error; incorrect variable values and keys
46
- mockFetch.mockOperation(
47
- {
48
- operation: fakeOperation,
49
- variables: {
50
- // @ts-expect-error Type 'number' is not assignable to type 'string'
51
- a: 42,
52
- // @ts-expect-error Type 'string' is not assignable to type 'number'
53
- b: "not a number",
54
- },
55
- },
56
- RespondWith.graphQLData({
57
- a: "string",
58
- b: 42,
59
- }),
60
- );
61
-
62
- // should error; incorrect variable keys
63
- mockFetch.mockOperation(
64
- {
65
- operation: fakeOperation,
66
- variables: {
67
- // @ts-expect-error Type '{ notAValidKey: number; }' is not assignable to type 'SomeGqlVariables'.
68
- // Object literal may only specify known properties, and 'notAValidKey' does not exist in type 'SomeGqlVariables'.
69
- notAValidKey: 42,
70
- },
71
- },
72
- RespondWith.graphQLData({
73
- a: "string",
74
- b: 42,
75
- }),
76
- );
77
-
78
- // should error; wrong mock response type
79
- mockFetch.mockOperation(
80
- {
81
- operation: fakeOperation,
82
- },
83
- // @ts-expect-error Argument of type 'MockResponse<string>' is not assignable to parameter of type 'MockResponse<GraphQLJson<SomeGqlData>>'.
84
- RespondWith.text("Hello, I'm not a GraphQL response at all!"),
85
- );
86
-
87
- // should error; invalid graphQL data
88
- mockFetch.mockOperation(
89
- {
90
- operation: fakeOperation,
91
- },
92
- // @ts-expect-error Argument of type 'MockResponse<GraphQLJson<{ a: number; b: string; }>>' is not assignable to parameter of type 'MockResponse<GraphQLJson<SomeGqlData>>'.
93
- RespondWith.graphQLData({
94
- a: 42,
95
- b: "string",
96
- }),
97
- );