@khanacademy/wonder-blocks-data 13.0.11 → 13.0.12

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.
Files changed (66) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/package.json +3 -3
  3. package/src/components/__tests__/data.test.tsx +0 -832
  4. package/src/components/__tests__/gql-router.test.tsx +0 -63
  5. package/src/components/__tests__/intercept-requests.test.tsx +0 -57
  6. package/src/components/__tests__/track-data.test.tsx +0 -56
  7. package/src/components/data.ts +0 -73
  8. package/src/components/gql-router.tsx +0 -63
  9. package/src/components/intercept-context.ts +0 -19
  10. package/src/components/intercept-requests.tsx +0 -67
  11. package/src/components/track-data.tsx +0 -28
  12. package/src/hooks/__tests__/__snapshots__/use-shared-cache.test.ts.snap +0 -17
  13. package/src/hooks/__tests__/use-cached-effect.test.tsx +0 -789
  14. package/src/hooks/__tests__/use-gql-router-context.test.tsx +0 -132
  15. package/src/hooks/__tests__/use-gql.test.tsx +0 -204
  16. package/src/hooks/__tests__/use-hydratable-effect.test.ts +0 -708
  17. package/src/hooks/__tests__/use-request-interception.test.tsx +0 -254
  18. package/src/hooks/__tests__/use-server-effect.test.ts +0 -293
  19. package/src/hooks/__tests__/use-shared-cache.test.ts +0 -263
  20. package/src/hooks/use-cached-effect.ts +0 -297
  21. package/src/hooks/use-gql-router-context.ts +0 -49
  22. package/src/hooks/use-gql.ts +0 -58
  23. package/src/hooks/use-hydratable-effect.ts +0 -201
  24. package/src/hooks/use-request-interception.ts +0 -53
  25. package/src/hooks/use-server-effect.ts +0 -75
  26. package/src/hooks/use-shared-cache.ts +0 -107
  27. package/src/index.ts +0 -46
  28. package/src/util/__tests__/__snapshots__/scoped-in-memory-cache.test.ts.snap +0 -19
  29. package/src/util/__tests__/__snapshots__/serializable-in-memory-cache.test.ts.snap +0 -19
  30. package/src/util/__tests__/get-gql-data-from-response.test.ts +0 -186
  31. package/src/util/__tests__/get-gql-request-id.test.ts +0 -132
  32. package/src/util/__tests__/graphql-document-node-parser.test.ts +0 -535
  33. package/src/util/__tests__/hydration-cache-api.test.ts +0 -34
  34. package/src/util/__tests__/merge-gql-context.test.ts +0 -73
  35. package/src/util/__tests__/purge-caches.test.ts +0 -28
  36. package/src/util/__tests__/request-api.test.ts +0 -176
  37. package/src/util/__tests__/request-fulfillment.test.ts +0 -146
  38. package/src/util/__tests__/request-tracking.test.tsx +0 -321
  39. package/src/util/__tests__/result-from-cache-response.test.ts +0 -79
  40. package/src/util/__tests__/scoped-in-memory-cache.test.ts +0 -316
  41. package/src/util/__tests__/serializable-in-memory-cache.test.ts +0 -397
  42. package/src/util/__tests__/ssr-cache.test.ts +0 -636
  43. package/src/util/__tests__/to-gql-operation.test.ts +0 -41
  44. package/src/util/data-error.ts +0 -63
  45. package/src/util/get-gql-data-from-response.ts +0 -65
  46. package/src/util/get-gql-request-id.ts +0 -106
  47. package/src/util/gql-error.ts +0 -43
  48. package/src/util/gql-router-context.ts +0 -9
  49. package/src/util/gql-types.ts +0 -64
  50. package/src/util/graphql-document-node-parser.ts +0 -132
  51. package/src/util/graphql-types.ts +0 -28
  52. package/src/util/hydration-cache-api.ts +0 -30
  53. package/src/util/merge-gql-context.ts +0 -35
  54. package/src/util/purge-caches.ts +0 -14
  55. package/src/util/request-api.ts +0 -65
  56. package/src/util/request-fulfillment.ts +0 -121
  57. package/src/util/request-tracking.ts +0 -211
  58. package/src/util/result-from-cache-response.ts +0 -30
  59. package/src/util/scoped-in-memory-cache.ts +0 -121
  60. package/src/util/serializable-in-memory-cache.ts +0 -44
  61. package/src/util/ssr-cache.ts +0 -193
  62. package/src/util/status.ts +0 -35
  63. package/src/util/to-gql-operation.ts +0 -43
  64. package/src/util/types.ts +0 -145
  65. package/tsconfig-build.json +0 -12
  66. package/tsconfig-build.tsbuildinfo +0 -1
