@khanacademy/wonder-blocks-data 3.1.2 → 5.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.
Files changed (51) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/es/index.js +408 -349
  3. package/dist/index.js +568 -467
  4. package/docs.md +17 -35
  5. package/package.json +1 -1
  6. package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +7 -46
  7. package/src/__tests__/generated-snapshot.test.js +60 -126
  8. package/src/components/__tests__/data.test.js +373 -313
  9. package/src/components/__tests__/intercept-requests.test.js +58 -0
  10. package/src/components/data.js +139 -21
  11. package/src/components/data.md +38 -69
  12. package/src/components/gql-router.js +1 -1
  13. package/src/components/intercept-context.js +6 -3
  14. package/src/components/intercept-requests.js +69 -0
  15. package/src/components/intercept-requests.md +54 -0
  16. package/src/components/track-data.md +9 -23
  17. package/src/hooks/__tests__/__snapshots__/use-shared-cache.test.js.snap +17 -0
  18. package/src/hooks/__tests__/use-gql.test.js +1 -0
  19. package/src/hooks/__tests__/use-request-interception.test.js +255 -0
  20. package/src/hooks/__tests__/use-server-effect.test.js +217 -0
  21. package/src/hooks/__tests__/use-shared-cache.test.js +307 -0
  22. package/src/hooks/use-gql.js +39 -31
  23. package/src/hooks/use-request-interception.js +54 -0
  24. package/src/hooks/use-server-effect.js +45 -0
  25. package/src/hooks/use-shared-cache.js +106 -0
  26. package/src/index.js +17 -20
  27. package/src/util/__tests__/__snapshots__/scoped-in-memory-cache.test.js.snap +19 -0
  28. package/src/util/__tests__/request-fulfillment.test.js +42 -85
  29. package/src/util/__tests__/request-tracking.test.js +72 -191
  30. package/src/util/__tests__/{result-from-cache-entry.test.js → result-from-cache-response.test.js} +9 -10
  31. package/src/util/__tests__/scoped-in-memory-cache.test.js +396 -0
  32. package/src/util/__tests__/ssr-cache.test.js +639 -0
  33. package/src/util/gql-types.js +5 -10
  34. package/src/util/request-fulfillment.js +36 -44
  35. package/src/util/request-tracking.js +62 -75
  36. package/src/util/{result-from-cache-entry.js → result-from-cache-response.js} +10 -13
  37. package/src/util/scoped-in-memory-cache.js +149 -0
  38. package/src/util/ssr-cache.js +206 -0
  39. package/src/util/types.js +43 -108
  40. package/src/components/__tests__/intercept-data.test.js +0 -87
  41. package/src/components/intercept-data.js +0 -77
  42. package/src/components/intercept-data.md +0 -65
  43. package/src/hooks/__tests__/use-data.test.js +0 -826
  44. package/src/hooks/use-data.js +0 -143
  45. package/src/util/__tests__/memory-cache.test.js +0 -446
  46. package/src/util/__tests__/request-handler.test.js +0 -121
  47. package/src/util/__tests__/response-cache.test.js +0 -879
  48. package/src/util/memory-cache.js +0 -187
  49. package/src/util/request-handler.js +0 -42
  50. package/src/util/request-handler.md +0 -51
  51. package/src/util/response-cache.js +0 -213
