@khanacademy/wonder-blocks-data 13.0.11 → 14.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 (66) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/package.json +5 -5
  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,254 +0,0 @@
1
- import * as React from "react";
2
- import {renderHook} from "@testing-library/react-hooks";
3
- import InterceptRequests from "../../components/intercept-requests";
4
- import {useRequestInterception} from "../use-request-interception";
5
-
6
- describe("#useRequestInterception", () => {
7
- it("should return a function", () => {
8
- // Arrange
9
-
10
- // Act
11
- const {
12
- result: {current: result},
13
- } = renderHook(() => useRequestInterception("ID", jest.fn()));
14
-
15
- // Assert
16
- expect(result).toBeInstanceOf(Function);
17
- });
18
-
19
- it("should return the same function if the arguments and context don't change", () => {
20
- // Arrange
21
- const handler = jest.fn();
22
-
23
- // Act
24
- const wrapper = renderHook(() => useRequestInterception("ID", handler));
25
- const result1 = wrapper.result.current;
26
- wrapper.rerender();
27
- const result2 = wrapper.result.current;
28
-
29
- // Assert
30
- expect(result1).toBe(result2);
31
- });
32
-
33
- it("should return a new function if the requestId changes", () => {
34
- // Arrange
35
- const handler = jest.fn();
36
-
37
- // Act
38
- const wrapper = renderHook(
39
- ({requestId}: any) => useRequestInterception(requestId, handler),
40
- {initialProps: {requestId: "ID"}},
41
- );
42
- const result1 = wrapper.result.current;
43
- wrapper.rerender({requestId: "ID2"});
44
- const result2 = wrapper.result.current;
45
-
46
- // Assert
47
- expect(result1).not.toBe(result2);
48
- });
49
-
50
- it("should return a new function if the handler changes", () => {
51
- // Arrange
52
-
53
- // Act
54
- const wrapper = renderHook(
55
- ({handler}: any) => useRequestInterception("ID", handler),
56
- {initialProps: {handler: jest.fn()}},
57
- );
58
- const result1 = wrapper.result.current;
59
- wrapper.rerender({handler: jest.fn()});
60
- const result2 = wrapper.result.current;
61
-
62
- // Assert
63
- expect(result1).not.toBe(result2);
64
- });
65
-
66
- it("should return a new function if the context changes", () => {
67
- // Arrange
68
- const handler = jest.fn();
69
- const interceptor1 = jest.fn();
70
- const interceptor2 = jest.fn();
71
- const Wrapper = ({children, interceptor}: any): React.ReactElement => (
72
- <InterceptRequests interceptor={interceptor}>
73
- {children}
74
- </InterceptRequests>
75
- );
76
-
77
- // Act
78
- const wrapper = renderHook(
79
- () => useRequestInterception("ID", handler),
80
- {wrapper: Wrapper, initialProps: {interceptor: interceptor1}},
81
- );
82
- const result1 = wrapper.result.current;
83
- wrapper.rerender({interceptor: interceptor2});
84
- const result2 = wrapper.result.current;
85
-
86
- // Assert
87
- expect(result1).not.toBe(result2);
88
- });
89
-
90
- describe("returned function", () => {
91
- it("should invoke the original handler when there are no interceptors", () => {
92
- // Arrange
93
- const handler = jest.fn();
94
- const requestId = "ID";
95
- const {
96
- result: {current: interceptedHandler},
97
- } = renderHook(() => useRequestInterception(requestId, handler));
98
-
99
- // Act
100
- interceptedHandler();
101
-
102
- // Assert
103
- expect(handler).toHaveBeenCalledTimes(1);
104
- });
105
-
106
- it("should invoke interceptors nearest to furthest", () => {
107
- // Arrange
108
- const handler = jest.fn();
109
- const interceptorFurthest = jest.fn(() => null);
110
- const interceptorNearest = jest.fn(() => null);
111
- const Wrapper = ({children}: any) => (
112
- <InterceptRequests interceptor={interceptorFurthest}>
113
- <InterceptRequests interceptor={interceptorNearest}>
114
- {children}
115
- </InterceptRequests>
116
- </InterceptRequests>
117
- );
118
- const {
119
- result: {current: interceptedHandler},
120
- } = renderHook(() => useRequestInterception("ID", handler), {
121
- wrapper: Wrapper,
122
- });
123
-
124
- // Act
125
- interceptedHandler();
126
-
127
- // Assert
128
- expect(interceptorNearest).toHaveBeenCalledBefore(
129
- interceptorFurthest,
130
- );
131
- });
132
-
133
- it("should invoke the handler last", () => {
134
- // Arrange
135
- const handler = jest.fn();
136
- const interceptorFurthest = jest.fn(() => null);
137
- const interceptorNearest = jest.fn(() => null);
138
- const Wrapper = ({children}: any) => (
139
- <InterceptRequests interceptor={interceptorFurthest}>
140
- <InterceptRequests interceptor={interceptorNearest}>
141
- {children}
142
- </InterceptRequests>
143
- </InterceptRequests>
144
- );
145
- const {
146
- result: {current: interceptedHandler},
147
- } = renderHook(() => useRequestInterception("ID", handler), {
148
- wrapper: Wrapper,
149
- });
150
-
151
- // Act
152
- interceptedHandler();
153
-
154
- // Assert
155
- expect(interceptorFurthest).toHaveBeenCalledBefore(handler);
156
- });
157
-
158
- it("should invoke the original handler when there all interceptors return null", () => {
159
- // Arrange
160
- const handler = jest.fn();
161
- const interceptor1 = jest.fn(() => null);
162
- const interceptor2 = jest.fn(() => null);
163
- const Wrapper = ({children}: any) => (
164
- <InterceptRequests interceptor={interceptor1}>
165
- <InterceptRequests interceptor={interceptor2}>
166
- {children}
167
- </InterceptRequests>
168
- </InterceptRequests>
169
- );
170
- const {
171
- result: {current: interceptedHandler},
172
- } = renderHook(() => useRequestInterception("ID", handler), {
173
- wrapper: Wrapper,
174
- });
175
-
176
- // Act
177
- interceptedHandler();
178
-
179
- // Assert
180
- expect(handler).toHaveBeenCalledTimes(1);
181
- });
182
-
183
- it("should return the result of the nearest interceptor that returns a non-null result", async () => {
184
- // Arrange
185
- const handler = jest
186
- .fn()
187
- .mockRejectedValue(
188
- new Error("This handler should have been intercepted"),
189
- );
190
- const interceptorFurthest = jest
191
- .fn()
192
- .mockRejectedValue(
193
- new Error("This interceptor should not get called"),
194
- );
195
- const interceptorNearest = jest
196
- .fn()
197
- .mockResolvedValue("INTERCEPTED_DATA");
198
- const Wrapper = ({children}: any) => (
199
- <InterceptRequests interceptor={interceptorFurthest}>
200
- <InterceptRequests interceptor={interceptorNearest}>
201
- {children}
202
- </InterceptRequests>
203
- </InterceptRequests>
204
- );
205
- const {
206
- result: {current: interceptedHandler},
207
- } = renderHook(() => useRequestInterception("ID", handler), {
208
- wrapper: Wrapper,
209
- });
210
-
211
- // Act
212
- const result = await interceptedHandler();
213
-
214
- // Assert
215
- expect(result).toBe("INTERCEPTED_DATA");
216
- });
217
-
218
- it("should not invoke interceptors or handlers beyond a non-null interception", () => {
219
- // Arrange
220
- const handler = jest
221
- .fn()
222
- .mockRejectedValue(
223
- new Error("This handler should have been intercepted"),
224
- );
225
- const interceptorFurthest = jest
226
- .fn()
227
- .mockRejectedValue(
228
- new Error("This interceptor should not get called"),
229
- );
230
- const interceptorNearest = jest
231
- .fn()
232
- .mockResolvedValue("INTERCEPTED_DATA");
233
- const Wrapper = ({children}: any) => (
234
- <InterceptRequests interceptor={interceptorFurthest}>
235
- <InterceptRequests interceptor={interceptorNearest}>
236
- {children}
237
- </InterceptRequests>
238
- </InterceptRequests>
239
- );
240
- const {
241
- result: {current: interceptedHandler},
242
- } = renderHook(() => useRequestInterception("ID", handler), {
243
- wrapper: Wrapper,
244
- });
245
-
246
- // Act
247
- interceptedHandler();
248
-
249
- // Assert
250
- expect(handler).not.toHaveBeenCalled();
251
- expect(interceptorFurthest).not.toHaveBeenCalled();
252
- });
253
- });
254
- });
@@ -1,293 +0,0 @@
1
- import {renderHook as clientRenderHook} from "@testing-library/react-hooks";
2
- import {renderHookStatic} from "@khanacademy/wonder-blocks-testing-core";
3
-
4
- import {Server} from "@khanacademy/wonder-blocks-core";
5
-
6
- import TrackData from "../../components/track-data";
7
- import {RequestFulfillment} from "../../util/request-fulfillment";
8
- import {SsrCache} from "../../util/ssr-cache";
9
- import {RequestTracker} from "../../util/request-tracking";
10
- import {DataError} from "../../util/data-error";
11
- import * as UseRequestInterception from "../use-request-interception";
12
-
13
- import {useServerEffect} from "../use-server-effect";
14
-
15
- jest.mock("../use-request-interception");
16
-
17
- describe("#useServerEffect", () => {
18
- beforeEach(() => {
19
- jest.resetAllMocks();
20
-
21
- const responseCache = new SsrCache();
22
- jest.spyOn(SsrCache, "Default", "get").mockReturnValue(responseCache);
23
- jest.spyOn(RequestFulfillment, "Default", "get").mockReturnValue(
24
- new RequestFulfillment(),
25
- );
26
- jest.spyOn(RequestTracker, "Default", "get").mockReturnValue(
27
- new RequestTracker(responseCache),
28
- );
29
-
30
- // Simple implementation of request interception that just returns
31
- // the handler.
32
- jest.spyOn(
33
- UseRequestInterception,
34
- "useRequestInterception",
35
- ).mockImplementation((_: any, handler: any) => handler);
36
- });
37
-
38
- it("should call useRequestInterception", () => {
39
- // Arrange
40
- const useRequestInterceptSpy = jest
41
- .spyOn(UseRequestInterception, "useRequestInterception")
42
- .mockReturnValue(jest.fn());
43
- const fakeHandler = jest.fn();
44
-
45
- // Act
46
- renderHookStatic(() => useServerEffect("ID", fakeHandler));
47
-
48
- // Assert
49
- expect(useRequestInterceptSpy).toHaveBeenCalledWith("ID", fakeHandler);
50
- });
51
-
52
- describe("when server-side", () => {
53
- beforeEach(() => {
54
- jest.spyOn(Server, "isServerSide").mockReturnValue(true);
55
- });
56
-
57
- it("should return null if no cached result", () => {
58
- // Arrange
59
- const fakeHandler = jest.fn();
60
-
61
- // Act
62
- const {
63
- result: {current: result},
64
- } = renderHookStatic(() => useServerEffect("ID", fakeHandler));
65
-
66
- // Assert
67
- expect(result).toBeNull();
68
- });
69
-
70
- it("should not directly request fulfillment", () => {
71
- // Arrange
72
- const fakeHandler = jest.fn();
73
- const fulfillRequestSpy = jest.spyOn(
74
- RequestFulfillment.Default,
75
- "fulfill",
76
- );
77
-
78
- // Act
79
- renderHookStatic(() => useServerEffect("ID", fakeHandler));
80
-
81
- // Assert
82
- expect(fulfillRequestSpy).not.toHaveBeenCalled();
83
- });
84
-
85
- it("should track the intercepted request", () => {
86
- // Arrange
87
- const fakeHandler = jest.fn();
88
- const interceptedHandler = jest.fn();
89
- jest.spyOn(
90
- UseRequestInterception,
91
- "useRequestInterception",
92
- ).mockReturnValue(interceptedHandler);
93
- const trackDataRequestSpy = jest.spyOn(
94
- RequestTracker.Default,
95
- "trackDataRequest",
96
- );
97
-
98
- // Act
99
- renderHookStatic(() => useServerEffect("ID", fakeHandler), {
100
- wrapper: TrackData,
101
- });
102
-
103
- // Assert
104
- expect(trackDataRequestSpy).toHaveBeenCalledWith(
105
- "ID",
106
- interceptedHandler,
107
- true,
108
- );
109
- });
110
-
111
- it("should not track the intercepted request if skip is true", () => {
112
- // Arrange
113
- const fakeHandler = jest.fn();
114
- const interceptedHandler = jest.fn();
115
- jest.spyOn(
116
- UseRequestInterception,
117
- "useRequestInterception",
118
- ).mockReturnValue(interceptedHandler);
119
- const trackDataRequestSpy = jest.spyOn(
120
- RequestTracker.Default,
121
- "trackDataRequest",
122
- );
123
-
124
- // Act
125
- renderHookStatic(
126
- () => useServerEffect("ID", fakeHandler, {skip: true}),
127
- {
128
- wrapper: TrackData,
129
- },
130
- );
131
-
132
- // Assert
133
- expect(trackDataRequestSpy).not.toHaveBeenCalled();
134
- });
135
-
136
- it("should not track the intercepted request if there is a cached result", () => {
137
- // Arrange
138
- const fakeHandler = jest.fn();
139
- const interceptedHandler = jest.fn();
140
- jest.spyOn(SsrCache.Default, "getEntry").mockReturnValueOnce({
141
- data: "DATA",
142
- error: undefined,
143
- });
144
- jest.spyOn(
145
- UseRequestInterception,
146
- "useRequestInterception",
147
- ).mockReturnValue(interceptedHandler);
148
- const trackDataRequestSpy = jest.spyOn(
149
- RequestTracker.Default,
150
- "trackDataRequest",
151
- );
152
-
153
- // Act
154
- renderHookStatic(() => useServerEffect("ID", fakeHandler), {
155
- wrapper: TrackData,
156
- });
157
-
158
- // Assert
159
- expect(trackDataRequestSpy).not.toHaveBeenCalled();
160
- });
161
-
162
- it("should return data cached result", () => {
163
- // Arrange
164
- const fakeHandler = jest.fn();
165
- jest.spyOn(SsrCache.Default, "getEntry").mockReturnValueOnce({
166
- data: "DATA",
167
- error: undefined,
168
- });
169
-
170
- // Act
171
- const {
172
- result: {current: result},
173
- } = renderHookStatic(() => useServerEffect("ID", fakeHandler));
174
-
175
- // Assert
176
- expect(result).toEqual({status: "success", data: "DATA"});
177
- });
178
-
179
- it("should return error cached result", () => {
180
- // Arrange
181
- const fakeHandler = jest.fn();
182
- jest.spyOn(SsrCache.Default, "getEntry").mockReturnValueOnce({
183
- error: "ERROR",
184
- });
185
-
186
- // Act
187
- const {
188
- result: {current: result},
189
- } = renderHookStatic(() => useServerEffect("ID", fakeHandler));
190
-
191
- // Assert
192
- expect(result).toEqual({
193
- status: "error",
194
- error: expect.any(DataError),
195
- });
196
- });
197
- });
198
-
199
- describe("when client-side", () => {
200
- beforeEach(() => {
201
- jest.spyOn(Server, "isServerSide").mockReturnValue(false);
202
- });
203
-
204
- it("should return null if no cached result", () => {
205
- // Arrange
206
- const fakeHandler = jest.fn();
207
-
208
- // Act
209
- const {
210
- result: {current: result},
211
- } = clientRenderHook(() => useServerEffect("ID", fakeHandler));
212
-
213
- // Assert
214
- expect(result).toBeNull();
215
- });
216
-
217
- it("should return data cached result", () => {
218
- // Arrange
219
- const fakeHandler = jest.fn();
220
- jest.spyOn(SsrCache.Default, "getEntry").mockReturnValueOnce({
221
- data: "DATA",
222
- error: undefined,
223
- });
224
-
225
- // Act
226
- const {
227
- result: {current: result},
228
- } = clientRenderHook(() => useServerEffect("ID", fakeHandler));
229
-
230
- // Assert
231
- expect(result).toEqual({status: "success", data: "DATA"});
232
- });
233
-
234
- it("should return error cached result", () => {
235
- // Arrange
236
- const fakeHandler = jest.fn();
237
- jest.spyOn(SsrCache.Default, "getEntry").mockReturnValueOnce({
238
- error: "ERROR",
239
- });
240
-
241
- // Act
242
- const {
243
- result: {current: result},
244
- } = clientRenderHook(() => useServerEffect("ID", fakeHandler));
245
-
246
- // Assert
247
- expect(result).toEqual({
248
- status: "error",
249
- error: expect.any(DataError),
250
- });
251
- });
252
-
253
- it("should not track the request", () => {
254
- // Arrange
255
- const fakeHandler = jest.fn().mockReturnValue(
256
- new Promise(() => {
257
- /*prevent act() warning*/
258
- }),
259
- );
260
- const trackDataRequestSpy = jest.spyOn(
261
- RequestTracker.Default,
262
- "trackDataRequest",
263
- );
264
-
265
- // Act
266
- clientRenderHook(() => useServerEffect("ID", fakeHandler), {
267
- wrapper: TrackData,
268
- });
269
-
270
- // Assert
271
- expect(trackDataRequestSpy).not.toHaveBeenCalled();
272
- });
273
-
274
- it("should not request fulfillment", () => {
275
- // Arrange
276
- const fakeHandler = jest.fn().mockReturnValue(
277
- new Promise(() => {
278
- /*prevent act() warning*/
279
- }),
280
- );
281
- const fulfillRequestSpy = jest.spyOn(
282
- RequestFulfillment.Default,
283
- "fulfill",
284
- );
285
-
286
- // Act
287
- clientRenderHook(() => useServerEffect("ID", fakeHandler));
288
-
289
- // Assert
290
- expect(fulfillRequestSpy).not.toHaveBeenCalled();
291
- });
292
- });
293
- });