@@ -1,832 +0,0 @@
1
- /* eslint-disable max-lines */
2
- import * as React from "react";
3
- import {render, act} from "@testing-library/react";
4
-
5
- // eslint-disable-next-line import/extensions
6
- import * as ReactDOMServer from "react-dom/server";
7
- import {Server, View} from "@khanacademy/wonder-blocks-core";
8
-
9
- import {SharedCache} from "../../hooks/use-shared-cache";
10
- import TrackData from "../track-data";
11
- import {RequestFulfillment} from "../../util/request-fulfillment";
12
- import {SsrCache} from "../../util/ssr-cache";
13
- import {RequestTracker} from "../../util/request-tracking";
14
- import InterceptRequests from "../intercept-requests";
15
- import Data from "../data";
16
- import {WhenClientSide} from "../../hooks/use-hydratable-effect";
17
-
18
- describe("Data", () => {
19
- beforeEach(() => {
20
- SharedCache.purgeAll();
21
-
22
- const responseCache = new SsrCache();
23
- jest.spyOn(SsrCache, "Default", "get").mockReturnValue(responseCache);
24
- jest.spyOn(RequestFulfillment, "Default", "get").mockReturnValue(
25
- new RequestFulfillment(),
26
- );
27
- jest.spyOn(RequestTracker, "Default", "get").mockReturnValue(
28
- new RequestTracker(responseCache),
29
- );
30
- });
31
-
32
- describe("CSR: isServerSide false", () => {
33
- beforeEach(() => {
34
- jest.spyOn(Server, "isServerSide").mockReturnValue(false);
35
- });
36
-
37
- describe("without hydrated data", () => {
38
- beforeEach(() => {
39
- /**
40
- * Each of these test cases will not have cached data to be
41
- * retrieved in the beginning.
42
- */
43
- jest.spyOn(SsrCache.Default, "getEntry").mockReturnValueOnce(
44
- null,
45
- );
46
- });
47
-
48
- it("should make request for data on construction", async () => {
49
- // Arrange
50
- const response: any = Promise.resolve("data");
51
- const fakeHandler = jest.fn().mockReturnValue(response);
52
- const fakeChildrenFn = jest.fn(() => null);
53
-
54
- // Act
55
- render(
56
- <Data handler={fakeHandler} requestId="ID">
57
- {fakeChildrenFn}
58
- </Data>,
59
- );
60
- await act(() => response);
61
-
62
- // Assert
63
- expect(fakeHandler).toHaveBeenCalledTimes(1);
64
- });
65
-
66
- it("should initially render children with loading", async () => {
67
- // Arrange
68
- const response: any = Promise.resolve("data");
69
- const fakeHandler = jest.fn().mockReturnValue(response);
70
- const fakeChildrenFn = jest.fn(() => null);
71
-
72
- // Act
73
- render(
74
- <Data handler={fakeHandler} requestId="ID">
75
- {fakeChildrenFn}
76
- </Data>,
77
- );
78
- await act(() => response);
79
-
80
- // Assert
81
- expect(fakeChildrenFn).toHaveBeenCalledWith({
82
- status: "loading",
83
- });
84
- });
85
-
86
- it("should share single request across all uses", () => {
87
- // Arrange
88
- const fakeHandler = jest.fn(
89
- () => new Promise((resolve: any, reject: any) => {}),
90
- ) as jest.Mock<Promise<any>>;
91
- const fakeChildrenFn = jest.fn(() => null);
92
-
93
- // Act
94
- render(
95
- <View>
96
- <Data handler={fakeHandler} requestId="ID">
97
- {fakeChildrenFn}
98
- </Data>
99
- <Data handler={fakeHandler} requestId="ID">
100
- {fakeChildrenFn}
101
- </Data>
102
- </View>,
103
- );
104
-
105
- // Assert
106
- expect(fakeHandler).toHaveBeenCalledTimes(1);
107
- });
108
-
109
- it("should render with an error if the handler request rejects to an error", async () => {
110
- // Arrange
111
- const fulfillSpy = jest.spyOn(
112
- RequestFulfillment.Default,
113
- "fulfill",
114
- );
115
- const fakeHandler = () => Promise.reject(new Error("OH NOES!"));
116
- const fakeChildrenFn = jest.fn(() => null);
117
-
118
- // Act
119
- render(
120
- <Data handler={fakeHandler} requestId="ID">
121
- {fakeChildrenFn}
122
- </Data>,
123
- );
124
-
125
- /**
126
- * We wait for the fulfillment to resolve.
127
- */
128
- await act(() =>
129
- fulfillSpy.mock.results[0].value.catch(() => {
130
- /* do nothing */
131
- }),
132
- );
133
-
134
- // Assert
135
- expect(fakeChildrenFn).toHaveBeenNthCalledWith(2, {
136
- status: "error",
137
- error: expect.any(Error),
138
- });
139
- expect(fakeChildrenFn).toHaveBeenCalledTimes(2);
140
- });
141
-
142
- it("should render with data if the handler resolves with data", async () => {
143
- // Arrange
144
- const fulfillSpy = jest.spyOn(
145
- RequestFulfillment.Default,
146
- "fulfill",
147
- );
148
-
149
- const fakeHandler = () => Promise.resolve("YAY! DATA!");
150
- const fakeChildrenFn = jest.fn(() => null);
151
-
152
- // Act
153
- render(
154
- <Data handler={fakeHandler} requestId="ID">
155
- {fakeChildrenFn}
156
- </Data>,
157
- );
158
- /**
159
- * We wait for the fulfillment to resolve.
160
- */
161
- await act(() => fulfillSpy.mock.results[0].value);
162
-
163
- // Assert
164
- expect(fakeChildrenFn).toHaveBeenCalledTimes(2);
165
- expect(fakeChildrenFn).toHaveBeenLastCalledWith({
166
- status: "success",
167
- data: "YAY! DATA!",
168
- });
169
- });
170
-
171
- it("should render with aborted if the request rejects with an abort error", async () => {
172
- // Arrange
173
- const fulfillSpy = jest.spyOn(
174
- RequestFulfillment.Default,
175
- "fulfill",
176
- );
177
-
178
- const abortError = new Error("bang bang, abort!");
179
- abortError.name = "AbortError";
180
- const fakeHandler = () => Promise.reject(abortError);
181
- const fakeChildrenFn = jest.fn(() => null);
182
-
183
- // Act
184
- render(
185
- <Data handler={fakeHandler} requestId="ID">
186
- {fakeChildrenFn}
187
- </Data>,
188
- );
189
- /**
190
- * We wait for the fulfillment to resolve.
191
- */
192
- await act(() => fulfillSpy.mock.results[0].value);
193
-
194
- // Assert
195
- expect(fakeChildrenFn).toHaveBeenCalledTimes(2);
196
- expect(fakeChildrenFn).toHaveBeenLastCalledWith({
197
- status: "aborted",
198
- });
199
- });
200
-
201
- it("should render with an error if the RequestFulfillment rejects with an error", async () => {
202
- // Arrange
203
- const fulfillSpy = jest
204
- .spyOn(RequestFulfillment.Default, "fulfill")
205
- .mockResolvedValue({
206
- status: "error",
207
- error: new Error("CATASTROPHE!"),
208
- });
209
-
210
- const fakeHandler = () => Promise.resolve("YAY!");
211
- const fakeChildrenFn = jest.fn(() => null);
212
-
213
- // Act
214
- render(
215
- <Data handler={fakeHandler} requestId="ID">
216
- {fakeChildrenFn}
217
- </Data>,
218
- );
219
- /**
220
- * We wait for the fulfillment to reject.
221
- */
222
- await act(() =>
223
- fulfillSpy.mock.results[0].value.catch(() => {}),
224
- );
225
-
226
- // Assert
227
- expect(fakeChildrenFn).toHaveBeenCalledTimes(2);
228
- expect(fakeChildrenFn).toHaveBeenLastCalledWith({
229
- status: "error",
230
- error: expect.any(Error),
231
- });
232
- });
233
-
234
- it("should start loading if the id changes and request not cached", async () => {
235
- // Arrange
236
- const fulfillSpy = jest.spyOn(
237
- RequestFulfillment.Default,
238
- "fulfill",
239
- );
240
-
241
- const fakeHandler = () => Promise.resolve("HELLO!");
242
- const fakeChildrenFn = jest.fn(() => null);
243
- const wrapper = render(
244
- <Data handler={fakeHandler} requestId="ID">
245
- {fakeChildrenFn}
246
- </Data>,
247
- );
248
- // We want to make sure we render the data state so we can
249
- // see our switch back to loading.
250
- await act(() => fulfillSpy.mock.results[0].value);
251
- fulfillSpy.mockClear();
252
- fakeChildrenFn.mockClear();
253
-
254
- // Act
255
- wrapper.rerender(
256
- <Data handler={fakeHandler} requestId="NEW_ID">
257
- {fakeChildrenFn}
258
- </Data>,
259
- );
260
-
261
- // Assert
262
- expect(fakeChildrenFn).toHaveBeenCalledTimes(1);
263
- expect(fakeChildrenFn).toHaveBeenLastCalledWith({
264
- status: "loading",
265
- });
266
-
267
- // We have to do this or testing-library gets very upset.
268
- await act(() => fulfillSpy.mock.results[0].value);
269
- });
270
-
271
- it("should ignore resolution of pending handler fulfillment when id changes", async () => {
272
- // Arrange
273
- const oldRequest: any = Promise.resolve("OLD DATA");
274
- const oldHandler = jest
275
- .fn()
276
- .mockReturnValueOnce(oldRequest)
277
- .mockReturnValue(
278
- new Promise(() => {
279
- /*let's have the new request remain pending*/
280
- }),
281
- );
282
-
283
- // Act
284
- const fakeChildrenFn = jest.fn(() => null);
285
- const wrapper = render(
286
- <Data handler={oldHandler} requestId="ID">
287
- {fakeChildrenFn}
288
- </Data>,
289
- );
290
- wrapper.rerender(
291
- <Data handler={oldHandler} requestId="NEW_ID">
292
- {fakeChildrenFn}
293
- </Data>,
294
- );
295
- await act(() => oldRequest);
296
-
297
- // Assert
298
- expect(fakeChildrenFn).not.toHaveBeenCalledWith({
299
- status: "success",
300
- data: "OLD DATA",
301
- });
302
- });
303
-
304
- it("should ignore rejection of pending handler fulfillment when id changes", async () => {
305
- // Arrange
306
- const oldRequest = Promise.reject(new Error("BOOM!"));
307
- const oldHandler = jest
308
- .fn()
309
- .mockReturnValueOnce(oldRequest)
310
- .mockReturnValue(
311
- new Promise(() => {
312
- /*let's have the new request remain pending*/
313
- }),
314
- );
315
-
316
- // Act
317
- const fakeChildrenFn = jest.fn(() => null);
318
- const wrapper = render(
319
- <Data handler={oldHandler} requestId="ID">
320
- {fakeChildrenFn}
321
- </Data>,
322
- );
323
- wrapper.rerender(
324
- <Data handler={oldHandler} requestId="NEW_ID">
325
- {fakeChildrenFn}
326
- </Data>,
327
- );
328
- await act(() =>
329
- oldRequest.catch(() => {
330
- /*ignore*/
331
- }),
332
- );
333
-
334
- // Assert
335
- expect(fakeChildrenFn).not.toHaveBeenCalledWith({
336
- status: "error",
337
- error: "BOOM!",
338
- });
339
- });
340
-
341
- it("should ignore catastrophic request fulfillment when id changes", async () => {
342
- // Arrange
343
- const catastrophe: any = Promise.resolve({
344
- status: "error",
345
- error: new Error("CATASTROPHE!"),
346
- });
347
- jest.spyOn(
348
- RequestFulfillment.Default,
349
- "fulfill",
350
- ).mockReturnValueOnce(catastrophe);
351
- const oldHandler = jest.fn().mockResolvedValue("OLD DATA");
352
-
353
- // Act
354
- const fakeChildrenFn = jest.fn(() => null);
355
- const wrapper = render(
356
- <Data handler={oldHandler} requestId="ID">
357
- {fakeChildrenFn}
358
- </Data>,
359
- );
360
- wrapper.rerender(
361
- <Data handler={oldHandler} requestId="NEW_ID">
362
- {fakeChildrenFn}
363
- </Data>,
364
- );
365
- await act(() =>
366
- catastrophe.catch(() => {
367
- /* ignore */
368
- }),
369
- );
370
-
371
- // Assert
372
- expect(fakeChildrenFn).not.toHaveBeenCalledWith({
373
- status: "error",
374
- error: expect.any(Error),
375
- });
376
- });
377
-
378
- describe("with data interceptor", () => {
379
- it("should request data from interceptor", async () => {
380
- // Arrange
381
- const fakeHandler = jest.fn().mockResolvedValue("data");
382
- const fakeChildrenFn = jest.fn(() => null);
383
- const interceptHandler = jest
384
- .fn()
385
- .mockResolvedValue("INTERCEPTED DATA");
386
-
387
- // Act
388
- render(
389
- <InterceptRequests interceptor={interceptHandler}>
390
- <Data handler={fakeHandler} requestId="ID">
391
- {fakeChildrenFn}
392
- </Data>
393
- </InterceptRequests>,
394
- );
395
- await act(() => interceptHandler.mock.results[0].value);
396
-
397
- // Assert
398
- expect(interceptHandler).toHaveBeenCalledTimes(1);
399
- expect(fakeHandler).not.toHaveBeenCalled();
400
- });
401
-
402
- it("should invoke handler method if interceptor method returns null", async () => {
403
- // Arrange
404
- const fakeHandler = jest.fn().mockResolvedValue("data");
405
- const fakeChildrenFn = jest.fn(() => null);
406
- const interceptHandler = jest.fn(() => null);
407
-
408
- // Act
409
- render(
410
- <InterceptRequests interceptor={interceptHandler}>
411
- <Data handler={fakeHandler} requestId="ID">
412
- {fakeChildrenFn}
413
- </Data>
414
- </InterceptRequests>,
415
- );
416
- await act(() => fakeHandler.mock.results[0].value);
417
-
418
- // Assert
419
- expect(interceptHandler).toHaveBeenCalledTimes(1);
420
- expect(fakeHandler).toHaveBeenCalledTimes(1);
421
- });
422
- });
423
-
424
- it("should retain old data while reloading if retainResultOnChange is true", async () => {
425
- // Arrange
426
- const response1: any = Promise.resolve("data1");
427
- const response2: any = Promise.resolve("data2");
428
- const fakeHandler1 = () => response1;
429
- const fakeHandler2 = () => response2;
430
- const fakeChildrenFn = jest.fn(() => null);
431
-
432
- // Act
433
- const wrapper = render(
434
- <Data
435
- handler={fakeHandler1}
436
- requestId="ID1"
437
- retainResultOnChange={true}
438
- >
439
- {fakeChildrenFn}
440
- </Data>,
441
- );
442
- fakeChildrenFn.mockClear();
443
- await act(() => response1);
444
- wrapper.rerender(
445
- <Data
446
- handler={fakeHandler2}
447
- requestId="ID2"
448
- retainResultOnChange={true}
449
- >
450
- {fakeChildrenFn}
451
- </Data>,
452
- );
453
- await act(() => response2);
454
-
455
- // Assert
456
- expect(fakeChildrenFn).not.toHaveBeenCalledWith({
457
- status: "loading",
458
- });
459
- expect(fakeChildrenFn).toHaveBeenCalledWith({
460
- status: "success",
461
- data: "data1",
462
- });
463
- expect(fakeChildrenFn).toHaveBeenLastCalledWith({
464
- status: "success",
465
- data: "data2",
466
- });
467
- });
468
- });
469
-
470
- describe("with hydrated data", () => {
471
- beforeEach(() => {
472
- /**
473
- * Each of these test cases will start out with some cached data
474
- * retrieved.
475
- */
476
- jest.spyOn(
477
- SsrCache.Default,
478
- "getEntry",
479
- // Fake once because that's how the cache would work,
480
- // deleting the hydrated value as soon as it was used.
481
- ).mockReturnValueOnce({
482
- data: "YAY! DATA!",
483
- });
484
- });
485
-
486
- it("should render first time with the cached data", () => {
487
- // Arrange
488
- const fakeHandler = () => Promise.resolve("data");
489
- const fakeChildrenFn = jest.fn(() => null);
490
-
491
- // Act
492
- render(
493
- <Data handler={fakeHandler} requestId="ID">
494
- {fakeChildrenFn}
495
- </Data>,
496
- );
497
-
498
- // Assert
499
- expect(fakeChildrenFn).toHaveBeenCalledWith({
500
- status: "success",
501
- data: "YAY! DATA!",
502
- });
503
- });
504
-
505
- it("should not request data when clientBehavior is WhenClientSide.ExecuteWhenNoSuccessResult and cache has a valid success result", () => {
506
- // Arrange
507
- const fakeHandler = jest.fn().mockResolvedValue("data");
508
- const fakeChildrenFn = jest.fn(() => null);
509
-
510
- // Act
511
- render(
512
- <Data
513
- handler={fakeHandler}
514
- requestId="ID"
515
- clientBehavior={
516
- WhenClientSide.ExecuteWhenNoSuccessResult
517
- }
518
- >
519
- {fakeChildrenFn}
520
- </Data>,
521
- );
522
-
523
- // Assert
524
- expect(fakeHandler).not.toHaveBeenCalled();
525
- });
526
-
527
- it("should request data if cached data value is valid but clientBehavior is WhenClientSide.AlwaysExecute is true", async () => {
528
- // Arrange
529
- const fakeHandler = jest.fn().mockResolvedValue("data");
530
- const fakeChildrenFn = jest.fn(() => null);
531
-
532
- // Act
533
- render(
534
- <Data
535
- handler={fakeHandler}
536
- requestId="ID"
537
- clientBehavior={WhenClientSide.AlwaysExecute}
538
- >
539
- {fakeChildrenFn}
540
- </Data>,
541
- );
542
- await act(() => fakeHandler.mock.results[0].value);
543
-
544
- // Assert
545
- expect(fakeHandler).toHaveBeenCalledTimes(1);
546
- });
547
- });
548
-
549
- describe("with cached error", () => {
550
- beforeEach(() => {
551
- /**
552
- * Each of these test cases will start out with a cached error.
553
- */
554
- jest.spyOn(
555
- SsrCache.Default,
556
- "getEntry",
557
- // Fake once because that's how the cache would work,
558
- // deleting the hydrated value as soon as it was used.
559
- ).mockReturnValueOnce({
560
- error: "BOO! ERROR!",
561
- });
562
- });
563
-
564
- it("should always request data if there's a cached error", async () => {
565
- // Arrange
566
- const fakeHandler = jest.fn().mockResolvedValue("data");
567
- const fakeChildrenFn = jest.fn(() => null);
568
-
569
- // Act
570
- render(
571
- <Data handler={fakeHandler} requestId="ID">
572
- {fakeChildrenFn}
573
- </Data>,
574
- );
575
- // Have to await the promise in an act to keep TL/R happy.
576
- await act(() => fakeHandler.mock.results[0].value);
577
-
578
- // Assert
579
- expect(fakeHandler).toHaveBeenCalledTimes(1);
580
- });
581
- });
582
- });
583
-
584
- describe("SSR: isServerSide true", () => {
585
- beforeEach(() => {
586
- jest.spyOn(Server, "isServerSide").mockReturnValue(true);
587
- });
588
-
589
- describe("without cached data", () => {
590
- beforeEach(() => {
591
- /**
592
- * Each of these test cases will never have cached data
593
- * retrieved.
594
- */
595
- jest.spyOn(SsrCache.Default, "getEntry").mockReturnValue(null);
596
- });
597
-
598
- it("should not request data", () => {
599
- // Arrange
600
- const fakeHandler = jest.fn().mockResolvedValue("data");
601
- const fakeChildrenFn = jest.fn(() => null);
602
-
603
- // Act
604
- ReactDOMServer.renderToString(
605
- <Data handler={fakeHandler} requestId="ID">
606
- {fakeChildrenFn}
607
- </Data>,
608
- );
609
-
610
- // Assert
611
- expect(fakeHandler).not.toHaveBeenCalled();
612
- });
613
-
614
- it("should render children with loading", () => {
615
- // Arrange
616
- const fakeHandler = jest.fn().mockResolvedValue("data");
617
- const fakeChildrenFn = jest.fn(() => null);
618
-
619
- // Act
620
- ReactDOMServer.renderToString(
621
- <Data handler={fakeHandler} requestId="ID">
622
- {fakeChildrenFn}
623
- </Data>,
624
- );
625
-
626
- // Assert
627
- expect(fakeChildrenFn).toHaveBeenCalledWith({
628
- status: "loading",
629
- });
630
- });
631
-
632
- it("should invoke the tracking call", () => {
633
- // Arrange
634
- const trackSpy = jest.spyOn(
635
- RequestTracker.Default,
636
- "trackDataRequest",
637
- );
638
- const fakeHandler = jest.fn().mockResolvedValue("data");
639
- const fakeChildrenFn = jest.fn(() => null);
640
-
641
- // Act
642
- ReactDOMServer.renderToString(
643
- <TrackData>
644
- <Data handler={fakeHandler} requestId="ID">
645
- {fakeChildrenFn}
646
- </Data>
647
- </TrackData>,
648
- );
649
-
650
- // Assert
651
- expect(trackSpy).toHaveBeenCalledWith(
652
- "ID",
653
- expect.any(Function),
654
- true,
655
- );
656
- });
657
-
658
- describe("with data interceptor", () => {
659
- it("should not request data from the interceptor", () => {
660
- // Arrange
661
- const fakeHandler = jest.fn().mockResolvedValue("data");
662
- const fakeChildrenFn = jest.fn(() => null);
663
- const interceptedHandler = jest.fn(() =>
664
- Promise.resolve("DATA!"),
665
- );
666
-
667
- // Act
668
- ReactDOMServer.renderToString(
669
- <InterceptRequests interceptor={interceptedHandler}>
670
- <Data handler={fakeHandler} requestId="ID">
671
- {fakeChildrenFn}
672
- </Data>
673
- </InterceptRequests>,
674
- );
675
-
676
- // Assert
677
- expect(fakeHandler).not.toHaveBeenCalled();
678
- expect(interceptedHandler).not.toHaveBeenCalled();
679
- });
680
-
681
- it("should invoke the tracking call", () => {
682
- // Arrange
683
- const trackSpy = jest.spyOn(
684
- RequestTracker.Default,
685
- "trackDataRequest",
686
- );
687
- const fakeHandler = jest.fn().mockResolvedValue("data");
688
- const fakeChildrenFn = jest.fn(() => null);
689
- const interceptedHandler = jest
690
- .fn()
691
- .mockResolvedValue("INTERCEPTED");
692
-
693
- // Act
694
- ReactDOMServer.renderToString(
695
- <TrackData>
696
- <InterceptRequests interceptor={interceptedHandler}>
697
- <Data handler={fakeHandler} requestId="ID">
698
- {fakeChildrenFn}
699
- </Data>
700
- </InterceptRequests>
701
- </TrackData>,
702
- );
703
-
704
- // Assert
705
- expect(trackSpy).toHaveBeenCalledWith(
706
- "ID",
707
- expect.any(Function),
708
- true,
709
- );
710
- });
711
- });
712
- });
713
-
714
- describe("with cached data", () => {
715
- beforeEach(() => {
716
- /**
717
- * Each of these test cases will start out with some cached data
718
- * retrieved.
719
- */
720
- jest.spyOn(SsrCache.Default, "getEntry").mockReturnValue({
721
- data: "YAY! DATA!",
722
- });
723
- });
724
-
725
- it("should not request data", () => {
726
- // Arrange
727
- const fakeHandler = jest.fn().mockResolvedValue("data");
728
- const fakeChildrenFn = jest.fn(() => null);
729
-
730
- // Act
731
- ReactDOMServer.renderToString(
732
- <Data handler={fakeHandler} requestId="ID">
733
- {fakeChildrenFn}
734
- </Data>,
735
- );
736
-
737
- // Assert
738
- expect(fakeHandler).not.toHaveBeenCalled();
739
- });
740
-
741
- it("should render children with data", () => {
742
- // Arrange
743
- const fakeHandler = jest.fn().mockResolvedValue("data");
744
- const fakeChildrenFn = jest.fn(() => null);
745
-
746
- // Act
747
- ReactDOMServer.renderToString(
748
- <Data handler={fakeHandler} requestId="ID">
749
- {fakeChildrenFn}
750
- </Data>,
751
- );
752
-
753
- // Assert
754
- expect(fakeChildrenFn).toHaveBeenCalledWith({
755
- status: "success",
756
- data: "YAY! DATA!",
757
- });
758
- });
759
-
760
- it("should render children with error", () => {
761
- // Arrange
762
- jest.spyOn(SsrCache.Default, "getEntry").mockReturnValue({
763
- error: "OH NO! IT GO BOOM",
764
- });
765
- const fakeHandler = jest.fn().mockResolvedValue("data");
766
- const fakeChildrenFn = jest.fn(() => null);
767
-
768
- // Act
769
- ReactDOMServer.renderToString(
770
- <Data handler={fakeHandler} requestId="ID">
771
- {fakeChildrenFn}
772
- </Data>,
773
- );
774
-
775
- // Assert
776
- expect(fakeChildrenFn).toHaveBeenCalledWith({
777
- status: "error",
778
- error: expect.any(Error),
779
- });
780
- });
781
-
782
- it("should not invoke the tracking call", () => {
783
- // Arrange
784
- const trackSpy = jest.spyOn(
785
- RequestTracker.Default,
786
- "trackDataRequest",
787
- );
788
- const fakeHandler = jest.fn().mockResolvedValue("data");
789
- const fakeChildrenFn = jest.fn(() => null);
790
-
791
- // Act
792
- ReactDOMServer.renderToString(
793
- <TrackData>
794
- <Data handler={fakeHandler} requestId="ID">
795
- {fakeChildrenFn}
796
- </Data>
797
- </TrackData>,
798
- );
799
-
800
- // Assert
801
- expect(trackSpy).not.toHaveBeenCalledWith(
802
- fakeHandler,
803
- "options",
804
- );
805
- });
806
-
807
- describe("with data interceptor", () => {
808
- it("should not request data from interceptor", () => {
809
- // Arrange
810
- const fakeHandler = jest.fn().mockResolvedValue("data");
811
- const fakeChildrenFn = jest.fn(() => null);
812
- const interceptHandler = jest
813
- .fn()
814
- .mockResolvedValue("INTERCEPTED");
815
-
816
- // Act
817
- ReactDOMServer.renderToString(
818
- <InterceptRequests interceptor={interceptHandler}>
819
- <Data handler={fakeHandler} requestId="ID">
820
- {fakeChildrenFn}
821
- </Data>
822
- </InterceptRequests>,
823
- );
824
-
825
- // Assert
826
- expect(fakeHandler).not.toHaveBeenCalled();
827
- expect(interceptHandler).not.toHaveBeenCalled();
828
- });
829
- });
830
- });
831
- });
832
- });