Skip to content

Commit 3e412ad

Browse files
authored
Merge pull request #42 from adjsky/master
animation.id, animation.cancel
2 parents 6887572 + 1e2b75b commit 3e412ad

File tree

4 files changed

+98
-30
lines changed

4 files changed

+98
-30
lines changed

src/mocks/web-animations-api/Animation.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { mockKeyframeEffect } from './KeyframeEffect';
22
import { mockAnimationPlaybackEvent } from './AnimationPlaybackEvent';
33
import { mockDocumentTimeline } from './DocumentTimeline';
44
import { getEasingFunctionFromString } from './easingFunctions';
5+
import { addAnimation, removeAnimation } from './elementAnimations';
56

67
type ActiveAnimationTimeline = AnimationTimeline & {
78
currentTime: NonNullable<AnimationTimeline['currentTime']>;
@@ -136,15 +137,33 @@ class MockedAnimation extends EventTarget implements Animation {
136137
return null;
137138
}
138139

140+
#addToTarget() {
141+
if (!this.#hasKeyframeEffect() || this.effect.target == null) {
142+
return;
143+
}
144+
145+
addAnimation(this.effect.target, this);
146+
}
147+
148+
#removeFromTarget() {
149+
if (!this.#hasKeyframeEffect() || this.effect.target == null) {
150+
return;
151+
}
152+
153+
removeAnimation(this.effect.target, this);
154+
}
155+
139156
#getNewFinishedPromise() {
140157
this.#promiseStates.finished = 'pending';
141158

142159
return new Promise<Animation>((resolve, reject) => {
143160
this.#resolvers.finished.resolve = (animation) => {
161+
this.#removeFromTarget();
144162
this.#promiseStates.finished = 'resolved';
145163
resolve(animation);
146164
};
147165
this.#resolvers.finished.reject = (error) => {
166+
this.#removeFromTarget();
148167
this.#promiseStates.finished = 'rejected';
149168
reject(error);
150169
};
@@ -153,6 +172,7 @@ class MockedAnimation extends EventTarget implements Animation {
153172

154173
#getNewReadyPromise() {
155174
this.#promiseStates.ready = 'pending';
175+
this.#addToTarget();
156176

157177
return new Promise<Animation>((resolve, reject) => {
158178
this.#resolvers.ready.resolve = (animation) => {

src/mocks/web-animations-api/__tests__/index.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,40 @@ describe('Animations API', () => {
3535
expect(element.getAnimations().length).toBe(0);
3636
expect(document.getAnimations().length).toBe(0);
3737
});
38+
39+
it('should add/delete an animation to/from element and document lists if created manually', async () => {
40+
const element = document.createElement('div');
41+
42+
const keyframeEffect = new KeyframeEffect(element, { opacity: 0 }, 100);
43+
const animation = new Animation(keyframeEffect);
44+
animation.play();
45+
46+
expect(element.getAnimations().length).toBe(1);
47+
expect(element.getAnimations()).toContain(animation);
48+
expect(document.getAnimations().length).toBe(1);
49+
expect(document.getAnimations()).toContain(animation);
50+
51+
await animation.finished;
52+
53+
expect(element.getAnimations().length).toBe(0);
54+
expect(document.getAnimations().length).toBe(0);
55+
});
56+
57+
it('should read id from options and attach it to the returned animation', async () => {
58+
const element = document.createElement('div');
59+
const testId = 'testId';
60+
61+
const animation = element.animate({ opacity: 0 }, { id: testId });
62+
expect(animation.id).toBe(testId);
63+
});
64+
65+
it('should remove an animation from element if the animation was cancelled', () => {
66+
const element = document.createElement('div');
67+
68+
const animation = element.animate({ opacity: 0 }, 1000);
69+
expect(element.getAnimations().length).toBe(1);
70+
71+
animation.cancel();
72+
expect(element.getAnimations().length).toBe(0);
73+
});
3874
});
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const elementAnimations = new Map<Element, Animation[]>();
2+
3+
export function removeAnimation(element: Element, animation: Animation) {
4+
const animations = elementAnimations.get(element);
5+
6+
if (animations) {
7+
const index = animations.indexOf(animation);
8+
9+
if (index !== -1) {
10+
animations.splice(index, 1);
11+
}
12+
}
13+
}
14+
15+
export function addAnimation(element: Element, animation: Animation) {
16+
const animations = elementAnimations.get(element) ?? [];
17+
animations.push(animation);
18+
19+
elementAnimations.set(element, animations);
20+
}
21+
22+
export function getAnimations(this: Element) {
23+
return elementAnimations.get(this) ?? [];
24+
}
25+
26+
export function getAllAnimations() {
27+
return Array.from(elementAnimations.values()).flat();
28+
}
29+
30+
export function clearAnimations() {
31+
elementAnimations.clear();
32+
}

src/mocks/web-animations-api/index.ts

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,27 @@
11
import { mockAnimation } from './Animation';
2-
3-
const elementAnimations = new Map<Element, Animation[]>();
2+
import {
3+
getAnimations,
4+
getAllAnimations,
5+
clearAnimations,
6+
} from './elementAnimations';
47

58
function animate(
69
this: Element,
710
keyframes: Keyframe[],
8-
options?: number | KeyframeEffectOptions
11+
options?: number | KeyframeAnimationOptions
912
) {
1013
const keyframeEffect = new KeyframeEffect(this, keyframes, options);
1114

1215
const animation = new Animation(keyframeEffect);
13-
14-
const animations = elementAnimations.get(this) ?? [];
15-
16-
animations.push(animation);
17-
18-
elementAnimations.set(this, animations);
19-
20-
animation.addEventListener('finish', () => {
21-
const animations = elementAnimations.get(this);
22-
23-
if (animations) {
24-
const index = animations.indexOf(animation);
25-
26-
if (index !== -1) {
27-
animations.splice(index, 1);
28-
}
29-
}
30-
});
16+
if (typeof options == 'object' && options.id) {
17+
animation.id = options.id;
18+
}
3119

3220
animation.play();
3321

3422
return animation;
3523
}
3624

37-
function getAnimations(this: Element) {
38-
return elementAnimations.get(this) ?? [];
39-
}
40-
41-
function getAllAnimations() {
42-
return Array.from(elementAnimations.values()).flat();
43-
}
44-
4525
function mockAnimationsApi() {
4626
const savedAnimate = Element.prototype.animate;
4727
const savedGetAnimations = Element.prototype.getAnimations;
@@ -69,7 +49,7 @@ function mockAnimationsApi() {
6949
});
7050

7151
afterEach(() => {
72-
elementAnimations.clear();
52+
clearAnimations();
7353
});
7454

7555
afterAll(() => {

0 commit comments

Comments
 (0)