@khanacademy/wonder-blocks-timing 4.0.1 → 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 (50) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/components/with-action-scheduler.d.ts +4 -1
  3. package/dist/es/index.js +93 -105
  4. package/dist/hooks/use-interval.d.ts +27 -5
  5. package/dist/hooks/use-timeout.d.ts +27 -5
  6. package/dist/index.d.ts +2 -5
  7. package/dist/index.js +92 -105
  8. package/dist/util/animation-frame.d.ts +6 -6
  9. package/dist/util/interval.d.ts +8 -8
  10. package/dist/util/policies.d.ts +12 -8
  11. package/dist/util/timeout.d.ts +8 -7
  12. package/dist/util/types.d.ts +18 -10
  13. package/package.json +3 -3
  14. package/src/components/with-action-scheduler.tsx +9 -1
  15. package/src/hooks/__tests__/use-interval.test.ts +453 -56
  16. package/src/hooks/__tests__/use-timeout.test.ts +412 -58
  17. package/src/hooks/use-interval.ts +90 -25
  18. package/src/hooks/use-timeout.ts +90 -25
  19. package/src/index.ts +4 -14
  20. package/src/util/__tests__/animation-frame.test.ts +9 -10
  21. package/src/util/animation-frame.ts +12 -16
  22. package/src/util/interval.ts +13 -18
  23. package/src/util/policies.ts +13 -8
  24. package/src/util/timeout.ts +14 -18
  25. package/src/util/types.ts +19 -11
  26. package/tsconfig-build.json +2 -4
  27. package/tsconfig-build.tsbuildinfo +1 -1
  28. package/dist/components/action-scheduler-provider.js.flow +0 -33
  29. package/dist/components/with-action-scheduler.js.flow +0 -22
  30. package/dist/hooks/internal/use-updating-ref.d.ts +0 -13
  31. package/dist/hooks/internal/use-updating-ref.js.flow +0 -20
  32. package/dist/hooks/use-interval.js.flow +0 -17
  33. package/dist/hooks/use-scheduled-interval.d.ts +0 -2
  34. package/dist/hooks/use-scheduled-interval.js.flow +0 -12
  35. package/dist/hooks/use-scheduled-timeout.d.ts +0 -2
  36. package/dist/hooks/use-scheduled-timeout.js.flow +0 -12
  37. package/dist/hooks/use-timeout.js.flow +0 -17
  38. package/dist/index.js.flow +0 -31
  39. package/dist/util/action-scheduler.js.flow +0 -38
  40. package/dist/util/animation-frame.js.flow +0 -70
  41. package/dist/util/interval.js.flow +0 -69
  42. package/dist/util/policies.js.flow +0 -14
  43. package/dist/util/timeout.js.flow +0 -71
  44. package/dist/util/types.js.flow +0 -232
  45. package/dist/util/types.typestest.js.flow +0 -6
  46. package/src/hooks/__tests__/use-scheduled-interval.test.ts +0 -460
  47. package/src/hooks/__tests__/use-scheduled-timeout.test.ts +0 -478
  48. package/src/hooks/internal/use-updating-ref.ts +0 -23
  49. package/src/hooks/use-scheduled-interval.ts +0 -72
  50. package/src/hooks/use-scheduled-timeout.ts +0 -79
