1 | interface FrameCallback {
|
2 | (time: number): any;
|
3 | }
|
4 |
|
5 | export default class AnimationFrame {
|
6 | private isUsingMockAnimationFrame = false;
|
7 | private queued: {[key: number]: FrameCallback} = {};
|
8 | private originalRequestAnimationFrame: any;
|
9 | private originalCancelAnimationFrame: any;
|
10 | private currentAnimationFrame = 0;
|
11 |
|
12 | mock() {
|
13 | if (this.isUsingMockAnimationFrame) {
|
14 | throw new Error(
|
15 | 'The animation frame is already mocked, but you tried to mock it again.',
|
16 | );
|
17 | }
|
18 |
|
19 | this.isUsingMockAnimationFrame = true;
|
20 |
|
21 | this.originalRequestAnimationFrame = window.requestAnimationFrame;
|
22 | window.requestAnimationFrame = this.requestAnimationFrame;
|
23 |
|
24 | this.originalCancelAnimationFrame = window.cancelAnimationFrame;
|
25 | window.cancelAnimationFrame = this.cancelAnimationFrame;
|
26 | }
|
27 |
|
28 | restore() {
|
29 | if (!this.isUsingMockAnimationFrame) {
|
30 | throw new Error(
|
31 | 'The animation frame is already real, but you tried to restore it again.',
|
32 | );
|
33 | }
|
34 |
|
35 | this.isUsingMockAnimationFrame = false;
|
36 |
|
37 | window.requestAnimationFrame = this.originalRequestAnimationFrame;
|
38 | window.cancelAnimationFrame = this.originalCancelAnimationFrame;
|
39 | }
|
40 |
|
41 | isMocked() {
|
42 | return this.isUsingMockAnimationFrame;
|
43 | }
|
44 |
|
45 | runFrame() {
|
46 | this.ensureAnimationFrameIsMock();
|
47 |
|
48 |
|
49 | Object.keys(this.queued).forEach((frame: any) => {
|
50 | const callback = this.queued[frame];
|
51 | delete this.queued[frame];
|
52 | callback(Date.now());
|
53 | });
|
54 | }
|
55 |
|
56 | private requestAnimationFrame = (callback: FrameCallback): number => {
|
57 | this.currentAnimationFrame += 1;
|
58 | this.queued[this.currentAnimationFrame] = callback;
|
59 | return this.currentAnimationFrame;
|
60 | };
|
61 |
|
62 | private cancelAnimationFrame = (frame: number) => {
|
63 | delete this.queued[frame];
|
64 | };
|
65 |
|
66 | private ensureAnimationFrameIsMock() {
|
67 | if (!this.isUsingMockAnimationFrame) {
|
68 | throw new Error(
|
69 | 'You must call animationFrame.mock() before interacting with the mock request- or cancel- AnimationFrame methods.',
|
70 | );
|
71 | }
|
72 | }
|
73 | }
|