@khanacademy/wonder-blocks-timing 4.0.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.
- package/CHANGELOG.md +12 -0
- package/dist/es/index.js +89 -104
- package/dist/hooks/use-interval.d.ts +27 -5
- package/dist/hooks/use-timeout.d.ts +27 -5
- package/dist/index.d.ts +2 -5
- package/dist/index.js +88 -104
- package/dist/util/animation-frame.d.ts +6 -6
- package/dist/util/interval.d.ts +7 -7
- package/dist/util/policies.d.ts +12 -8
- package/dist/util/timeout.d.ts +7 -6
- package/dist/util/types.d.ts +18 -10
- package/package.json +1 -1
- package/src/hooks/__tests__/use-interval.test.ts +453 -56
- package/src/hooks/__tests__/use-timeout.test.ts +412 -58
- package/src/hooks/use-interval.ts +90 -25
- package/src/hooks/use-timeout.ts +90 -25
- package/src/index.ts +4 -14
- package/src/util/animation-frame.ts +12 -16
- package/src/util/interval.ts +12 -16
- package/src/util/policies.ts +13 -8
- package/src/util/timeout.ts +13 -16
- package/src/util/types.ts +19 -11
- package/tsconfig-build.json +2 -4
- package/tsconfig-build.tsbuildinfo +1 -1
- package/dist/hooks/internal/use-updating-ref.d.ts +0 -13
- package/dist/hooks/use-scheduled-interval.d.ts +0 -2
- package/dist/hooks/use-scheduled-timeout.d.ts +0 -2
- package/src/hooks/__tests__/use-scheduled-interval.test.ts +0 -460
- package/src/hooks/__tests__/use-scheduled-timeout.test.ts +0 -478
- package/src/hooks/internal/use-updating-ref.ts +0 -23
- package/src/hooks/use-scheduled-interval.ts +0 -72
- package/src/hooks/use-scheduled-timeout.ts +0 -79
package/dist/util/timeout.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { SchedulePolicy, ClearPolicy } from "./policies";
|
|
2
|
+
import type { ITimeout } from "./types";
|
|
2
3
|
/**
|
|
3
4
|
* Encapsulates everything associated with calling setTimeout/clearTimeout, and
|
|
4
5
|
* managing the lifecycle of that timer, including the ability to resolve or
|
|
@@ -16,10 +17,10 @@ export default class Timeout implements ITimeout {
|
|
|
16
17
|
* Creates a timeout that will invoke the given action after
|
|
17
18
|
* the given period. The timeout does not start until set is called.
|
|
18
19
|
*
|
|
19
|
-
* @param
|
|
20
|
+
* @param action The action to be invoked when the timeout
|
|
20
21
|
* period has passed.
|
|
21
|
-
* @param
|
|
22
|
-
* @param
|
|
22
|
+
* @param timeoutMs The timeout period.
|
|
23
|
+
* @param [schedulePolicy] When SchedulePolicy.Immediately,
|
|
23
24
|
* the timer is set immediately on instantiation; otherwise, `set` must be
|
|
24
25
|
* called to set the timeout.
|
|
25
26
|
* Defaults to `SchedulePolicy.Immediately`.
|
|
@@ -29,7 +30,7 @@ export default class Timeout implements ITimeout {
|
|
|
29
30
|
/**
|
|
30
31
|
* Determine if the timeout is set or not.
|
|
31
32
|
*
|
|
32
|
-
* @returns
|
|
33
|
+
* @returns true if the timeout is set (aka pending), otherwise
|
|
33
34
|
* false.
|
|
34
35
|
* @memberof Timeout
|
|
35
36
|
*/
|
|
@@ -50,7 +51,7 @@ export default class Timeout implements ITimeout {
|
|
|
50
51
|
* If the timeout is pending, this cancels that pending timeout without
|
|
51
52
|
* invoking the action. If no timeout is pending, this does nothing.
|
|
52
53
|
*
|
|
53
|
-
* @param
|
|
54
|
+
* @param [policy] When ClearPolicy.Resolve, if the request
|
|
54
55
|
* was set when called, the request action is invoked after cancelling
|
|
55
56
|
* the request; otherwise, the pending action is cancelled.
|
|
56
57
|
* Defaults to `ClearPolicy.Cancel`.
|
package/dist/util/types.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export type ClearPolicy = "resolve-on-clear" | "cancel-on-clear";
|
|
1
|
+
import * as Policies from "./policies";
|
|
3
2
|
/**
|
|
4
3
|
* Encapsulates everything associated with calling setTimeout/clearTimeout, and
|
|
5
4
|
* managing the lifecycle of that timer, including the ability to resolve or
|
|
@@ -33,14 +32,14 @@ export interface ITimeout {
|
|
|
33
32
|
* If the timeout is pending, this cancels that pending timeout. If no
|
|
34
33
|
* timeout is pending, this does nothing.
|
|
35
34
|
*
|
|
36
|
-
* @param
|
|
35
|
+
* @param [policy] When ClearPolicy.Resolve, if the request
|
|
37
36
|
* was set when called, the request action is invoked after cancelling
|
|
38
37
|
* the request; otherwise, the pending action is cancelled.
|
|
39
38
|
* Defaults to `ClearPolicy.Cancel`.
|
|
40
39
|
*
|
|
41
40
|
* @memberof ITimeout
|
|
42
41
|
*/
|
|
43
|
-
clear(policy?: ClearPolicy): void;
|
|
42
|
+
clear(policy?: Policies.ClearPolicy): void;
|
|
44
43
|
}
|
|
45
44
|
/**
|
|
46
45
|
* Encapsulates everything associated with calling setInterval/clearInterval,
|
|
@@ -73,14 +72,14 @@ export interface IInterval {
|
|
|
73
72
|
* If the interval is active, this cancels that interval. If the interval
|
|
74
73
|
* is not active, this does nothing.
|
|
75
74
|
*
|
|
76
|
-
* @param
|
|
75
|
+
* @param [policy] When ClearPolicy.Resolve, if the request
|
|
77
76
|
* was set when called, the request action is invoked after cancelling
|
|
78
77
|
* the request; otherwise, the pending action is cancelled.
|
|
79
78
|
* Defaults to `ClearPolicy.Cancel`.
|
|
80
79
|
*
|
|
81
80
|
* @memberof IInterval
|
|
82
81
|
*/
|
|
83
|
-
clear(policy?: ClearPolicy): void;
|
|
82
|
+
clear(policy?: Policies.ClearPolicy): void;
|
|
84
83
|
}
|
|
85
84
|
/**
|
|
86
85
|
* Encapsulates everything associated with calling requestAnimationFrame/
|
|
@@ -115,18 +114,27 @@ export interface IAnimationFrame {
|
|
|
115
114
|
* If the request is pending, this cancels that pending request. If no
|
|
116
115
|
* request is pending, this does nothing.
|
|
117
116
|
*
|
|
118
|
-
* @param
|
|
117
|
+
* @param [policy] When ClearPolicy.Resolve, if the request
|
|
119
118
|
* was set when called, the request action is invoked after cancelling
|
|
120
119
|
* the request; otherwise, the pending action is cancelled.
|
|
121
120
|
* Defaults to `ClearPolicy.Cancel`.
|
|
122
121
|
*
|
|
123
122
|
* @memberof IAnimationFrame
|
|
124
123
|
*/
|
|
125
|
-
clear(policy?: ClearPolicy): void;
|
|
124
|
+
clear(policy?: Policies.ClearPolicy): void;
|
|
126
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Options for the scheduling APIs.
|
|
128
|
+
*/
|
|
127
129
|
export type Options = {
|
|
128
|
-
schedulePolicy?: SchedulePolicy;
|
|
129
|
-
clearPolicy?: ClearPolicy;
|
|
130
|
+
schedulePolicy?: Policies.SchedulePolicy;
|
|
131
|
+
clearPolicy?: Policies.ClearPolicy;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Options for the hook variants of our scheduling APIs.
|
|
135
|
+
*/
|
|
136
|
+
export type HookOptions = Options & {
|
|
137
|
+
actionPolicy?: Policies.ActionPolicy;
|
|
130
138
|
};
|
|
131
139
|
/**
|
|
132
140
|
* Provides means to request timeouts, intervals, and animation frames, with
|
package/package.json
CHANGED
|
@@ -1,123 +1,520 @@
|
|
|
1
|
-
import {renderHook} from "@testing-library/react-hooks";
|
|
1
|
+
import {renderHook, act} from "@testing-library/react-hooks";
|
|
2
|
+
import {SchedulePolicy, ClearPolicy, ActionPolicy} from "../../util/policies";
|
|
2
3
|
|
|
3
4
|
import {useInterval} from "../use-interval";
|
|
4
5
|
|
|
5
|
-
describe("
|
|
6
|
+
describe("useInterval", () => {
|
|
6
7
|
beforeEach(() => {
|
|
7
8
|
jest.useFakeTimers();
|
|
8
9
|
});
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
jest.restoreAllMocks();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("throws if the action is not a function", () => {
|
|
11
16
|
// Arrange
|
|
12
|
-
const action = jest.fn();
|
|
13
17
|
|
|
14
18
|
// Act
|
|
15
|
-
renderHook(() => useInterval(
|
|
16
|
-
jest.advanceTimersByTime(501);
|
|
19
|
+
const {result} = renderHook(() => useInterval(null as any, 1000));
|
|
17
20
|
|
|
18
21
|
// Assert
|
|
19
|
-
expect(
|
|
22
|
+
expect(result.error).toEqual(Error("Action must be a function"));
|
|
20
23
|
});
|
|
21
24
|
|
|
22
|
-
it("
|
|
25
|
+
it("throws if the period is less than 1", () => {
|
|
23
26
|
// Arrange
|
|
24
|
-
const action = jest.fn();
|
|
25
27
|
|
|
26
28
|
// Act
|
|
27
|
-
renderHook(() => useInterval(
|
|
28
|
-
jest.advanceTimersByTime(1001);
|
|
29
|
+
const {result} = renderHook(() => useInterval(() => {}, 0));
|
|
29
30
|
|
|
30
31
|
// Assert
|
|
31
|
-
expect(
|
|
32
|
+
expect(result.error).toEqual(Error("Interval period must be >= 1"));
|
|
32
33
|
});
|
|
33
34
|
|
|
34
|
-
it("
|
|
35
|
+
it("sets an interval when schedule policy is SchedulePolicy.Immediately", () => {
|
|
35
36
|
// Arrange
|
|
36
|
-
const
|
|
37
|
+
const intervalSpy = jest.spyOn(global, "setInterval");
|
|
37
38
|
|
|
38
39
|
// Act
|
|
39
|
-
|
|
40
|
-
({active}: any) => useInterval(action, 500, active),
|
|
41
|
-
{initialProps: {active: false}},
|
|
42
|
-
);
|
|
43
|
-
rerender({active: true});
|
|
44
|
-
jest.advanceTimersByTime(501);
|
|
40
|
+
renderHook(() => useInterval(() => {}, 1000));
|
|
45
41
|
|
|
46
42
|
// Assert
|
|
43
|
+
expect(intervalSpy).toHaveBeenCalledTimes(1);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should call the action before unmounting when clear policy is Resolve", () => {
|
|
47
|
+
const action = jest.fn();
|
|
48
|
+
const {unmount} = renderHook(() =>
|
|
49
|
+
useInterval(action, 1000, {
|
|
50
|
+
clearPolicy: ClearPolicy.Resolve,
|
|
51
|
+
}),
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
act(() => {
|
|
55
|
+
unmount();
|
|
56
|
+
});
|
|
57
|
+
|
|
47
58
|
expect(action).toHaveBeenCalled();
|
|
48
59
|
});
|
|
49
60
|
|
|
50
|
-
it("should
|
|
61
|
+
it("should call the current action", () => {
|
|
51
62
|
// Arrange
|
|
52
|
-
const
|
|
63
|
+
const action1 = jest.fn();
|
|
64
|
+
const action2 = jest.fn();
|
|
53
65
|
const {rerender} = renderHook(
|
|
54
|
-
({
|
|
55
|
-
{
|
|
66
|
+
({action}: any) => useInterval(action, 500),
|
|
67
|
+
{
|
|
68
|
+
initialProps: {action: action1},
|
|
69
|
+
},
|
|
56
70
|
);
|
|
57
71
|
|
|
58
72
|
// Act
|
|
59
|
-
rerender({
|
|
73
|
+
rerender({action: action2});
|
|
60
74
|
jest.advanceTimersByTime(501);
|
|
61
75
|
|
|
62
76
|
// Assert
|
|
63
|
-
expect(
|
|
77
|
+
expect(action2).toHaveBeenCalledTimes(1);
|
|
64
78
|
});
|
|
65
79
|
|
|
66
|
-
it("should
|
|
80
|
+
it("should only call setInterval once even if action changes", () => {
|
|
67
81
|
// Arrange
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
82
|
+
const intervalSpy = jest.spyOn(global, "setInterval");
|
|
83
|
+
const action1 = jest.fn();
|
|
84
|
+
const action2 = jest.fn();
|
|
71
85
|
const {rerender} = renderHook(
|
|
72
|
-
({
|
|
73
|
-
{
|
|
86
|
+
({action}: any) => useInterval(action, 500),
|
|
87
|
+
{
|
|
88
|
+
initialProps: {action: action1},
|
|
89
|
+
},
|
|
74
90
|
);
|
|
75
|
-
|
|
76
|
-
|
|
91
|
+
|
|
92
|
+
// Act
|
|
93
|
+
rerender({action: action2});
|
|
77
94
|
|
|
78
95
|
// Assert
|
|
79
|
-
expect(
|
|
80
|
-
jest.advanceTimersByTime(1001);
|
|
81
|
-
expect(action).toHaveBeenCalled();
|
|
96
|
+
expect(intervalSpy).toHaveBeenCalledTimes(1);
|
|
82
97
|
});
|
|
83
98
|
|
|
84
|
-
it("should not reset the interval if
|
|
99
|
+
it("should not reset the interval if the action changes", () => {
|
|
85
100
|
// Arrange
|
|
86
101
|
const action1 = jest.fn();
|
|
87
102
|
const action2 = jest.fn();
|
|
88
|
-
const timeoutSpy = jest.spyOn(window, "setTimeout");
|
|
89
|
-
|
|
90
|
-
// Act
|
|
91
103
|
const {rerender} = renderHook(
|
|
92
|
-
({action}: any) => useInterval(action, 500
|
|
93
|
-
{
|
|
104
|
+
({action}: any) => useInterval(action, 500),
|
|
105
|
+
{
|
|
106
|
+
initialProps: {action: action1},
|
|
107
|
+
},
|
|
94
108
|
);
|
|
95
|
-
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
const callCount = timeoutSpy.mock.calls.length;
|
|
109
|
+
|
|
110
|
+
// Act
|
|
111
|
+
jest.advanceTimersByTime(250);
|
|
99
112
|
rerender({action: action2});
|
|
100
|
-
jest.advanceTimersByTime(
|
|
113
|
+
jest.advanceTimersByTime(751);
|
|
101
114
|
|
|
102
115
|
// Assert
|
|
103
|
-
expect(
|
|
116
|
+
expect(action1).not.toHaveBeenCalled();
|
|
117
|
+
expect(action2).toHaveBeenCalledTimes(2);
|
|
104
118
|
});
|
|
105
119
|
|
|
106
|
-
it("should
|
|
120
|
+
it("should reset the interval if the action changes and the action policy is Reset", () => {
|
|
107
121
|
// Arrange
|
|
108
122
|
const action1 = jest.fn();
|
|
109
123
|
const action2 = jest.fn();
|
|
124
|
+
const {rerender} = renderHook(
|
|
125
|
+
({action}: any) =>
|
|
126
|
+
useInterval(action, 500, {actionPolicy: ActionPolicy.Reset}),
|
|
127
|
+
{
|
|
128
|
+
initialProps: {action: action1},
|
|
129
|
+
},
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
// Act
|
|
133
|
+
jest.advanceTimersByTime(250);
|
|
134
|
+
rerender({action: action2});
|
|
135
|
+
jest.advanceTimersByTime(751);
|
|
136
|
+
|
|
137
|
+
// Assert
|
|
138
|
+
expect(action1).not.toHaveBeenCalled();
|
|
139
|
+
expect(action2).toHaveBeenCalledTimes(1);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should use the new interval period after changing it", () => {
|
|
143
|
+
// Arrange
|
|
144
|
+
const action = jest.fn();
|
|
145
|
+
const {rerender} = renderHook(
|
|
146
|
+
({intervalMs}: any) => useInterval(action, intervalMs),
|
|
147
|
+
{
|
|
148
|
+
initialProps: {intervalMs: 500},
|
|
149
|
+
},
|
|
150
|
+
);
|
|
151
|
+
rerender({intervalMs: 1000});
|
|
110
152
|
|
|
111
153
|
// Act
|
|
154
|
+
jest.advanceTimersByTime(1501);
|
|
155
|
+
|
|
156
|
+
// Assert
|
|
157
|
+
expect(action).toHaveBeenCalledTimes(1);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("should restart the interval if intervalMs changes", () => {
|
|
161
|
+
// Arrange
|
|
162
|
+
const intervalSpy = jest.spyOn(global, "setInterval");
|
|
112
163
|
const {rerender} = renderHook(
|
|
113
|
-
({
|
|
114
|
-
{
|
|
164
|
+
({intervalMs}: any) => useInterval(() => {}, intervalMs),
|
|
165
|
+
{
|
|
166
|
+
initialProps: {intervalMs: 500},
|
|
167
|
+
},
|
|
115
168
|
);
|
|
116
|
-
|
|
117
|
-
|
|
169
|
+
|
|
170
|
+
// Act
|
|
171
|
+
rerender({intervalMs: 1000});
|
|
118
172
|
|
|
119
173
|
// Assert
|
|
120
|
-
expect(
|
|
121
|
-
expect(
|
|
174
|
+
expect(intervalSpy).toHaveBeenCalledWith(expect.any(Function), 500);
|
|
175
|
+
expect(intervalSpy).toHaveBeenCalledWith(expect.any(Function), 1000);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe("isSet", () => {
|
|
179
|
+
it("is false when the interval has not been set [SchedulePolicy.OnDemand]", () => {
|
|
180
|
+
// Arrange
|
|
181
|
+
const {result} = renderHook(() =>
|
|
182
|
+
useInterval(() => {}, 1000, {
|
|
183
|
+
schedulePolicy: SchedulePolicy.OnDemand,
|
|
184
|
+
}),
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
// Act
|
|
188
|
+
const isSet = result.current.isSet;
|
|
189
|
+
|
|
190
|
+
// Assert
|
|
191
|
+
expect(isSet).toBeFalsy();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("is true when the interval is active", () => {
|
|
195
|
+
// Arrange
|
|
196
|
+
const {result} = renderHook(() => useInterval(() => {}, 1000));
|
|
197
|
+
act(() => {
|
|
198
|
+
result.current.set();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Act
|
|
202
|
+
const isSet = result.current.isSet;
|
|
203
|
+
|
|
204
|
+
// Assert
|
|
205
|
+
expect(isSet).toBeTruthy();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("is false when the interval is cleared", () => {
|
|
209
|
+
// Arrange
|
|
210
|
+
const {result} = renderHook(() => useInterval(() => {}, 1000));
|
|
211
|
+
act(() => {
|
|
212
|
+
result.current.set();
|
|
213
|
+
result.current.clear();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Act
|
|
217
|
+
const isSet = result.current.isSet;
|
|
218
|
+
|
|
219
|
+
// Assert
|
|
220
|
+
expect(isSet).toBeFalsy();
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe("#set", () => {
|
|
225
|
+
it("should call setInterval", () => {
|
|
226
|
+
// Arrange
|
|
227
|
+
const intervalSpy = jest.spyOn(global, "setInterval");
|
|
228
|
+
const {result} = renderHook(() =>
|
|
229
|
+
useInterval(() => {}, 500, {
|
|
230
|
+
schedulePolicy: SchedulePolicy.OnDemand,
|
|
231
|
+
}),
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
// Act
|
|
235
|
+
act(() => {
|
|
236
|
+
result.current.set();
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Assert
|
|
240
|
+
expect(intervalSpy).toHaveBeenNthCalledWith(
|
|
241
|
+
1,
|
|
242
|
+
expect.any(Function),
|
|
243
|
+
500,
|
|
244
|
+
);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("should invoke setInterval to call the given action", () => {
|
|
248
|
+
// Arrange
|
|
249
|
+
const intervalSpy = jest.spyOn(global, "setInterval");
|
|
250
|
+
const action = jest.fn();
|
|
251
|
+
const {result} = renderHook(() =>
|
|
252
|
+
useInterval(action, 500, {
|
|
253
|
+
schedulePolicy: SchedulePolicy.OnDemand,
|
|
254
|
+
}),
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
act(() => {
|
|
258
|
+
result.current.set();
|
|
259
|
+
});
|
|
260
|
+
const scheduledAction = intervalSpy.mock.calls[0][0];
|
|
261
|
+
|
|
262
|
+
// Act
|
|
263
|
+
scheduledAction();
|
|
264
|
+
|
|
265
|
+
// Assert
|
|
266
|
+
expect(action).toHaveBeenCalledTimes(1);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("should clear the active interval", () => {
|
|
270
|
+
// Arrange
|
|
271
|
+
const action = jest.fn();
|
|
272
|
+
const {result} = renderHook(() =>
|
|
273
|
+
useInterval(action, 500, {
|
|
274
|
+
schedulePolicy: SchedulePolicy.OnDemand,
|
|
275
|
+
}),
|
|
276
|
+
);
|
|
277
|
+
act(() => {
|
|
278
|
+
result.current.set();
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// Act
|
|
282
|
+
act(() => {
|
|
283
|
+
result.current.set();
|
|
284
|
+
jest.advanceTimersByTime(501);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Assert
|
|
288
|
+
expect(action).toHaveBeenCalledTimes(1);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it("should set an interval that stays active while not cleared", () => {
|
|
292
|
+
// Arrange
|
|
293
|
+
const action = jest.fn();
|
|
294
|
+
const {result} = renderHook(() =>
|
|
295
|
+
useInterval(action, 500, {
|
|
296
|
+
schedulePolicy: SchedulePolicy.OnDemand,
|
|
297
|
+
}),
|
|
298
|
+
);
|
|
299
|
+
act(() => {
|
|
300
|
+
result.current.set();
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Act
|
|
304
|
+
act(() => {
|
|
305
|
+
jest.advanceTimersByTime(1501);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
// Assert
|
|
309
|
+
expect(action).toHaveBeenCalledTimes(3);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it("should continue to be set after calling it multiple times", () => {
|
|
313
|
+
// Arrange
|
|
314
|
+
const action = jest.fn();
|
|
315
|
+
const {result} = renderHook(() =>
|
|
316
|
+
useInterval(action, 500, {
|
|
317
|
+
schedulePolicy: SchedulePolicy.OnDemand,
|
|
318
|
+
}),
|
|
319
|
+
);
|
|
320
|
+
act(() => {
|
|
321
|
+
result.current.set();
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// Act
|
|
325
|
+
act(() => {
|
|
326
|
+
result.current.set();
|
|
327
|
+
});
|
|
328
|
+
act(() => {
|
|
329
|
+
jest.advanceTimersByTime(501);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// Assert
|
|
333
|
+
expect(action).toHaveBeenCalled();
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it("should set the interval after clearing it", () => {
|
|
337
|
+
// Arrange
|
|
338
|
+
const action = jest.fn();
|
|
339
|
+
const {result} = renderHook(() =>
|
|
340
|
+
useInterval(action, 500, {
|
|
341
|
+
schedulePolicy: SchedulePolicy.OnDemand,
|
|
342
|
+
}),
|
|
343
|
+
);
|
|
344
|
+
act(() => {
|
|
345
|
+
result.current.clear();
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Act
|
|
349
|
+
act(() => {
|
|
350
|
+
result.current.set();
|
|
351
|
+
});
|
|
352
|
+
act(() => {
|
|
353
|
+
jest.advanceTimersByTime(501);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
// Assert
|
|
357
|
+
expect(action).toHaveBeenCalled();
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it("should reset the inteval after calling set() again", () => {
|
|
361
|
+
// Arrange
|
|
362
|
+
const action = jest.fn();
|
|
363
|
+
const {result} = renderHook(() =>
|
|
364
|
+
useInterval(action, 750, {
|
|
365
|
+
schedulePolicy: SchedulePolicy.OnDemand,
|
|
366
|
+
}),
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
// Act
|
|
370
|
+
act(() => {
|
|
371
|
+
result.current.set();
|
|
372
|
+
jest.advanceTimersByTime(501);
|
|
373
|
+
result.current.set();
|
|
374
|
+
jest.advanceTimersByTime(501);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// Assert
|
|
378
|
+
expect(action).not.toHaveBeenCalled();
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it("shouldn't throw an error if called after the component unmounted", () => {
|
|
382
|
+
const action = jest.fn();
|
|
383
|
+
const {result, unmount} = renderHook(() =>
|
|
384
|
+
useInterval(action, 500),
|
|
385
|
+
);
|
|
386
|
+
act(() => {
|
|
387
|
+
unmount();
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// Act
|
|
391
|
+
const underTest = () => result.current.set();
|
|
392
|
+
|
|
393
|
+
// Assert
|
|
394
|
+
expect(underTest).not.toThrow();
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
describe("#clear", () => {
|
|
399
|
+
it("should clear an active interval", () => {
|
|
400
|
+
// Arrange
|
|
401
|
+
const action = jest.fn();
|
|
402
|
+
const {result} = renderHook(() => useInterval(action, 500));
|
|
403
|
+
act(() => {
|
|
404
|
+
result.current.set();
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// Act
|
|
408
|
+
act(() => {
|
|
409
|
+
result.current.clear();
|
|
410
|
+
});
|
|
411
|
+
act(() => {
|
|
412
|
+
jest.advanceTimersByTime(501);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
// Assert
|
|
416
|
+
expect(action).not.toHaveBeenCalled();
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
it("should invoke the action if clear policy is ClearPolicy.Resolve", () => {
|
|
420
|
+
// Arrange
|
|
421
|
+
const action = jest.fn();
|
|
422
|
+
const {result} = renderHook(() => useInterval(action, 500));
|
|
423
|
+
act(() => {
|
|
424
|
+
result.current.set();
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// Act
|
|
428
|
+
act(() => {
|
|
429
|
+
result.current.clear(ClearPolicy.Resolve);
|
|
430
|
+
});
|
|
431
|
+
act(() => {
|
|
432
|
+
jest.advanceTimersByTime(501);
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
// Assert
|
|
436
|
+
expect(action).toHaveBeenCalledTimes(1);
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
it("should not invoke the action if clear policy is ClearPolicy.Cancel", () => {
|
|
440
|
+
// Arrange
|
|
441
|
+
const action = jest.fn();
|
|
442
|
+
const {result} = renderHook(() =>
|
|
443
|
+
useInterval(action, 500, {
|
|
444
|
+
schedulePolicy: SchedulePolicy.Immediately,
|
|
445
|
+
}),
|
|
446
|
+
);
|
|
447
|
+
act(() => {
|
|
448
|
+
result.current.set();
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
// Act
|
|
452
|
+
act(() => {
|
|
453
|
+
result.current.clear(ClearPolicy.Cancel);
|
|
454
|
+
});
|
|
455
|
+
act(() => {
|
|
456
|
+
jest.advanceTimersByTime(501);
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
// Assert
|
|
460
|
+
expect(action).not.toHaveBeenCalled();
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it("should not invoke the action if interval is inactive and clear policy is ClearPolicy.Resolve", () => {
|
|
464
|
+
// Arrange
|
|
465
|
+
const action = jest.fn();
|
|
466
|
+
const {result} = renderHook(() =>
|
|
467
|
+
useInterval(action, 500, {
|
|
468
|
+
schedulePolicy: SchedulePolicy.OnDemand,
|
|
469
|
+
}),
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
// Act
|
|
473
|
+
act(() => {
|
|
474
|
+
result.current.clear(ClearPolicy.Resolve);
|
|
475
|
+
jest.advanceTimersByTime(501);
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
// Assert
|
|
479
|
+
expect(action).not.toHaveBeenCalled();
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
it("should not call the action on unmount if the interval is not running when the clearPolicy is ClearPolicy.Resolve", async () => {
|
|
483
|
+
// Arrange
|
|
484
|
+
const action = jest.fn();
|
|
485
|
+
const {result, unmount} = renderHook(() =>
|
|
486
|
+
useInterval(action, 500, {
|
|
487
|
+
clearPolicy: ClearPolicy.Resolve,
|
|
488
|
+
}),
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
// Act
|
|
492
|
+
act(() => {
|
|
493
|
+
result.current.clear();
|
|
494
|
+
});
|
|
495
|
+
act(() => {
|
|
496
|
+
unmount();
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
// Assert
|
|
500
|
+
expect(action).not.toHaveBeenCalled();
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
it("should not error if calling clear() after unmounting", () => {
|
|
504
|
+
// Arrange
|
|
505
|
+
const action = jest.fn();
|
|
506
|
+
const {result, unmount} = renderHook(() =>
|
|
507
|
+
useInterval(action, 500),
|
|
508
|
+
);
|
|
509
|
+
act(() => {
|
|
510
|
+
unmount();
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// Act
|
|
514
|
+
const underTest = () => result.current.clear();
|
|
515
|
+
|
|
516
|
+
// Assert
|
|
517
|
+
expect(underTest).not.toThrow();
|
|
518
|
+
});
|
|
122
519
|
});
|
|
123
520
|
});
|