@@ -1,460 +0,0 @@
1
- import {renderHook, act} from "@testing-library/react-hooks";
2
- import {SchedulePolicy, ClearPolicy} from "../../util/policies";
3
-
4
- import {useScheduledInterval} from "../use-scheduled-interval";
5
-
6
- describe("useScheduledInterval", () => {
7
- beforeEach(() => {
8
- jest.useFakeTimers();
9
- });
10
-
11
- afterEach(() => {
12
- jest.restoreAllMocks();
13
- });
14
-
15
- it("throws if the action is not a function", () => {
16
- // Arrange
17
-
18
- // Act
19
- const {result} = renderHook(() =>
20
- useScheduledInterval(null as any, 1000),
21
- );
22
-
23
- // Assert
24
- expect(result.error).toEqual(Error("Action must be a function"));
25
- });
26
-
27
- it("throws if the period is less than 1", () => {
28
- // Arrange
29
-
30
- // Act
31
- const {result} = renderHook(() => useScheduledInterval(() => {}, 0));
32
-
33
- // Assert
34
- expect(result.error).toEqual(Error("Interval period must be >= 1"));
35
- });
36
-
37
- it("sets an interval when schedule policy is SchedulePolicy.Immediately", () => {
38
- // Arrange
39
- const intervalSpy = jest.spyOn(global, "setInterval");
40
-
41
- // Act
42
- renderHook(() => useScheduledInterval(() => {}, 1000));
43
-
44
- // Assert
45
- expect(intervalSpy).toHaveBeenCalledTimes(1);
46
- });
47
-
48
- it("should call the action before unmounting", () => {
49
- const action = jest.fn();
50
- const {unmount} = renderHook(() =>
51
- useScheduledInterval(action, 1000, {
52
- clearPolicy: ClearPolicy.Resolve,
53
- }),
54
- );
55
-
56
- act(() => {
57
- unmount();
58
- });
59
-
60
- expect(action).toHaveBeenCalled();
61
- });
62
-
63
- it("should call the current action", () => {
64
- // Arrange
65
- const action1 = jest.fn();
66
- const action2 = jest.fn();
67
- const {rerender} = renderHook(
68
- ({action}: any) => useScheduledInterval(action, 500),
69
- {
70
- initialProps: {action: action1},
71
- },
72
- );
73
-
74
- // Act
75
- rerender({action: action2});
76
- jest.advanceTimersByTime(501);
77
-
78
- // Assert
79
- expect(action2).toHaveBeenCalledTimes(1);
80
- });
81
-
82
- it("should only call setInterval once even if action changes", () => {
83
- // Arrange
84
- const intervalSpy = jest.spyOn(global, "setInterval");
85
- const action1 = jest.fn();
86
- const action2 = jest.fn();
87
- const {rerender} = renderHook(
88
- ({action}: any) => useScheduledInterval(action, 500),
89
- {
90
- initialProps: {action: action1},
91
- },
92
- );
93
-
94
- // Act
95
- rerender({action: action2});
96
-
97
- // Assert
98
- expect(intervalSpy).toHaveBeenCalledTimes(1);
99
- });
100
-
101
- it("should use the new interval after changing it", () => {
102
- // Arrange
103
- const action = jest.fn();
104
- const {rerender} = renderHook(
105
- ({intervalMs}: any) => useScheduledInterval(action, intervalMs),
106
- {
107
- initialProps: {intervalMs: 500},
108
- },
109
- );
110
- rerender({intervalMs: 1000});
111
-
112
- // Act
113
- jest.advanceTimersByTime(1501);
114
-
115
- // Assert
116
- expect(action).toHaveBeenCalledTimes(1);
117
- });
118
-
119
- it("should restart the interval if intervalMs changes", () => {
120
- // Arrange
121
- const intervalSpy = jest.spyOn(global, "setInterval");
122
- const {rerender} = renderHook(
123
- ({intervalMs}: any) => useScheduledInterval(() => {}, intervalMs),
124
- {
125
- initialProps: {intervalMs: 500},
126
- },
127
- );
128
-
129
- // Act
130
- rerender({intervalMs: 1000});
131
-
132
- // Assert
133
- expect(intervalSpy).toHaveBeenCalledWith(expect.any(Function), 500);
134
- expect(intervalSpy).toHaveBeenCalledWith(expect.any(Function), 1000);
135
- });
136
-
137
- describe("isSet", () => {
138
- it("is false when the interval has not been set [SchedulePolicy.OnDemand]", () => {
139
- // Arrange
140
- const {result} = renderHook(() =>
141
- useScheduledInterval(() => {}, 1000, {
142
- schedulePolicy: SchedulePolicy.OnDemand,
143
- }),
144
- );
145
-
146
- // Act
147
- const isSet = result.current.isSet;
148
-
149
- // Assert
150
- expect(isSet).toBeFalsy();
151
- });
152
-
153
- it("is true when the interval is active", () => {
154
- // Arrange
155
- const {result} = renderHook(() =>
156
- useScheduledInterval(() => {}, 1000),
157
- );
158
- act(() => {
159
- result.current.set();
160
- });
161
-
162
- // Act
163
- const isSet = result.current.isSet;
164
-
165
- // Assert
166
- expect(isSet).toBeTruthy();
167
- });
168
-
169
- it("is false when the interval is cleared", () => {
170
- // Arrange
171
- const {result} = renderHook(() =>
172
- useScheduledInterval(() => {}, 1000),
173
- );
174
- act(() => {
175
- result.current.set();
176
- result.current.clear();
177
- });
178
-
179
- // Act
180
- const isSet = result.current.isSet;
181
-
182
- // Assert
183
- expect(isSet).toBeFalsy();
184
- });
185
- });
186
-
187
- describe("#set", () => {
188
- it("should call setInterval", () => {
189
- // Arrange
190
- const intervalSpy = jest.spyOn(global, "setInterval");
191
- const {result} = renderHook(() =>
192
- useScheduledInterval(() => {}, 500, {
193
- schedulePolicy: SchedulePolicy.OnDemand,
194
- }),
195
- );
196
-
197
- // Act
198
- act(() => {
199
- result.current.set();
200
- });
201
-
202
- // Assert
203
- expect(intervalSpy).toHaveBeenNthCalledWith(
204
- 1,
205
- expect.any(Function),
206
- 500,
207
- );
208
- });
209
-
210
- it("should invoke setInterval to call the given action", () => {
211
- // Arrange
212
- const intervalSpy = jest.spyOn(global, "setInterval");
213
- const action = jest.fn();
214
- const {result} = renderHook(() =>
215
- useScheduledInterval(action, 500, {
216
- schedulePolicy: SchedulePolicy.OnDemand,
217
- }),
218
- );
219
-
220
- act(() => {
221
- result.current.set();
222
- });
223
- const scheduledAction = intervalSpy.mock.calls[0][0];
224
-
225
- // Act
226
- scheduledAction();
227
-
228
- // Assert
229
- expect(action).toHaveBeenCalledTimes(1);
230
- });
231
-
232
- it("should clear the active interval", () => {
233
- // Arrange
234
- const action = jest.fn();
235
- const {result} = renderHook(() =>
236
- useScheduledInterval(action, 500, {
237
- schedulePolicy: SchedulePolicy.OnDemand,
238
- }),
239
- );
240
- act(() => {
241
- result.current.set();
242
- });
243
-
244
- // Act
245
- act(() => {
246
- result.current.set();
247
- jest.advanceTimersByTime(501);
248
- });
249
-
250
- // Assert
251
- expect(action).toHaveBeenCalledTimes(1);
252
- });
253
-
254
- it("should set an interval that stays active while not cleared", () => {
255
- // Arrange
256
- const action = jest.fn();
257
- const {result} = renderHook(() =>
258
- useScheduledInterval(action, 500),
259
- );
260
- act(() => {
261
- result.current.set();
262
- });
263
-
264
- // Act
265
- act(() => {
266
- jest.advanceTimersByTime(1501);
267
- });
268
-
269
- // Assert
270
- expect(action).toHaveBeenCalledTimes(3);
271
- });
272
-
273
- it("should continue to be set after calling it multiple times", () => {
274
- // Arrange
275
- const action = jest.fn();
276
- const {result} = renderHook(() =>
277
- useScheduledInterval(action, 500),
278
- );
279
- act(() => {
280
- result.current.set();
281
- });
282
-
283
- // Act
284
- act(() => {
285
- result.current.set();
286
- });
287
- act(() => {
288
- jest.advanceTimersByTime(501);
289
- });
290
-
291
- // Assert
292
- expect(action).toHaveBeenCalled();
293
- });
294
-
295
- it("should set the timeout after clearing it", () => {
296
- // Arrange
297
- const action = jest.fn();
298
- const {result} = renderHook(() =>
299
- useScheduledInterval(action, 500),
300
- );
301
- act(() => {
302
- result.current.clear();
303
- });
304
-
305
- // Act
306
- act(() => {
307
- result.current.set();
308
- });
309
- act(() => {
310
- jest.advanceTimersByTime(501);
311
- });
312
-
313
- // Assert
314
- expect(action).toHaveBeenCalled();
315
- });
316
-
317
- it("shouldn't throw an error if called after the component unmounted", () => {
318
- const action = jest.fn();
319
- const {result, unmount} = renderHook(() =>
320
- useScheduledInterval(action, 500),
321
- );
322
- act(() => {
323
- unmount();
324
- });
325
-
326
- // Act
327
- const underTest = () => result.current.set();
328
-
329
- // Assert
330
- expect(underTest).not.toThrow();
331
- });
332
- });
333
-
334
- describe("#clear", () => {
335
- it("should clear an active interval", () => {
336
- // Arrange
337
- const action = jest.fn();
338
- const {result} = renderHook(() =>
339
- useScheduledInterval(action, 500),
340
- );
341
- act(() => {
342
- result.current.set();
343
- });
344
-
345
- // Act
346
- act(() => {
347
- result.current.clear();
348
- });
349
- act(() => {
350
- jest.advanceTimersByTime(501);
351
- });
352
-
353
- // Assert
354
- expect(action).not.toHaveBeenCalled();
355
- });
356
-
357
- it("should invoke the action if clear policy is ClearPolicy.Resolve", () => {
358
- // Arrange
359
- const action = jest.fn();
360
- const {result} = renderHook(() =>
361
- useScheduledInterval(action, 500),
362
- );
363
- act(() => {
364
- result.current.set();
365
- });
366
-
367
- // Act
368
- act(() => {
369
- result.current.clear(ClearPolicy.Resolve);
370
- });
371
- act(() => {
372
- jest.advanceTimersByTime(501);
373
- });
374
-
375
- // Assert
376
- expect(action).toHaveBeenCalledTimes(1);
377
- });
378
-
379
- it("should not invoke the action if clear policy is ClearPolicy.Cancel", () => {
380
- // Arrange
381
- const action = jest.fn();
382
- const {result} = renderHook(() =>
383
- useScheduledInterval(action, 500, {
384
- schedulePolicy: SchedulePolicy.Immediately,
385
- }),
386
- );
387
- act(() => {
388
- result.current.set();
389
- });
390
-
391
- // Act
392
- act(() => {
393
- result.current.clear(ClearPolicy.Cancel);
394
- });
395
- act(() => {
396
- jest.advanceTimersByTime(501);
397
- });
398
-
399
- // Assert
400
- expect(action).not.toHaveBeenCalled();
401
- });
402
-
403
- it("should not invoke the action if interval is inactive and clear policy is ClearPolicy.Resolve", () => {
404
- // Arrange
405
- const action = jest.fn();
406
- const {result} = renderHook(() =>
407
- useScheduledInterval(action, 500, {
408
- schedulePolicy: SchedulePolicy.OnDemand,
409
- }),
410
- );
411
-
412
- // Act
413
- act(() => {
414
- result.current.clear(ClearPolicy.Resolve);
415
- jest.advanceTimersByTime(501);
416
- });
417
-
418
- // Assert
419
- expect(action).not.toHaveBeenCalled();
420
- });
421
-
422
- it("should not call the action again on unmount if it's already been cleared", () => {
423
- // Arrange
424
- const action = jest.fn();
425
- const {result, unmount} = renderHook(() =>
426
- useScheduledInterval(action, 500, {
427
- clearPolicy: ClearPolicy.Resolve,
428
- }),
429
- );
430
-
431
- // Act
432
- act(() => {
433
- result.current.clear();
434
- });
435
- act(() => {
436
- unmount();
437
- });
438
-
439
- // Assert
440
- expect(action).toHaveBeenCalledTimes(1);
441
- });
442
-
443
- it("should not error if calling clear() after unmounting", () => {
444
- // Arrange
445
- const action = jest.fn();
446
- const {result, unmount} = renderHook(() =>
447
- useScheduledInterval(action, 500),
448
- );
449
- act(() => {
450
- unmount();
451
- });
452
-
453
- // Act
454
- const underTest = () => result.current.clear();
455
-
456
- // Assert
457
- expect(underTest).not.toThrow();
458
- });
459
- });
460
- });