[Web Animations] Expose Web Animations CSS integration as an experimental feature
[WebKit-https.git] / LayoutTests / webanimations / css-animations.html
1 <!DOCTYPE html><!-- webkit-test-runner [ enableWebAnimationsCSSIntegration=true ] -->
2 <meta charset=utf-8>
3 <title>CSS Animations</title>
4 <style type="text/css" media="screen">
5
6 @keyframes animation {
7     from { left: 50px; }
8     to { left: 100px; }
9 }
10
11 @keyframes animation-top {
12     from { top: 50px; }
13     to { top: 100px; }
14 }
15
16 </style>
17 <body>
18 <script src="../resources/testharness.js"></script>
19 <script src="../resources/testharnessreport.js"></script>
20 <script>
21
22 'use strict';
23
24 function targetTest(testCallback, description)
25 {
26     test(() => {
27         const target = document.body.appendChild(document.createElement("div"));
28         testCallback(target);
29         target.remove();
30     }, description);
31 }
32
33 targetTest(target => {
34     assert_array_equals(target.getAnimations(), [], "An element should not have any animations initially.");
35
36     target.style.animationDelay = "-3s";
37     target.style.animationDuration = "2s";
38     target.style.animationTimingFunction = "linear";
39     target.style.animationFillMode = "forwards";
40     target.style.animationDirection = "alternate";
41     target.style.animationIterationCount = "2";
42     target.style.animationName = "animation";
43
44     const animation = target.getAnimations()[0];
45     assert_true(animation instanceof Animation, "The animation is an Animation.");
46     assert_true(animation instanceof CSSAnimation, "The animation is a CSSAnimation.");
47     assert_equals(animation.timeline, target.ownerDocument.timeline, "The animation's timeline is set to the element's document timeline.");
48     assert_equals(animation.playState, "running", "The animation is running as soon as it's created.");
49     assert_equals(animation.animationName, "animation", "The animation's animationName is set.");
50
51     const effect = animation.effect;
52     assert_true(effect instanceof KeyframeEffectReadOnly, "The animation's effect is a KeyframeEffectReadOnly.");
53     assert_false(effect instanceof KeyframeEffect, "The animation's effect is not a KeyframeEffect.");
54     assert_equals(effect.target, target, "The animation's effect is targeting the target.");
55
56     const timing = animation.effect.timing;
57     assert_equals(timing.fill, "forwards", "The animation's fill property matches the animation-fill-mode property.");
58     assert_equals(timing.delay, -3000, "The animation's delay property matches the animation-delay property.");
59     assert_equals(timing.duration, 2000, "The animation's duration property matches the animation-duration property.");
60     assert_equals(timing.iterations, 2, "The animation's iterations property matches the animation-iteration-count property.");
61     assert_equals(timing.direction, "alternate", "The animation's direction property matches the animation-direction property.");
62
63     const computedTiming = animation.effect.getComputedTiming();
64     assert_equals(computedTiming.activeDuration, 4000, "The animations's computed timing activeDuration property matches the properties set by CSS");
65     assert_equals(computedTiming.currentIteration, 1, "The animations's computed timing currentIteration property matches the properties set by CSS");
66     assert_equals(computedTiming.delay, -3000, "The animations's computed timing delay property matches the properties set by CSS");
67     assert_equals(computedTiming.duration, 2000, "The animations's computed timing duration property matches the properties set by CSS");
68     assert_equals(computedTiming.endDelay, 0, "The animations's computed timing endDelay property matches the properties set by CSS");
69     assert_equals(computedTiming.endTime, 1000, "The animations's computed timing endTime property matches the properties set by CSS");
70     assert_equals(computedTiming.iterationStart, 0, "The animations's computed timing iterationStart property matches the properties set by CSS");
71     assert_equals(computedTiming.iterations, 2, "The animations's computed timing iterations property matches the properties set by CSS");
72     assert_equals(computedTiming.localTime, 0, "The animations's computed timing localTime property matches the properties set by CSS");
73     assert_equals(computedTiming.progress, 0.5, "The animations's computed timing progress property matches the properties set by CSS");
74     assert_equals(computedTiming.fill, "forwards", "The animations's computed timing fill property matches the properties set by CSS");
75     assert_equals(computedTiming.easing, "linear", "The animations's computed timing easing property matches the properties set by CSS");
76     assert_equals(computedTiming.direction, "alternate", "The animations's computed timing direction property matches the properties set by CSS");
77
78     const keyframes = animation.effect.getKeyframes();
79     assert_equals(keyframes.length, 2, "The animation's effect has two keyframes.");
80     assert_equals(keyframes[0].offset, 0, "The animation's effect's first keyframe has a 0 offset.");
81     assert_equals(keyframes[0].left, "50px", "The animation's effect's first keyframe has its left property set to 50px.");
82     assert_equals(keyframes[1].offset, 1, "The animation's effect's first keyframe has a 1 offset.");
83     assert_equals(keyframes[1].left, "100px", "The animation's effect's first keyframe has its left property set to 100px.");
84
85     assert_equals(getComputedStyle(effect.target).left, "75px", "The animation's target's computed style reflects the animation state.");
86 }, "A CSS Animation should be reflected entirely as a CSSAnimation object on the timeline.");
87
88 targetTest(target => {
89     target.style.animationDelay = "-1s";
90     target.style.animationDuration = "2s";
91     target.style.animationName = "animation";
92
93     assert_equals(target.getAnimations()[0].effect.timing.delay, -1000, "The animation's delay matches the initial animation-delay property.");
94
95     target.style.animationDelay = 0;
96     assert_equals(target.getAnimations()[0].effect.timing.delay, 0, "The animation's delay matches the updated animation-delay property.");
97 }, "Web Animations should reflect the animation-delay property.");
98
99 targetTest(target => {
100     target.style.animationDuration = "2s";
101     target.style.animationName = "animation";
102
103     for (let direction of ["reverse", "alternate", "normal", "alternate-reverse"]) {
104         target.style.animationDirection = direction;
105         assert_equals(target.getAnimations()[0].effect.timing.direction, direction, `The animation's direction matches the "${direction}" CSS value.`);
106     }
107
108     target.style.removeProperty("animation-direction");
109     assert_equals(target.getAnimations()[0].effect.timing.direction, "normal", "The animation's easing matches the default animation-direction value when the property is not set.");
110 }, "Web Animations should reflect the animation-direction property.");
111
112 targetTest(target => {
113     target.style.animationDuration = "2s";
114     target.style.animationName = "animation";
115
116     assert_equals(target.getAnimations()[0].effect.timing.duration, 2000, "The animation's duration matches the initial animation-duration property.");
117
118     target.style.animationDuration = "1s";
119     assert_equals(target.getAnimations()[0].effect.timing.duration, 1000, "The animation's duration matches the updated animation-duration property.");
120 }, "Web Animations should reflect the animation-duration property.");
121
122 targetTest(target => {
123     target.style.animationDuration = "2s";
124     target.style.animationName = "animation";
125
126     for (let fillMode of ["forwards", "backwards", "none", "both"]) {
127         target.style.animationFillMode = fillMode;
128         assert_equals(target.getAnimations()[0].effect.timing.fill, fillMode, `The animation's fill mode matches the "${fillMode}" CSS value.`);
129     }
130
131     target.style.removeProperty("animation-fill-mode");
132     assert_equals(target.getAnimations()[0].effect.timing.fill, "none", "The animation's easing matches the default animation-fill-mode value when the property is not set.");
133 }, "Web Animations should reflect the animation-fill-mode property.");
134
135 targetTest(target => {
136     target.style.animationDuration = "2s";
137     target.style.animationName = "animation";
138
139     target.style.animationIterationCount = 2;
140     const initialAnimation = target.getAnimations()[0];
141     assert_equals(target.getAnimations()[0].effect.timing.iterations, 2, "The animation's duration matches the initial animation-iteration-count property.");
142
143     target.style.animationIterationCount = 1;
144     assert_equals(target.getAnimations()[0].effect.timing.iterations, 1, "The animation's duration matches the updated animation-iteration-count property.");
145
146     assert_equals(target.getAnimations()[0], initialAnimation, "The animation object remained the same instance throughout the test.");
147 }, "Web Animations should reflect the animation-iteration-count property.");
148
149 targetTest(target => {
150     target.style.animationDuration = "2s";
151     target.style.animationName = "animation";
152
153     const initialAnimation = target.getAnimations()[0];
154     assert_equals(target.getAnimations()[0].animationName, "animation", "The animation's name matches the initial animation-name CSS property.");
155
156     const initialKeyframes = initialAnimation.effect.getKeyframes();
157     assert_equals(initialKeyframes.length, 2);
158     assert_equals(initialKeyframes[0].offset, 0);
159     assert_equals(initialKeyframes[0].left, "50px");
160     assert_equals(initialKeyframes[1].offset, 1);
161     assert_equals(initialKeyframes[1].left, "100px");
162
163     target.style.animationName = "animation-top";
164     const updatedAnimation = target.getAnimations()[0];
165     assert_not_equals(updatedAnimation, initialAnimation, "Changing the animation-name property generates a different CSSAnimation object.");
166     assert_equals(updatedAnimation.animationName, "animation-top", "The animation's name matches the updated animation-name CSS property.");
167
168     const updatedKeyframes = updatedAnimation.effect.getKeyframes();
169     assert_equals(updatedKeyframes.length, 2);
170     assert_equals(updatedKeyframes[0].offset, 0);
171     assert_equals(updatedKeyframes[0].top, "50px");
172     assert_equals(updatedKeyframes[1].offset, 1);
173     assert_equals(updatedKeyframes[1].top, "100px");
174 }, "Web Animations should reflect the animation-name property.");
175
176 targetTest(target => {
177     target.style.animationDelay = "-1s";
178     target.style.animationDuration = "2s";
179     target.style.animationName = "animation";
180
181     const initialAnimation = target.getAnimations()[0];
182     assert_equals(target.getAnimations()[0].playState, "running", "Setting animation-play-state to running should resume the animation.");
183
184     target.style.animationPlayState = "paused";
185     assert_equals(target.getAnimations()[0].playState, "paused", "Setting animation-play-state back to paused should pause the animation.");
186
187     target.style.removeProperty("animation-play-state");
188     assert_equals(target.getAnimations()[0].playState, "running", "Removing the animation-play-state property should resume the animation.");
189
190     assert_equals(target.getAnimations()[0], initialAnimation, "The animation object remained the same instance throughout the test.");
191 }, "Web Animations should reflect the animation-play-state property.");
192
193 targetTest(target => {
194     target.style.animationDuration = "2s";
195     target.style.animationTimingFunction = "ease-out";
196     target.style.animationName = "animation";
197
198     assert_equals(target.getAnimations()[0].effect.timing.easing, "linear", "The animation's easing does not match the initial animation-timing-function property.");
199
200     target.style.animationTimingFunction = "ease-in";
201     assert_equals(target.getAnimations()[0].effect.timing.easing, "linear", "The animation's easing does not match the updated animation-timing-function property.");
202
203     target.style.removeProperty("animation-timing-function");
204     assert_equals(target.getAnimations()[0].effect.timing.easing, "linear", "The animation's easing does not match the default animation-timing-function value when the property is not set.");
205 }, "Web Animations should not reflect the animation-timing-function property on the effect's timing.");
206
207 function runAnimationCompletionTest(finalAssertionCallback, description)
208 {
209     targetTest(target => {
210         target.style.animationName = "animation";
211         assert_array_equals(target.getAnimations(), [], "Seting the animation-name property alone does not yield a CSSAnimation.");
212
213         target.style.animationDuration = "1s";
214         assert_equals(target.getAnimations().length, 1, "Seting the animation-duration property on top of the animation-name yields a CSSAnimation.");
215         assert_equals(target.getAnimations()[0].playState, "running", "Seting the animation-duration property on top of the animation-name yields a running CSSAnimation.");
216
217         finalAssertionCallback(target.getAnimations()[0]);
218         assert_array_equals(target.getAnimations(), [], `${description} no longer lists the animation.`);
219     }, `${description} no longer lists the animation after it has been running.`);
220 }
221
222 runAnimationCompletionTest(animation => animation.finish(), "Calling finish() on the animation");
223 runAnimationCompletionTest(animation => animation.currentTime = animation.effect.timing.duration, "Seeking the animation to its end time");
224 runAnimationCompletionTest(animation => animation.effect.target.style.animationName = "none", "Setting the target's animation-name to none");
225 runAnimationCompletionTest(animation => animation.effect.target.style.animationDuration = 0, "Setting the target's animation-duration to 0");
226
227 </script>
228 </body>