052e4c4c39c5121b871ea7960d4fd48a51a38c87
[WebKit-https.git] / LayoutTests / webanimations / css-transitions.html
1 <!DOCTYPE html><!-- webkit-test-runner [ enableWebAnimationsCSSIntegration=true ] -->
2 <meta charset=utf-8>
3 <title>CSS Transitions</title>
4 <body>
5 <script src="../resources/testharness.js"></script>
6 <script src="../resources/testharnessreport.js"></script>
7 <script>
8
9 'use strict';
10
11 function targetTest(testCallback, description)
12 {
13     test(() => {
14         const target = document.body.appendChild(document.createElement("div"));
15         testCallback(target);
16         target.remove();
17     }, description);
18 }
19
20 function forceStyleUpdate(element)
21 {
22     element.offsetLeft;
23 }
24
25 targetTest(target => {
26     target.style.left = "50px";
27
28     assert_array_equals(target.getAnimations(), [], "An element should not have any animations initially.");
29
30     target.style.transitionProperty = "left";
31     target.style.transitionDelay = "-1s";
32     target.style.transitionDuration = "2s";
33     target.style.transitionTimingFunction = "linear";
34
35     assert_array_equals(target.getAnimations(), [], "Setting CSS transitions properties should not yield a CSSTransition until a new target value is specified.");
36
37     forceStyleUpdate(target);
38     target.style.left = "100px";
39
40     const animation = target.getAnimations()[0];
41     assert_true(animation instanceof CSSTransition, "The animation is a CSSTransition.");
42     assert_true(animation instanceof Animation, "The animation is an Animation.");
43     assert_equals(animation.timeline, target.ownerDocument.timeline, "The animation's timeline is set to the element's document timeline.");
44     assert_equals(animation.playState, "running", "The animation is running as soon as it's created.");
45     assert_equals(animation.transitionProperty, "left", "The animation's transitionProperty is set.");
46
47     const effect = animation.effect;
48     assert_true(effect instanceof KeyframeEffectReadOnly, "The animation's effect is a KeyframeEffectReadOnly.");
49     assert_false(effect instanceof KeyframeEffect, "The animation's effect is not a KeyframeEffect.");
50     assert_equals(effect.target, target, "The animation's effect is targeting the target.");
51
52     const timing = animation.effect.timing;
53     assert_equals(timing.delay, -1000, "The animation's delay property matches the transition-delay property.");
54     assert_equals(timing.duration, 2000, "The animation's duration property matches the transition-duration property.");
55
56     const computedTiming = animation.effect.getComputedTiming();
57     assert_equals(computedTiming.activeDuration, 2000, "The animations's computed timing activeDuration property matches the properties set by CSS");
58     assert_equals(computedTiming.currentIteration, 0, "The animations's computed timing currentIteration property matches the properties set by CSS");
59     assert_equals(computedTiming.delay, -1000, "The animations's computed timing delay property matches the properties set by CSS");
60     assert_equals(computedTiming.duration, 2000, "The animations's computed timing duration property matches the properties set by CSS");
61     assert_equals(computedTiming.endDelay, 0, "The animations's computed timing endDelay property matches the properties set by CSS");
62     assert_equals(computedTiming.endTime, 1000, "The animations's computed timing endTime property matches the properties set by CSS");
63     assert_equals(computedTiming.iterationStart, 0, "The animations's computed timing iterationStart property matches the properties set by CSS");
64     assert_equals(computedTiming.iterations, 1, "The animations's computed timing iterations property matches the properties set by CSS");
65     assert_equals(computedTiming.localTime, 0, "The animations's computed timing localTime property matches the properties set by CSS");
66     assert_equals(computedTiming.progress, 0.5, "The animations's computed timing progress property matches the properties set by CSS");
67     assert_equals(computedTiming.fill, "backwards", "The animations's computed timing fill property matches the default value set for transitions");
68     assert_equals(computedTiming.easing, "linear", "The animations's computed timing easing property matches the properties set by CSS");
69     assert_equals(computedTiming.direction, "normal", "The animations's computed timing direction property matches the properties set by CSS");
70
71     const keyframes = animation.effect.getKeyframes();
72     assert_equals(keyframes.length, 2, "The animation's effect has two keyframes.");
73     assert_equals(keyframes[0].offset, 0, "The animation's effect's first keyframe has a 0 offset.");
74     assert_equals(keyframes[0].left, "50px", "The animation's effect's first keyframe has its left property set to 50px.");
75     assert_equals(keyframes[1].offset, 1, "The animation's effect's first keyframe has a 1 offset.");
76     assert_equals(keyframes[1].left, "100px", "The animation's effect's first keyframe has its left property set to 100px.");
77
78     assert_equals(getComputedStyle(effect.target).left, "75px", "The animation's target's computed style reflects the animation state.");
79 }, "A CSS Transition should be reflected entirely as a CSSTransition object on the timeline.");
80
81 function transitionProperty(target, propertyName, from, to)
82 {
83     target.style[propertyName] = from;
84     forceStyleUpdate(target);
85     target.style[propertyName] = to;
86 }
87
88 function transitionPropertyUpdateTest(testCallback, description)
89 {
90     targetTest(target => {
91         target.style.transitionProperty = "left";
92         target.style.transitionDelay = "-500ms";
93         target.style.transitionDuration = "2s";
94         transitionProperty(target, "left", "50px", "100px");
95         testCallback(target);
96     }, description);
97 }
98
99 transitionPropertyUpdateTest(target => {
100     const initialAnimation = target.getAnimations()[0];
101     assert_equals(initialAnimation.effect.timing.delay, -500, "The animation's delay matches the initial transition-delay property.");
102
103     target.style.transitionDelay = 0;
104     const updatedAnimation = target.getAnimations()[0];
105     assert_equals(updatedAnimation.effect.timing.delay, 0, "The animation's delay matches the updated transition-delay property.");
106
107     assert_not_equals(initialAnimation, updatedAnimation, "The animations before and after updating the transition-delay property differ.");
108 }, "Web Animations should reflect the transition-delay property.");
109
110 transitionPropertyUpdateTest(target => {
111     const initialAnimation = target.getAnimations()[0];
112     assert_equals(initialAnimation.effect.timing.duration, 2000, "The animation's duration matches the initial transition-duration property.");
113
114     target.style.transitionDuration = "1s";
115     const updatedAnimation = target.getAnimations()[0];
116     assert_equals(updatedAnimation.effect.timing.duration, 1000, "The animation's duration matches the updated transition-duration property.");
117
118     assert_not_equals(initialAnimation, updatedAnimation, "The animations before and after updating the transition-duration property differ.");
119 }, "Web Animations should reflect the transition-duration property.");
120
121 targetTest(target => {
122     target.style.transitionDuration = "2s";
123
124     target.style.transitionProperty = "left";
125     transitionProperty(target, "left", "50px", "100px");
126
127     const initialAnimation = target.getAnimations()[0];
128     assert_equals(target.getAnimations()[0].transitionProperty, "left", "The animation's property matches the initial transition-property CSS property.");
129
130     const initialKeyframes = initialAnimation.effect.getKeyframes();
131     assert_equals(initialKeyframes.length, 2);
132     assert_equals(initialKeyframes[0].offset, 0);
133     assert_equals(initialKeyframes[0].left, "50px");
134     assert_equals(initialKeyframes[1].offset, 1);
135     assert_equals(initialKeyframes[1].left, "100px");
136
137     target.style.transitionProperty = "top";
138     transitionProperty(target, "top", "50px", "100px");
139
140     const updatedAnimation = target.getAnimations()[0];
141     assert_equals(updatedAnimation.transitionProperty, "top", "The animation's property matches the updated transition-property CSS property.");
142
143     const updatedKeyframes = updatedAnimation.effect.getKeyframes();
144     assert_equals(updatedKeyframes.length, 2);
145     assert_equals(updatedKeyframes[0].offset, 0);
146     assert_equals(updatedKeyframes[0].top, "50px");
147     assert_equals(updatedKeyframes[1].offset, 1);
148     assert_equals(updatedKeyframes[1].top, "100px");
149
150     assert_not_equals(updatedAnimation, initialAnimation, "Changing the transition-property property generates a different CSSTransition object.");
151 }, "Web Animations should reflect the transition-property property.");
152
153 transitionPropertyUpdateTest(target => {
154     const initialAnimation = target.getAnimations()[0];
155     assert_equals(initialAnimation.effect.timing.easing, "linear", "The animation's easing does not match the default transition-timing-function property.");
156
157     target.style.transitionTimingFunction = "ease-in";
158     const updatedAnimation = target.getAnimations()[0];
159     assert_equals(updatedAnimation.effect.timing.easing, "linear", "The animation's easing does not match the updated transition-timing-function property.");
160
161     target.style.removeProperty("transition-timing-function");
162     const finalAnimation = target.getAnimations()[0];
163     assert_equals(target.getAnimations()[0].effect.timing.easing, "linear", "The animation's easing does not match the default transition-timing-function value when the property is not set.");
164 }, "Web Animations should not reflect the transition-timing-function property on the effect's timing.");
165
166 function runAnimationCompletionTest(finalAssertionCallback, description)
167 {
168     targetTest(target => {
169         target.style.transitionProperty = "left";
170         target.style.transitionDuration = "1s";
171         transitionProperty(target, "left", "50px", "100px");
172
173         assert_equals(target.getAnimations().length, 1, "Seting the transition-duration property on top of the transition-property yields a CSSTransition.");
174         assert_equals(target.getAnimations()[0].playState, "running", "Seting the transition-duration property on top of the transition-property yields a running CSSTransition.");
175
176         finalAssertionCallback(target.getAnimations()[0]);
177
178         assert_array_equals(target.getAnimations(), [], `${description} no longer lists the animation.`);
179     }, `${description} no longer lists the animation after it has been running.`);
180 }
181
182 runAnimationCompletionTest(animation => animation.finish(), "Calling finish() on the animation");
183 runAnimationCompletionTest(animation => animation.currentTime = animation.effect.timing.duration, "Seeking the animation to its end time");
184 runAnimationCompletionTest(animation => animation.effect.target.style.transitionProperty = "none", "Setting the target's transition-property to none");
185 runAnimationCompletionTest(animation => animation.effect.target.style.transitionDuration = 0, "Seeking the target's transition-duration to 0");
186
187 </script>
188 </body>