@@ -1,879 +0,0 @@
1
- // @flow
2
- import {Server} from "@khanacademy/wonder-blocks-core";
3
- import {ResponseCache} from "../response-cache.js";
4
- import MemoryCache from "../memory-cache.js";
5
-
6
- import type {IRequestHandler} from "../types.js";
7
-
8
- describe("../response-cache.js", () => {
9
- afterEach(() => {
10
- /**
11
- * This is needed or the JSON.stringify mocks need to be
12
- * mockImplementationOnce. This is because if the snapshots need
13
- * to update, they write the inline snapshot and that appears to invoke
14
- * prettier which in turn, calls JSON.stringify. And if that mock
15
- * throws, then boom. No snapshot update and a big old confusing test
16
- * failure.
17
- */
18
- jest.restoreAllMocks();
19
- });
20
-
21
- describe("@Default", () => {
22
- it("should return an instance of ResponseCache", () => {
23
- // Arrange
24
-
25
- // Act
26
- const result = ResponseCache.Default;
27
-
28
- // Assert
29
- expect(result).toBeInstanceOf(ResponseCache);
30
- });
31
-
32
- it("should return the same instance on each call", () => {
33
- // Arrange
34
-
35
- // Act
36
- const result1 = ResponseCache.Default;
37
- const result2 = ResponseCache.Default;
38
-
39
- // Assert
40
- expect(result1).toBe(result2);
41
- });
42
- });
43
-
44
- describe("#initialize", () => {
45
- it("should initialize the cache with the given data", () => {
46
- // Arrange
47
- const cache = new ResponseCache();
48
- const fakeHandler: IRequestHandler<string, string> = {
49
- getKey: () => "MY_KEY",
50
- type: "MY_HANDLER",
51
- fulfillRequest: jest.fn(),
52
- hydrate: true,
53
- };
54
-
55
- // Act
56
- cache.initialize({
57
- MY_HANDLER: {
58
- MY_KEY: {data: "THE_DATA"},
59
- },
60
- });
61
- const result = cache.getEntry(fakeHandler, "options");
62
-
63
- // Assert
64
- expect(result).toStrictEqual({data: "THE_DATA"});
65
- });
66
-
67
- it("should throw if the cache is already intialized", () => {
68
- // Arrange
69
- const internalCache = new MemoryCache({
70
- MY_HANDLER: {
71
- MY_KEY: {data: "THE_DATA"},
72
- },
73
- });
74
- const cache = new ResponseCache(internalCache);
75
-
76
- // Act
77
- const underTest = () =>
78
- cache.initialize({
79
- MY_HANDLER: {
80
- MY_OTHER_KEY: {data: "MORE_DATA"},
81
- },
82
- });
83
-
84
- // Assert
85
- expect(underTest).toThrowErrorMatchingInlineSnapshot(
86
- `"Cannot initialize data response cache more than once"`,
87
- );
88
- });
89
-
90
- it("should throw if the data is invalid", () => {
91
- // Arrange
92
- jest.spyOn(JSON, "stringify").mockImplementation(() => {
93
- throw new Error("BANG!");
94
- });
95
- const internalCache = new MemoryCache();
96
- const cache = new ResponseCache(internalCache);
97
-
98
- // Act
99
- const underTest = () => cache.initialize({});
100
-
101
- // Assert
102
- expect(underTest).toThrowErrorMatchingInlineSnapshot(
103
- `"An error occurred trying to initialize the data response cache: Error: An error occurred trying to initialize from a response cache snapshot: Error: BANG!"`,
104
- );
105
- });
106
-
107
- it("should deep clone the cached data", () => {
108
- // Arrange
109
- const cache = new ResponseCache();
110
- const fakeHandler: IRequestHandler<string, string> = {
111
- getKey: () => "MY_KEY",
112
- type: "MY_HANDLER",
113
- fulfillRequest: jest.fn(),
114
- hydrate: true,
115
- };
116
- const sourceData = {
117
- MY_HANDLER: {
118
- MY_KEY: {data: "THE_DATA"},
119
- },
120
- };
121
-
122
- // Act
123
- cache.initialize(sourceData);
124
- // Try to mutate the cache.
125
- sourceData["MY_HANDLER"]["MY_KEY"] = {data: "SOME_NEW_DATA"};
126
- const result = cache.getEntry(fakeHandler, "options");
127
-
128
- // Assert
129
- expect(result).toStrictEqual({data: "THE_DATA"});
130
- });
131
- });
132
-
133
- describe("#cacheData", () => {
134
- describe("when client-side", () => {
135
- it("should not store the entry in the hydration cache", () => {
136
- // Arrange
137
- const hydrationCache = new MemoryCache();
138
- const cache = new ResponseCache(hydrationCache);
139
- const fakeHandler: IRequestHandler<string, string> = {
140
- getKey: () => "MY_KEY",
141
- type: "MY_HANDLER",
142
- fulfillRequest: jest.fn(),
143
- hydrate: true,
144
- };
145
- const hydrationStoreSpy = jest.spyOn(hydrationCache, "store");
146
-
147
- // Act
148
- cache.cacheData(fakeHandler, "options", "data");
149
-
150
- // Assert
151
- expect(hydrationStoreSpy).not.toHaveBeenCalled();
152
- });
153
-
154
- it("should not store the entry in the ssrOnly cache", () => {
155
- // Arrange
156
- const hydrationCache = new MemoryCache();
157
- const ssrOnlyCache = new MemoryCache();
158
- const cache = new ResponseCache(hydrationCache, ssrOnlyCache);
159
- const fakeHandler: IRequestHandler<string, string> = {
160
- getKey: () => "MY_KEY",
161
- type: "MY_HANDLER",
162
- fulfillRequest: jest.fn(),
163
- hydrate: true,
164
- };
165
- const ssrOnlyStoreSpy = jest.spyOn(ssrOnlyCache, "store");
166
-
167
- // Act
168
- cache.cacheData(fakeHandler, "options", "data");
169
-
170
- // Assert
171
- expect(ssrOnlyStoreSpy).not.toHaveBeenCalled();
172
- });
173
- });
174
-
175
- describe("when server-side", () => {
176
- beforeEach(() => {
177
- jest.spyOn(Server, "isServerSide").mockReturnValue(true);
178
- });
179
-
180
- describe("when the handler wants hydration", () => {
181
- it("should store the entry in the hydration cache", () => {
182
- // Arrange
183
- const hydrationCache = new MemoryCache();
184
- const cache = new ResponseCache(hydrationCache);
185
- const fakeHandler: IRequestHandler<string, string> = {
186
- getKey: () => "MY_KEY",
187
- type: "MY_HANDLER",
188
- fulfillRequest: jest.fn(),
189
- hydrate: true,
190
- };
191
- const hydrationStoreSpy = jest.spyOn(
192
- hydrationCache,
193
- "store",
194
- );
195
-
196
- // Act
197
- cache.cacheData(fakeHandler, "options", "data");
198
-
199
- // Assert
200
- expect(hydrationStoreSpy).toHaveBeenCalledWith(
201
- fakeHandler,
202
- "options",
203
- {data: "data"},
204
- );
205
- });
206
-
207
- it("should not store the entry in the ssrOnly cache", () => {
208
- // Arrange
209
- const hydrationCache = new MemoryCache();
210
- const ssrOnlyCache = new MemoryCache();
211
- const cache = new ResponseCache(
212
- hydrationCache,
213
- ssrOnlyCache,
214
- );
215
- const fakeHandler: IRequestHandler<string, string> = {
216
- getKey: () => "MY_KEY",
217
- type: "MY_HANDLER",
218
- fulfillRequest: jest.fn(),
219
- hydrate: true,
220
- };
221
- const ssrOnlyStoreSpy = jest.spyOn(ssrOnlyCache, "store");
222
-
223
- // Act
224
- cache.cacheData(fakeHandler, "options", "data");
225
-
226
- // Assert
227
- expect(ssrOnlyStoreSpy).not.toHaveBeenCalled();
228
- });
229
- });
230
-
231
- describe("when the handler does not hydration", () => {
232
- it("should store the entry in the ssr-only cache", () => {
233
- // Arrange
234
- const hydrationCache = new MemoryCache();
235
- const ssrOnlyCache = new MemoryCache();
236
- const cache = new ResponseCache(
237
- hydrationCache,
238
- ssrOnlyCache,
239
- );
240
- const fakeHandler: IRequestHandler<string, string> = {
241
- getKey: () => "MY_KEY",
242
- type: "MY_HANDLER",
243
- fulfillRequest: jest.fn(),
244
- hydrate: false,
245
- };
246
- const ssrOnlyStoreSpy = jest.spyOn(ssrOnlyCache, "store");
247
-
248
- // Act
249
- cache.cacheData(fakeHandler, "options", "data");
250
-
251
- // Assert
252
- expect(ssrOnlyStoreSpy).toHaveBeenCalledWith(
253
- fakeHandler,
254
- "options",
255
- {
256
- data: "data",
257
- },
258
- );
259
- });
260
-
261
- it("should not store the entry in the hydration cache", () => {
262
- // Arrange
263
- const hydrationCache = new MemoryCache();
264
- const ssrOnlyCache = new MemoryCache();
265
- const cache = new ResponseCache(
266
- hydrationCache,
267
- ssrOnlyCache,
268
- );
269
- const fakeHandler: IRequestHandler<string, string> = {
270
- getKey: () => "MY_KEY",
271
- type: "MY_HANDLER",
272
- fulfillRequest: jest.fn(),
273
- hydrate: false,
274
- };
275
- const hydrationStoreSpy = jest.spyOn(
276
- hydrationCache,
277
- "store",
278
- );
279
-
280
- // Act
281
- cache.cacheData(fakeHandler, "options", "data");
282
-
283
- // Assert
284
- expect(hydrationStoreSpy).not.toHaveBeenCalled();
285
- });
286
- });
287
- });
288
- });
289
-
290
- describe("#cacheError", () => {
291
- describe("when client-side", () => {
292
- it("should not store the entry in the hydration cache", () => {
293
- // Arrange
294
- const hydrationCache = new MemoryCache();
295
- const cache = new ResponseCache(hydrationCache);
296
- const fakeHandler: IRequestHandler<string, string> = {
297
- getKey: () => "MY_KEY",
298
- type: "MY_HANDLER",
299
- fulfillRequest: jest.fn(),
300
- hydrate: true,
301
- };
302
- const hydrationStoreSpy = jest.spyOn(hydrationCache, "store");
303
-
304
- // Act
305
- cache.cacheError(fakeHandler, "options", new Error("Ooops!"));
306
-
307
- // Assert
308
- expect(hydrationStoreSpy).not.toHaveBeenCalled();
309
- });
310
-
311
- it("should not store the entry in the ssrOnly cache", () => {
312
- // Arrange
313
- const hydrationCache = new MemoryCache();
314
- const ssrOnlyCache = new MemoryCache();
315
- const cache = new ResponseCache(hydrationCache, ssrOnlyCache);
316
- const fakeHandler: IRequestHandler<string, string> = {
317
- getKey: () => "MY_KEY",
318
- type: "MY_HANDLER",
319
- fulfillRequest: jest.fn(),
320
- hydrate: true,
321
- };
322
- const ssrOnlyStoreSpy = jest.spyOn(ssrOnlyCache, "store");
323
-
324
- // Act
325
- cache.cacheError(fakeHandler, "options", "Ooops!");
326
-
327
- // Assert
328
- expect(ssrOnlyStoreSpy).not.toHaveBeenCalled();
329
- });
330
- });
331
-
332
- describe("when server-side", () => {
333
- beforeEach(() => {
334
- jest.spyOn(Server, "isServerSide").mockReturnValue(true);
335
- });
336
-
337
- describe("when the handler wants hydration", () => {
338
- it("should store the entry in the hydration cache", () => {
339
- // Arrange
340
- const hydrationCache = new MemoryCache();
341
- const cache = new ResponseCache(hydrationCache);
342
- const fakeHandler: IRequestHandler<string, string> = {
343
- getKey: () => "MY_KEY",
344
- type: "MY_HANDLER",
345
- fulfillRequest: jest.fn(),
346
- hydrate: true,
347
- };
348
- const hydrationStoreSpy = jest.spyOn(
349
- hydrationCache,
350
- "store",
351
- );
352
-
353
- // Act
354
- cache.cacheError(
355
- fakeHandler,
356
- "options",
357
- new Error("Ooops!"),
358
- );
359
-
360
- // Assert
361
- expect(hydrationStoreSpy).toHaveBeenCalledWith(
362
- fakeHandler,
363
- "options",
364
- {error: "Ooops!"},
365
- );
366
- });
367
-
368
- it("should not store the entry in the ssrOnly cache", () => {
369
- // Arrange
370
- const hydrationCache = new MemoryCache();
371
- const ssrOnlyCache = new MemoryCache();
372
- const cache = new ResponseCache(
373
- hydrationCache,
374
- ssrOnlyCache,
375
- );
376
- const fakeHandler: IRequestHandler<string, string> = {
377
- getKey: () => "MY_KEY",
378
- type: "MY_HANDLER",
379
- fulfillRequest: jest.fn(),
380
- hydrate: true,
381
- };
382
- const ssrOnlyStoreSpy = jest.spyOn(ssrOnlyCache, "store");
383
-
384
- // Act
385
- cache.cacheError(
386
- fakeHandler,
387
- "options",
388
- new Error("Ooops!"),
389
- );
390
-
391
- // Assert
392
- expect(ssrOnlyStoreSpy).not.toHaveBeenCalled();
393
- });
394
- });
395
-
396
- describe("when the handler does not hydration", () => {
397
- it("should store the entry in the ssr-only cache", () => {
398
- // Arrange
399
- const hydrationCache = new MemoryCache();
400
- const ssrOnlyCache = new MemoryCache();
401
- const cache = new ResponseCache(
402
- hydrationCache,
403
- ssrOnlyCache,
404
- );
405
- const fakeHandler: IRequestHandler<string, string> = {
406
- getKey: () => "MY_KEY",
407
- type: "MY_HANDLER",
408
- fulfillRequest: jest.fn(),
409
- hydrate: false,
410
- };
411
- const ssrOnlyStoreSpy = jest.spyOn(ssrOnlyCache, "store");
412
-
413
- // Act
414
- cache.cacheError(
415
- fakeHandler,
416
- "options",
417
- new Error("Ooops!"),
418
- );
419
-
420
- // Assert
421
- expect(ssrOnlyStoreSpy).toHaveBeenCalledWith(
422
- fakeHandler,
423
- "options",
424
- {error: "Ooops!"},
425
- );
426
- });
427
-
428
- it("should not store the entry in the hydration cache", () => {
429
- // Arrange
430
- const hydrationCache = new MemoryCache();
431
- const ssrOnlyCache = new MemoryCache();
432
- const cache = new ResponseCache(
433
- hydrationCache,
434
- ssrOnlyCache,
435
- );
436
- const fakeHandler: IRequestHandler<string, string> = {
437
- getKey: () => "MY_KEY",
438
- type: "MY_HANDLER",
439
- fulfillRequest: jest.fn(),
440
- hydrate: false,
441
- };
442
- const hydrationStoreSpy = jest.spyOn(
443
- hydrationCache,
444
- "store",
445
- );
446
-
447
- // Act
448
- cache.cacheError(
449
- fakeHandler,
450
- "options",
451
- new Error("Ooops!"),
452
- );
453
-
454
- // Assert
455
- expect(hydrationStoreSpy).not.toHaveBeenCalled();
456
- });
457
- });
458
- });
459
- });
460
-
461
- describe("#getEntry", () => {
462
- describe("when client-side", () => {
463
- beforeEach(() => {
464
- jest.spyOn(Server, "isServerSide").mockReturnValue(false);
465
- });
466
-
467
- describe("handler wants hydration", () => {
468
- it("should return null if not in the hydration cache", () => {
469
- // Arrange
470
- const hydrationCache = new MemoryCache();
471
- jest.spyOn(hydrationCache, "retrieve").mockReturnValue(
472
- null,
473
- );
474
- const cache = new ResponseCache(hydrationCache);
475
- const fakeHandler: IRequestHandler<string, string> = {
476
- getKey: () => "MY_KEY",
477
- type: "MY_HANDLER",
478
- fulfillRequest: jest.fn(),
479
- hydrate: true,
480
- };
481
-
482
- // Act
483
- const result = cache.getEntry(fakeHandler, "options");
484
-
485
- // Assert
486
- expect(result).toBeNull();
487
- });
488
-
489
- it("should return the cached entry if in the hydration cache", () => {
490
- // Arrange
491
- const hydrationCache = new MemoryCache();
492
- jest.spyOn(hydrationCache, "retrieve").mockReturnValue({
493
- data: "data!",
494
- });
495
- const cache = new ResponseCache(hydrationCache);
496
- const fakeHandler: IRequestHandler<string, string> = {
497
- getKey: () => "MY_KEY",
498
- type: "MY_HANDLER",
499
- fulfillRequest: jest.fn(),
500
- hydrate: true,
501
- };
502
-
503
- // Act
504
- const result = cache.getEntry(fakeHandler, "options");
505
-
506
- // Assert
507
- expect(result).toStrictEqual({data: "data!"});
508
- });
509
- });
510
-
511
- describe("handler does not want hyrdation", () => {
512
- it("should return undefined", () => {
513
- // Arrange
514
- const hydrationCache = new MemoryCache();
515
- jest.spyOn(hydrationCache, "retrieve").mockReturnValue({
516
- data: "data!",
517
- });
518
- const cache = new ResponseCache(hydrationCache);
519
- const fakeHandler: IRequestHandler<string, string> = {
520
- getKey: () => "MY_KEY",
521
- type: "MY_HANDLER",
522
- fulfillRequest: jest.fn(),
523
- hydrate: false,
524
- };
525
-
526
- // Act
527
- const result = cache.getEntry(fakeHandler, "options");
528
-
529
- // Assert
530
- expect(result).toBeUndefined();
531
- });
532
- });
533
- });
534
-
535
- describe("when server-side", () => {
536
- beforeEach(() => {
537
- jest.spyOn(Server, "isServerSide").mockReturnValue(true);
538
- });
539
-
540
- describe("handler wants hydration", () => {
541
- it("should return null if not in the hydration cache", () => {
542
- // Arrange
543
- const hydrationCache = new MemoryCache();
544
- jest.spyOn(hydrationCache, "retrieve").mockReturnValue(
545
- null,
546
- );
547
- const cache = new ResponseCache(hydrationCache);
548
- const fakeHandler: IRequestHandler<string, string> = {
549
- getKey: () => "MY_KEY",
550
- type: "MY_HANDLER",
551
- fulfillRequest: jest.fn(),
552
- hydrate: true,
553
- };
554
-
555
- // Act
556
- const result = cache.getEntry(fakeHandler, "options");
557
-
558
- // Assert
559
- expect(result).toBeNull();
560
- });
561
-
562
- it("should return the cached entry if in the hydration cache", () => {
563
- // Arrange
564
- const hydrationCache = new MemoryCache();
565
- jest.spyOn(hydrationCache, "retrieve").mockReturnValue({
566
- data: "data!",
567
- });
568
- const cache = new ResponseCache(hydrationCache);
569
- const fakeHandler: IRequestHandler<string, string> = {
570
- getKey: () => "MY_KEY",
571
- type: "MY_HANDLER",
572
- fulfillRequest: jest.fn(),
573
- hydrate: true,
574
- };
575
-
576
- // Act
577
- const result = cache.getEntry(fakeHandler, "options");
578
-
579
- // Assert
580
- expect(result).toStrictEqual({data: "data!"});
581
- });
582
- });
583
-
584
- describe("handler does not want hyrdation", () => {
585
- it("should return null if not in the ssr-only cache", () => {
586
- // Arrange
587
- const hydrationCache = new MemoryCache();
588
- const ssrOnlyCache = new MemoryCache();
589
- jest.spyOn(hydrationCache, "retrieve").mockReturnValue(
590
- "NOT NULL",
591
- );
592
- jest.spyOn(ssrOnlyCache, "retrieve").mockReturnValue(null);
593
- const cache = new ResponseCache(
594
- hydrationCache,
595
- ssrOnlyCache,
596
- );
597
- const fakeHandler: IRequestHandler<string, string> = {
598
- getKey: () => "MY_KEY",
599
- type: "MY_HANDLER",
600
- fulfillRequest: jest.fn(),
601
- hydrate: false,
602
- };
603
-
604
- // Act
605
- const result = cache.getEntry(fakeHandler, "options");
606
-
607
- // Assert
608
- expect(result).toBeNull();
609
- });
610
-
611
- it("should return the cached entry if in the ssr-only cache", () => {
612
- // Arrange
613
- const hydrationCache = new MemoryCache();
614
- const ssrOnlyCache = new MemoryCache();
615
- jest.spyOn(hydrationCache, "retrieve").mockReturnValue({
616
- data: "wrong data!",
617
- });
618
- jest.spyOn(ssrOnlyCache, "retrieve").mockReturnValue({
619
- data: "data!",
620
- });
621
- const cache = new ResponseCache(
622
- hydrationCache,
623
- ssrOnlyCache,
624
- );
625
- const fakeHandler: IRequestHandler<string, string> = {
626
- getKey: () => "MY_KEY",
627
- type: "MY_HANDLER",
628
- fulfillRequest: jest.fn(),
629
- hydrate: false,
630
- };
631
-
632
- // Act
633
- const result = cache.getEntry(fakeHandler, "options");
634
-
635
- // Assert
636
- expect(result).toStrictEqual({data: "data!"});
637
- });
638
- });
639
- });
640
- });
641
-
642
- describe("#remove", () => {
643
- describe("when handler wants hydration", () => {
644
- it("should return false if nothing was removed from hydration cache", () => {
645
- // Arrange
646
- const hydrationCache = new MemoryCache();
647
- jest.spyOn(hydrationCache, "remove").mockReturnValue(false);
648
- const cache = new ResponseCache(hydrationCache);
649
- const fakeHandler: IRequestHandler<string, string> = {
650
- getKey: () => "MY_KEY",
651
- type: "MY_HANDLER",
652
- fulfillRequest: jest.fn(),
653
- hydrate: true,
654
- };
655
-
656
- // Act
657
- const result = cache.remove(fakeHandler, "optionsA");
658
-
659
- // Assert
660
- expect(result).toBeFalsy();
661
- });
662
-
663
- it("should return true if something was removed from hydration cache", () => {
664
- // Arrange
665
- const hydrationCache = new MemoryCache();
666
- jest.spyOn(hydrationCache, "remove").mockReturnValue(true);
667
- const cache = new ResponseCache(hydrationCache);
668
- const fakeHandler: IRequestHandler<string, string> = {
669
- getKey: () => "MY_KEY",
670
- type: "MY_HANDLER",
671
- fulfillRequest: jest.fn(),
672
- hydrate: true,
673
- };
674
-
675
- // Act
676
- const result = cache.remove(fakeHandler, "optionsA");
677
-
678
- // Assert
679
- expect(result).toBeTruthy();
680
- });
681
- });
682
-
683
- describe("when handler does not want hydration", () => {
684
- it("should return false", () => {
685
- // Arrange
686
- const hydrationCache = new MemoryCache();
687
- const ssrOnlyCache = new MemoryCache();
688
- jest.spyOn(hydrationCache, "remove").mockReturnValue(true);
689
- jest.spyOn(ssrOnlyCache, "remove").mockReturnValue(true);
690
- const cache = new ResponseCache(hydrationCache, ssrOnlyCache);
691
- const fakeHandler: IRequestHandler<string, string> = {
692
- getKey: () => "MY_KEY",
693
- type: "MY_HANDLER",
694
- fulfillRequest: jest.fn(),
695
- hydrate: false,
696
- };
697
-
698
- // Act
699
- const result = cache.remove(fakeHandler, "optionsA");
700
-
701
- // Assert
702
- expect(result).toBeFalsy();
703
- });
704
-
705
- describe("when server-side", () => {
706
- beforeEach(() => {
707
- jest.spyOn(Server, "isServerSide").mockReturnValue(true);
708
- });
709
-
710
- it("should return false if nothing was removed from ssr-only cache", () => {
711
- // Arrange
712
- const hydrationCache = new MemoryCache();
713
- const ssrOnlyCache = new MemoryCache();
714
- jest.spyOn(hydrationCache, "remove").mockReturnValue(true);
715
- jest.spyOn(ssrOnlyCache, "remove").mockReturnValue(false);
716
- const cache = new ResponseCache(
717
- hydrationCache,
718
- ssrOnlyCache,
719
- );
720
- const fakeHandler: IRequestHandler<string, string> = {
721
- getKey: () => "MY_KEY",
722
- type: "MY_HANDLER",
723
- fulfillRequest: jest.fn(),
724
- hydrate: false,
725
- };
726
-
727
- // Act
728
- const result = cache.remove(fakeHandler, "optionsA");
729
-
730
- // Assert
731
- expect(result).toBeFalsy();
732
- });
733
-
734
- it("should return true if something was removed from ssr-only cache", () => {
735
- // Arrange
736
- const hydrationCache = new MemoryCache();
737
- const ssrOnlyCache = new MemoryCache();
738
- jest.spyOn(ssrOnlyCache, "remove").mockReturnValue(true);
739
- const cache = new ResponseCache(
740
- hydrationCache,
741
- ssrOnlyCache,
742
- );
743
- const fakeHandler: IRequestHandler<string, string> = {
744
- getKey: () => "MY_KEY",
745
- type: "MY_HANDLER",
746
- fulfillRequest: jest.fn(),
747
- hydrate: false,
748
- };
749
-
750
- // Act
751
- const result = cache.remove(fakeHandler, "optionsA");
752
-
753
- // Assert
754
- expect(result).toBeTruthy();
755
- });
756
- });
757
- });
758
- });
759
-
760
- describe("#removeAll", () => {
761
- describe("when handler wants hydration", () => {
762
- it("should return total number of entries removed from hydration cache", () => {
763
- // Arrange
764
- const hydrationCache = new MemoryCache();
765
- jest.spyOn(hydrationCache, "removeAll").mockReturnValue(1);
766
- const cache = new ResponseCache(hydrationCache);
767
- const fakeHandler: IRequestHandler<string, string> = {
768
- getKey: () => "MY_KEY",
769
- type: "MY_HANDLER",
770
- fulfillRequest: jest.fn(),
771
- hydrate: true,
772
- };
773
-
774
- // Act
775
- const result = cache.removeAll(fakeHandler);
776
-
777
- // Assert
778
- expect(result).toBe(1);
779
- });
780
- });
781
-
782
- describe("when handler does not want hydration", () => {
783
- it("should return zero", () => {
784
- // Arrange
785
- const hydrationCache = new MemoryCache();
786
- const ssrOnlyCache = new MemoryCache();
787
- jest.spyOn(hydrationCache, "removeAll").mockReturnValue(42);
788
- jest.spyOn(ssrOnlyCache, "removeAll").mockReturnValue(42);
789
- const cache = new ResponseCache(hydrationCache, ssrOnlyCache);
790
- const fakeHandler: IRequestHandler<string, string> = {
791
- getKey: () => "MY_KEY",
792
- type: "MY_HANDLER",
793
- fulfillRequest: jest.fn(),
794
- hydrate: false,
795
- };
796
-
797
- // Act
798
- const result = cache.removeAll(fakeHandler);
799
-
800
- // Assert
801
- expect(result).toBe(0);
802
- });
803
-
804
- describe("when server-side", () => {
805
- beforeEach(() => {
806
- jest.spyOn(Server, "isServerSide").mockReturnValue(true);
807
- });
808
-
809
- it("should return total number of entries removed from ssr-only cache", () => {
810
- // Arrange
811
- const hydrationCache = new MemoryCache();
812
- const ssrOnlyCache = new MemoryCache();
813
- jest.spyOn(hydrationCache, "removeAll").mockReturnValue(13);
814
- jest.spyOn(ssrOnlyCache, "removeAll").mockReturnValue(42);
815
- const cache = new ResponseCache(
816
- hydrationCache,
817
- ssrOnlyCache,
818
- );
819
- const fakeHandler: IRequestHandler<string, string> = {
820
- getKey: () => "MY_KEY",
821
- type: "MY_HANDLER",
822
- fulfillRequest: jest.fn(),
823
- hydrate: false,
824
- };
825
-
826
- // Act
827
- const result = cache.removeAll(fakeHandler);
828
-
829
- // Assert
830
- expect(result).toBe(42);
831
- });
832
- });
833
- });
834
- });
835
-
836
- describe("#cloneHydratableData", () => {
837
- it("should clone the hydration cache", () => {
838
- // Arrange
839
- const hydrationCache = new MemoryCache();
840
- const cloneSpy = jest
841
- .spyOn(hydrationCache, "cloneData")
842
- .mockReturnValue("CLONE!");
843
- const cache = new ResponseCache(hydrationCache);
844
- const fakeHandler: IRequestHandler<string, string> = {
845
- getKey: (options) => options,
846
- type: "MY_HANDLER",
847
- fulfillRequest: jest.fn(),
848
- hydrate: true,
849
- };
850
- // Let's add to the initialized state to check that everything
851
- // is cloning as we expect.
852
- cache.cacheData(fakeHandler, "OPTIONS1", "DATA");
853
- cache.cacheError(fakeHandler, "OPTIONS2", new Error("OH NO!"));
854
-
855
- // Act
856
- const result = cache.cloneHydratableData();
857
-
858
- // Assert
859
- expect(cloneSpy).toHaveBeenCalled();
860
- expect(result).toBe("CLONE!");
861
- });
862
-
863
- it("should throw if the cloning fails", () => {
864
- // Arrange
865
- const cache = new ResponseCache();
866
- jest.spyOn(JSON, "stringify").mockImplementation(() => {
867
- throw new Error("BANG!");
868
- });
869
-
870
- // Act
871
- const underTest = () => cache.cloneHydratableData();
872
-
873
- // Assert
874
- expect(underTest).toThrowErrorMatchingInlineSnapshot(
875
- `"An error occurred while trying to clone the cache: Error: BANG!"`,
876
- );
877
- });
878
- });
879
- });