@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.
- package/CHANGELOG.md +8 -0
- package/package.json +3 -3
- package/src/components/__tests__/data.test.tsx +0 -832
- package/src/components/__tests__/gql-router.test.tsx +0 -63
- package/src/components/__tests__/intercept-requests.test.tsx +0 -57
- package/src/components/__tests__/track-data.test.tsx +0 -56
- package/src/components/data.ts +0 -73
- package/src/components/gql-router.tsx +0 -63
- package/src/components/intercept-context.ts +0 -19
- package/src/components/intercept-requests.tsx +0 -67
- package/src/components/track-data.tsx +0 -28
- package/src/hooks/__tests__/__snapshots__/use-shared-cache.test.ts.snap +0 -17
- package/src/hooks/__tests__/use-cached-effect.test.tsx +0 -789
- package/src/hooks/__tests__/use-gql-router-context.test.tsx +0 -132
- package/src/hooks/__tests__/use-gql.test.tsx +0 -204
- package/src/hooks/__tests__/use-hydratable-effect.test.ts +0 -708
- package/src/hooks/__tests__/use-request-interception.test.tsx +0 -254
- package/src/hooks/__tests__/use-server-effect.test.ts +0 -293
- package/src/hooks/__tests__/use-shared-cache.test.ts +0 -263
- package/src/hooks/use-cached-effect.ts +0 -297
- package/src/hooks/use-gql-router-context.ts +0 -49
- package/src/hooks/use-gql.ts +0 -58
- package/src/hooks/use-hydratable-effect.ts +0 -201
- package/src/hooks/use-request-interception.ts +0 -53
- package/src/hooks/use-server-effect.ts +0 -75
- package/src/hooks/use-shared-cache.ts +0 -107
- package/src/index.ts +0 -46
- package/src/util/__tests__/__snapshots__/scoped-in-memory-cache.test.ts.snap +0 -19
- package/src/util/__tests__/__snapshots__/serializable-in-memory-cache.test.ts.snap +0 -19
- package/src/util/__tests__/get-gql-data-from-response.test.ts +0 -186
- package/src/util/__tests__/get-gql-request-id.test.ts +0 -132
- package/src/util/__tests__/graphql-document-node-parser.test.ts +0 -535
- package/src/util/__tests__/hydration-cache-api.test.ts +0 -34
- package/src/util/__tests__/merge-gql-context.test.ts +0 -73
- package/src/util/__tests__/purge-caches.test.ts +0 -28
- package/src/util/__tests__/request-api.test.ts +0 -176
- package/src/util/__tests__/request-fulfillment.test.ts +0 -146
- package/src/util/__tests__/request-tracking.test.tsx +0 -321
- package/src/util/__tests__/result-from-cache-response.test.ts +0 -79
- package/src/util/__tests__/scoped-in-memory-cache.test.ts +0 -316
- package/src/util/__tests__/serializable-in-memory-cache.test.ts +0 -397
- package/src/util/__tests__/ssr-cache.test.ts +0 -636
- package/src/util/__tests__/to-gql-operation.test.ts +0 -41
- package/src/util/data-error.ts +0 -63
- package/src/util/get-gql-data-from-response.ts +0 -65
- package/src/util/get-gql-request-id.ts +0 -106
- package/src/util/gql-error.ts +0 -43
- package/src/util/gql-router-context.ts +0 -9
- package/src/util/gql-types.ts +0 -64
- package/src/util/graphql-document-node-parser.ts +0 -132
- package/src/util/graphql-types.ts +0 -28
- package/src/util/hydration-cache-api.ts +0 -30
- package/src/util/merge-gql-context.ts +0 -35
- package/src/util/purge-caches.ts +0 -14
- package/src/util/request-api.ts +0 -65
- package/src/util/request-fulfillment.ts +0 -121
- package/src/util/request-tracking.ts +0 -211
- package/src/util/result-from-cache-response.ts +0 -30
- package/src/util/scoped-in-memory-cache.ts +0 -121
- package/src/util/serializable-in-memory-cache.ts +0 -44
- package/src/util/ssr-cache.ts +0 -193
- package/src/util/status.ts +0 -35
- package/src/util/to-gql-operation.ts +0 -43
- package/src/util/types.ts +0 -145
- package/tsconfig-build.json +0 -12
- package/tsconfig-build.tsbuildinfo +0 -1
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line import/no-unassigned-import
|
|
2
|
-
import "jest-extended";
|
|
3
|
-
import {jest as wsJest} from "@khanacademy/wonder-stuff-testing";
|
|
4
|
-
import {Server} from "@khanacademy/wonder-blocks-core";
|
|
5
|
-
import {RequestFulfillment} from "../request-fulfillment";
|
|
6
|
-
import {RequestTracker} from "../request-tracking";
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
abortInflightRequests,
|
|
10
|
-
fetchTrackedRequests,
|
|
11
|
-
hasTrackedRequestsToBeFetched,
|
|
12
|
-
} from "../request-api";
|
|
13
|
-
|
|
14
|
-
describe("#fetchTrackedRequests", () => {
|
|
15
|
-
describe("when server-side", () => {
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
jest.spyOn(Server, "isServerSide").mockReturnValue(true);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it("should call RequestTracker.Default.fulfillTrackedRequests", () => {
|
|
21
|
-
// Arrange
|
|
22
|
-
const fulfillTrackedRequestsSpy = jest.spyOn(
|
|
23
|
-
RequestTracker.Default,
|
|
24
|
-
"fulfillTrackedRequests",
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
// Act
|
|
28
|
-
fetchTrackedRequests();
|
|
29
|
-
|
|
30
|
-
// Assert
|
|
31
|
-
expect(fulfillTrackedRequestsSpy).toHaveBeenCalled();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it("should return the response cache", async () => {
|
|
35
|
-
// Arrange
|
|
36
|
-
const responseCache: Record<string, any> = {};
|
|
37
|
-
jest.spyOn(
|
|
38
|
-
RequestTracker.Default,
|
|
39
|
-
"fulfillTrackedRequests",
|
|
40
|
-
).mockResolvedValue(responseCache);
|
|
41
|
-
|
|
42
|
-
// Act
|
|
43
|
-
const result = await fetchTrackedRequests();
|
|
44
|
-
|
|
45
|
-
// Assert
|
|
46
|
-
expect(result).toBe(responseCache);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
describe("when client-side", () => {
|
|
51
|
-
beforeEach(() => {
|
|
52
|
-
jest.spyOn(Server, "isServerSide").mockReturnValue(false);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
wsJest.afterEachRestoreEnv("NODE_ENV");
|
|
56
|
-
|
|
57
|
-
describe("in production", () => {
|
|
58
|
-
it("should reject with error", async () => {
|
|
59
|
-
// Arrange
|
|
60
|
-
process.env.NODE_ENV = "production";
|
|
61
|
-
|
|
62
|
-
// Act
|
|
63
|
-
const result = fetchTrackedRequests();
|
|
64
|
-
|
|
65
|
-
// Assert
|
|
66
|
-
await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
67
|
-
`"No CSR tracking"`,
|
|
68
|
-
);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
describe("not in production", () => {
|
|
73
|
-
it("should reject with error", async () => {
|
|
74
|
-
// Arrange
|
|
75
|
-
process.env.NODE_ENV = "test";
|
|
76
|
-
|
|
77
|
-
// Act
|
|
78
|
-
const result = fetchTrackedRequests();
|
|
79
|
-
|
|
80
|
-
// Assert
|
|
81
|
-
await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
82
|
-
`"Data requests are not tracked for fulfillment when when client-side"`,
|
|
83
|
-
);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
describe("#hasTrackedRequestsToBeFetched", () => {
|
|
90
|
-
describe("when server-side", () => {
|
|
91
|
-
beforeEach(() => {
|
|
92
|
-
jest.spyOn(Server, "isServerSide").mockReturnValue(true);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it("should call RequestTracker.Default.hasUnfulfilledRequests", () => {
|
|
96
|
-
// Arrange
|
|
97
|
-
const hasUnfulfilledRequestsSpy = jest.spyOn(
|
|
98
|
-
RequestTracker.Default,
|
|
99
|
-
"hasUnfulfilledRequests",
|
|
100
|
-
"get",
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
// Act
|
|
104
|
-
hasTrackedRequestsToBeFetched();
|
|
105
|
-
|
|
106
|
-
// Assert
|
|
107
|
-
expect(hasUnfulfilledRequestsSpy).toHaveBeenCalled();
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it("should return the boolean value from RequestTracker.Default.hasUnfulfilledRequests", () => {
|
|
111
|
-
// Arrange
|
|
112
|
-
jest.spyOn(
|
|
113
|
-
RequestTracker.Default,
|
|
114
|
-
"hasUnfulfilledRequests",
|
|
115
|
-
"get",
|
|
116
|
-
).mockReturnValue(true);
|
|
117
|
-
|
|
118
|
-
// Act
|
|
119
|
-
const result = hasTrackedRequestsToBeFetched();
|
|
120
|
-
|
|
121
|
-
// Assert
|
|
122
|
-
expect(result).toBeTrue();
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
describe("when client-side", () => {
|
|
127
|
-
beforeEach(() => {
|
|
128
|
-
jest.spyOn(Server, "isServerSide").mockReturnValue(false);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
wsJest.afterEachRestoreEnv("NODE_ENV");
|
|
132
|
-
|
|
133
|
-
describe("in production", () => {
|
|
134
|
-
it("should reject with error", () => {
|
|
135
|
-
// Arrange
|
|
136
|
-
process.env.NODE_ENV = "production";
|
|
137
|
-
|
|
138
|
-
// Act
|
|
139
|
-
const underTest = () => hasTrackedRequestsToBeFetched();
|
|
140
|
-
|
|
141
|
-
// Assert
|
|
142
|
-
expect(underTest).toThrowErrorMatchingInlineSnapshot(
|
|
143
|
-
`"No CSR tracking"`,
|
|
144
|
-
);
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
describe("not in production", () => {
|
|
149
|
-
it("should reject with error", () => {
|
|
150
|
-
// Arrange
|
|
151
|
-
process.env.NODE_ENV = "test";
|
|
152
|
-
|
|
153
|
-
// Act
|
|
154
|
-
const underTest = () => hasTrackedRequestsToBeFetched();
|
|
155
|
-
|
|
156
|
-
// Assert
|
|
157
|
-
expect(underTest).toThrowErrorMatchingInlineSnapshot(
|
|
158
|
-
`"Data requests are not tracked for fulfillment when when client-side"`,
|
|
159
|
-
);
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
describe("#abortInflightRequests", () => {
|
|
166
|
-
it("should call RequestFulfillment.Default.abortAll", () => {
|
|
167
|
-
// Arrange
|
|
168
|
-
const abortAllSpy = jest.spyOn(RequestFulfillment.Default, "abortAll");
|
|
169
|
-
|
|
170
|
-
// Act
|
|
171
|
-
abortInflightRequests();
|
|
172
|
-
|
|
173
|
-
// Assert
|
|
174
|
-
expect(abortAllSpy).toHaveBeenCalled();
|
|
175
|
-
});
|
|
176
|
-
});
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import {RequestFulfillment} from "../request-fulfillment";
|
|
2
|
-
import {DataError} from "../data-error";
|
|
3
|
-
|
|
4
|
-
describe("RequestFulfillment", () => {
|
|
5
|
-
it("should provide static default instance", () => {
|
|
6
|
-
// Arrange
|
|
7
|
-
|
|
8
|
-
// Act
|
|
9
|
-
const defaultInstance = RequestFulfillment.Default;
|
|
10
|
-
|
|
11
|
-
// Assert
|
|
12
|
-
expect(defaultInstance).toBe(RequestFulfillment.Default);
|
|
13
|
-
expect(defaultInstance).toBeInstanceOf(RequestFulfillment);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
describe("#fulfill", () => {
|
|
17
|
-
it("should resolve to an error result", async () => {
|
|
18
|
-
// Arrange
|
|
19
|
-
const requestFulfillment = new RequestFulfillment();
|
|
20
|
-
const fakeBadRequestHandler = () => Promise.reject("OH NO!");
|
|
21
|
-
|
|
22
|
-
// Act
|
|
23
|
-
const result = await requestFulfillment.fulfill("ID", {
|
|
24
|
-
handler: fakeBadRequestHandler,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Assert
|
|
28
|
-
expect(result).toStrictEqual({
|
|
29
|
-
status: "error",
|
|
30
|
-
error: expect.any(DataError),
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it("should resolve to an aborted result", async () => {
|
|
35
|
-
// Arrange
|
|
36
|
-
const requestFulfillment = new RequestFulfillment();
|
|
37
|
-
const abortError = new Error("abort abort abort, awoooga");
|
|
38
|
-
abortError.name = "AbortError";
|
|
39
|
-
const fakeBadRequestHandler = () => Promise.reject(abortError);
|
|
40
|
-
|
|
41
|
-
// Act
|
|
42
|
-
const result = await requestFulfillment.fulfill("ID", {
|
|
43
|
-
handler: fakeBadRequestHandler,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// Assert
|
|
47
|
-
expect(result).toStrictEqual({
|
|
48
|
-
status: "aborted",
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("should resolve to a data result", async () => {
|
|
53
|
-
// Arrange
|
|
54
|
-
const requestFulfillment = new RequestFulfillment();
|
|
55
|
-
const fakeRequestHandler = () => Promise.resolve("DATA!");
|
|
56
|
-
|
|
57
|
-
// Act
|
|
58
|
-
const result = await requestFulfillment.fulfill("ID", {
|
|
59
|
-
handler: fakeRequestHandler,
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// Assert
|
|
63
|
-
expect(result).toStrictEqual({
|
|
64
|
-
status: "success",
|
|
65
|
-
data: "DATA!",
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("should reuse inflight requests", () => {
|
|
70
|
-
// Arrange
|
|
71
|
-
const requestFulfillment = new RequestFulfillment();
|
|
72
|
-
const fakeRequestHandler = () => Promise.resolve("DATA!");
|
|
73
|
-
|
|
74
|
-
// Act
|
|
75
|
-
const promise = requestFulfillment.fulfill("ID", {
|
|
76
|
-
handler: fakeRequestHandler,
|
|
77
|
-
});
|
|
78
|
-
const result = requestFulfillment.fulfill("ID", {
|
|
79
|
-
handler: fakeRequestHandler,
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// Assert
|
|
83
|
-
expect(result).toBe(promise);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it("should remove inflight requests upon completion", async () => {
|
|
87
|
-
// Arrange
|
|
88
|
-
const requestFulfillment = new RequestFulfillment();
|
|
89
|
-
const fakeRequestHandler = () => Promise.resolve("DATA!");
|
|
90
|
-
|
|
91
|
-
// Act
|
|
92
|
-
const promise = requestFulfillment.fulfill("ID", {
|
|
93
|
-
handler: fakeRequestHandler,
|
|
94
|
-
});
|
|
95
|
-
await promise;
|
|
96
|
-
const result = requestFulfillment.fulfill("ID", {
|
|
97
|
-
handler: fakeRequestHandler,
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Assert
|
|
101
|
-
expect(result).not.toBe(promise);
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
describe("#abort", () => {
|
|
106
|
-
it("should delete the given request from the inflight requests", () => {
|
|
107
|
-
// Arrange
|
|
108
|
-
const requestFulfillment = new RequestFulfillment();
|
|
109
|
-
const fakeRequestHandler = () => Promise.resolve("DATA!");
|
|
110
|
-
const promise = requestFulfillment.fulfill("ID", {
|
|
111
|
-
handler: fakeRequestHandler,
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// Act
|
|
115
|
-
requestFulfillment.abort("ID");
|
|
116
|
-
const result = requestFulfillment.fulfill("ID", {
|
|
117
|
-
handler: fakeRequestHandler,
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// Assert
|
|
121
|
-
expect(result).not.toBe(promise);
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
describe("#abortAll", () => {
|
|
126
|
-
it("should abort all inflight requests", () => {
|
|
127
|
-
// Arrange
|
|
128
|
-
const requestFulfillment = new RequestFulfillment();
|
|
129
|
-
const abortSpy = jest.spyOn(requestFulfillment, "abort");
|
|
130
|
-
const fakeRequestHandler = () => Promise.resolve("DATA!");
|
|
131
|
-
requestFulfillment.fulfill("ID1", {
|
|
132
|
-
handler: fakeRequestHandler,
|
|
133
|
-
});
|
|
134
|
-
requestFulfillment.fulfill("ID2", {
|
|
135
|
-
handler: fakeRequestHandler,
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// Act
|
|
139
|
-
requestFulfillment.abortAll();
|
|
140
|
-
|
|
141
|
-
// Assert
|
|
142
|
-
expect(abortSpy).toHaveBeenCalledWith("ID1");
|
|
143
|
-
expect(abortSpy).toHaveBeenCalledWith("ID2");
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
});
|
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {render} from "@testing-library/react";
|
|
3
|
-
|
|
4
|
-
import {Server} from "@khanacademy/wonder-blocks-core";
|
|
5
|
-
import {RequestTracker, TrackerContext} from "../request-tracking";
|
|
6
|
-
import {SsrCache} from "../ssr-cache";
|
|
7
|
-
|
|
8
|
-
describe("../request-tracking.js", () => {
|
|
9
|
-
describe("TrackerContext", () => {
|
|
10
|
-
it("should default to null", async () => {
|
|
11
|
-
// Arrange
|
|
12
|
-
|
|
13
|
-
// Act
|
|
14
|
-
const result = await new Promise((resolve: any, reject: any) => {
|
|
15
|
-
render(
|
|
16
|
-
<TrackerContext.Consumer>
|
|
17
|
-
{(fn: any) => resolve(fn)}
|
|
18
|
-
</TrackerContext.Consumer>,
|
|
19
|
-
);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
// Assert
|
|
23
|
-
expect(result).toBeNull();
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe("RequestTracker", () => {
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
jest.spyOn(Server, "isServerSide").mockReturnValue(true);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const createRequestTracker = () =>
|
|
33
|
-
/**
|
|
34
|
-
* We pass our own response cache instance so that the test cases
|
|
35
|
-
* are not sharing the same default instance.
|
|
36
|
-
*/
|
|
37
|
-
new RequestTracker(new SsrCache());
|
|
38
|
-
|
|
39
|
-
describe("@Default", () => {
|
|
40
|
-
it("should return an instance of RequestTracker", () => {
|
|
41
|
-
// Arrange
|
|
42
|
-
|
|
43
|
-
// Act
|
|
44
|
-
const result = RequestTracker.Default;
|
|
45
|
-
|
|
46
|
-
// Assert
|
|
47
|
-
expect(result).toBeInstanceOf(RequestTracker);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("should return the same instance on each call", () => {
|
|
51
|
-
// Arrange
|
|
52
|
-
|
|
53
|
-
// Act
|
|
54
|
-
const result1 = RequestTracker.Default;
|
|
55
|
-
const result2 = RequestTracker.Default;
|
|
56
|
-
|
|
57
|
-
// Assert
|
|
58
|
-
expect(result1).toBe(result2);
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
describe("#trackDataRequest", () => {
|
|
63
|
-
it("should track a request", async () => {
|
|
64
|
-
// Arrange
|
|
65
|
-
const requestTracker = new RequestTracker();
|
|
66
|
-
const fakeHandler = jest.fn();
|
|
67
|
-
|
|
68
|
-
// Act
|
|
69
|
-
requestTracker.trackDataRequest("ID", fakeHandler, false);
|
|
70
|
-
await requestTracker.fulfillTrackedRequests();
|
|
71
|
-
|
|
72
|
-
// Assert
|
|
73
|
-
expect(fakeHandler).toHaveBeenCalledTimes(1);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it("should track each matching request once", async () => {
|
|
77
|
-
// Arrange
|
|
78
|
-
const requestTracker = createRequestTracker();
|
|
79
|
-
const fakeHandler = jest.fn().mockResolvedValue("DATA");
|
|
80
|
-
|
|
81
|
-
// Act
|
|
82
|
-
requestTracker.trackDataRequest("ID", fakeHandler, true);
|
|
83
|
-
requestTracker.trackDataRequest("ID", fakeHandler, true);
|
|
84
|
-
await requestTracker.fulfillTrackedRequests();
|
|
85
|
-
|
|
86
|
-
// Assert
|
|
87
|
-
expect(fakeHandler).toHaveBeenCalledTimes(1);
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
describe("#hasUnfulfilledRequests", () => {
|
|
92
|
-
it("should return false if no requests have been tracked", () => {
|
|
93
|
-
// Arrange
|
|
94
|
-
const requestTracker = createRequestTracker();
|
|
95
|
-
|
|
96
|
-
// Act
|
|
97
|
-
const result = requestTracker.hasUnfulfilledRequests;
|
|
98
|
-
|
|
99
|
-
// Assert
|
|
100
|
-
expect(result).toBe(false);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it("should return true if there are requests waiting to be fulfilled", () => {
|
|
104
|
-
// Arrange
|
|
105
|
-
const requestTracker = createRequestTracker();
|
|
106
|
-
const fakeHandler = jest.fn();
|
|
107
|
-
requestTracker.trackDataRequest("ID", fakeHandler, true);
|
|
108
|
-
|
|
109
|
-
// Act
|
|
110
|
-
const result = requestTracker.hasUnfulfilledRequests;
|
|
111
|
-
|
|
112
|
-
// Assert
|
|
113
|
-
expect(result).toBe(true);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it("should return false if all tracked requests have been fulfilled", () => {
|
|
117
|
-
// Arrange
|
|
118
|
-
const requestTracker = createRequestTracker();
|
|
119
|
-
const fakeHandler = jest.fn().mockResolvedValue(5);
|
|
120
|
-
requestTracker.trackDataRequest("ID", fakeHandler, false);
|
|
121
|
-
requestTracker.fulfillTrackedRequests();
|
|
122
|
-
|
|
123
|
-
// Act
|
|
124
|
-
const result = requestTracker.hasUnfulfilledRequests;
|
|
125
|
-
|
|
126
|
-
// Assert
|
|
127
|
-
expect(result).toBe(false);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe("#fulfillTrackedRequests", () => {
|
|
132
|
-
it("should return an empty cache if no requests tracked", async () => {
|
|
133
|
-
// Arrange
|
|
134
|
-
const requestTracker = createRequestTracker();
|
|
135
|
-
|
|
136
|
-
// Act
|
|
137
|
-
const result = await requestTracker.fulfillTrackedRequests();
|
|
138
|
-
|
|
139
|
-
// Assert
|
|
140
|
-
expect(result).toStrictEqual({});
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("should cache errors caused directly by handlers", async () => {
|
|
144
|
-
// Arrange
|
|
145
|
-
const requestTracker = createRequestTracker();
|
|
146
|
-
const fakeBadHandler = () => {
|
|
147
|
-
throw new Error("OH NO!");
|
|
148
|
-
};
|
|
149
|
-
requestTracker.trackDataRequest("ID", fakeBadHandler, true);
|
|
150
|
-
|
|
151
|
-
// Act
|
|
152
|
-
const result = await requestTracker.fulfillTrackedRequests();
|
|
153
|
-
|
|
154
|
-
// Assert
|
|
155
|
-
expect(result).toStrictEqual({
|
|
156
|
-
ID: {
|
|
157
|
-
error: "OH NO!",
|
|
158
|
-
},
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it("should cache errors occurring in promises", async () => {
|
|
163
|
-
// Arrange
|
|
164
|
-
const requestTracker = createRequestTracker();
|
|
165
|
-
const fakeBadRequestHandler = (): Promise<any> =>
|
|
166
|
-
new Promise((resolve: any, reject: any) =>
|
|
167
|
-
reject("OH NO!"),
|
|
168
|
-
);
|
|
169
|
-
requestTracker.trackDataRequest(
|
|
170
|
-
"ID",
|
|
171
|
-
fakeBadRequestHandler,
|
|
172
|
-
true,
|
|
173
|
-
);
|
|
174
|
-
// Act
|
|
175
|
-
const result = await requestTracker.fulfillTrackedRequests();
|
|
176
|
-
|
|
177
|
-
// Assert
|
|
178
|
-
expect(result).toStrictEqual({
|
|
179
|
-
ID: {
|
|
180
|
-
error: "Request failed",
|
|
181
|
-
},
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
it("should cache data and errors for all requests", async () => {
|
|
186
|
-
// Arrange
|
|
187
|
-
const requestTracker = createRequestTracker();
|
|
188
|
-
/**
|
|
189
|
-
* We're going to check a few things here:
|
|
190
|
-
* - Handlers that crash when making the request
|
|
191
|
-
* - Handlers that reject the promise
|
|
192
|
-
* - Handlers that resolve
|
|
193
|
-
*/
|
|
194
|
-
const fakeBadRequestHandler = (): Promise<any> =>
|
|
195
|
-
new Promise((resolve: any, reject: any) =>
|
|
196
|
-
reject("OH NO!"),
|
|
197
|
-
);
|
|
198
|
-
const fakeBadHandler = (): Promise<any> => {
|
|
199
|
-
throw new Error("OH NO!");
|
|
200
|
-
};
|
|
201
|
-
const fakeValidHandler = ((): (() => Promise<any>) => {
|
|
202
|
-
let counter = 0;
|
|
203
|
-
return () => {
|
|
204
|
-
counter++;
|
|
205
|
-
return Promise.resolve(`DATA:${counter}`);
|
|
206
|
-
};
|
|
207
|
-
})();
|
|
208
|
-
requestTracker.trackDataRequest(
|
|
209
|
-
"BAD_REQUEST",
|
|
210
|
-
fakeBadRequestHandler,
|
|
211
|
-
true,
|
|
212
|
-
);
|
|
213
|
-
requestTracker.trackDataRequest(
|
|
214
|
-
"BAD_HANDLER",
|
|
215
|
-
fakeBadHandler,
|
|
216
|
-
true,
|
|
217
|
-
);
|
|
218
|
-
requestTracker.trackDataRequest(
|
|
219
|
-
"VALID_HANDLER1",
|
|
220
|
-
fakeValidHandler,
|
|
221
|
-
true,
|
|
222
|
-
);
|
|
223
|
-
requestTracker.trackDataRequest(
|
|
224
|
-
"VALID_HANDLER2",
|
|
225
|
-
fakeValidHandler,
|
|
226
|
-
true,
|
|
227
|
-
);
|
|
228
|
-
|
|
229
|
-
// Act
|
|
230
|
-
const result = await requestTracker.fulfillTrackedRequests();
|
|
231
|
-
|
|
232
|
-
// Assert
|
|
233
|
-
expect(result).toStrictEqual({
|
|
234
|
-
BAD_REQUEST: {
|
|
235
|
-
error: "Request failed",
|
|
236
|
-
},
|
|
237
|
-
BAD_HANDLER: {
|
|
238
|
-
error: "OH NO!",
|
|
239
|
-
},
|
|
240
|
-
VALID_HANDLER1: {
|
|
241
|
-
data: "DATA:1",
|
|
242
|
-
},
|
|
243
|
-
VALID_HANDLER2: {
|
|
244
|
-
data: "DATA:2",
|
|
245
|
-
},
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
it("should ignore loading results", async () => {
|
|
250
|
-
// Arrange
|
|
251
|
-
const requestTracker = createRequestTracker();
|
|
252
|
-
jest.spyOn(
|
|
253
|
-
requestTracker._requestFulfillment,
|
|
254
|
-
"fulfill",
|
|
255
|
-
).mockResolvedValue({status: "loading"});
|
|
256
|
-
const fakeValidHandler = () =>
|
|
257
|
-
Promise.reject(new Error("Not called for this test case"));
|
|
258
|
-
requestTracker.trackDataRequest("ID", fakeValidHandler, true);
|
|
259
|
-
|
|
260
|
-
// Act
|
|
261
|
-
const result = await requestTracker.fulfillTrackedRequests();
|
|
262
|
-
|
|
263
|
-
// Assert
|
|
264
|
-
expect(result).toStrictEqual({});
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
it("should ignore aborted results", async () => {
|
|
268
|
-
// Arrange
|
|
269
|
-
const requestTracker = createRequestTracker();
|
|
270
|
-
jest.spyOn(
|
|
271
|
-
requestTracker._requestFulfillment,
|
|
272
|
-
"fulfill",
|
|
273
|
-
).mockResolvedValue({status: "aborted"});
|
|
274
|
-
const fakeValidHandler = () =>
|
|
275
|
-
Promise.reject(new Error("Not called for this test case"));
|
|
276
|
-
requestTracker.trackDataRequest("ID", fakeValidHandler, false);
|
|
277
|
-
|
|
278
|
-
// Act
|
|
279
|
-
const result = await requestTracker.fulfillTrackedRequests();
|
|
280
|
-
|
|
281
|
-
// Assert
|
|
282
|
-
expect(result).toStrictEqual({});
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
it("should clear the tracked requests", async () => {
|
|
286
|
-
// Arrange
|
|
287
|
-
const requestTracker = createRequestTracker();
|
|
288
|
-
const fakeStaticHandler = jest.fn(() =>
|
|
289
|
-
Promise.resolve("DATA"),
|
|
290
|
-
);
|
|
291
|
-
requestTracker.trackDataRequest("1", fakeStaticHandler, true);
|
|
292
|
-
requestTracker.trackDataRequest("2", fakeStaticHandler, true);
|
|
293
|
-
requestTracker.trackDataRequest("3", fakeStaticHandler, true);
|
|
294
|
-
|
|
295
|
-
// Act
|
|
296
|
-
await requestTracker.fulfillTrackedRequests();
|
|
297
|
-
fakeStaticHandler.mockClear();
|
|
298
|
-
await requestTracker.fulfillTrackedRequests();
|
|
299
|
-
|
|
300
|
-
// Assert
|
|
301
|
-
expect(fakeStaticHandler).not.toHaveBeenCalled();
|
|
302
|
-
});
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
describe("#reset", () => {
|
|
306
|
-
it("should clear the tracked data requests", async () => {
|
|
307
|
-
// Arrange
|
|
308
|
-
const requestTracker = createRequestTracker();
|
|
309
|
-
const fakeHandler = jest.fn().mockResolvedValue("DATA");
|
|
310
|
-
requestTracker.trackDataRequest("ID", fakeHandler, true);
|
|
311
|
-
|
|
312
|
-
// Act
|
|
313
|
-
requestTracker.reset();
|
|
314
|
-
await requestTracker.fulfillTrackedRequests();
|
|
315
|
-
|
|
316
|
-
// Assert
|
|
317
|
-
expect(fakeHandler).not.toHaveBeenCalled();
|
|
318
|
-
});
|
|
319
|
-
});
|
|
320
|
-
});
|
|
321
|
-
});
|