[Web Animations] Expose Web Animations CSS integration as an experimental feature
[WebKit-https.git] / LayoutTests / imported / w3c / web-platform-tests / web-animations / timing-model / animations / reversing-an-animation.html
1 <!DOCTYPE html><!-- webkit-test-runner [ enableWebAnimationsCSSIntegration=true ] -->
2 <meta charset=utf-8>
3 <title>Reverse an animation</title>
4 <link rel="help"
5       href="https://drafts.csswg.org/web-animations/#reverse-an-animation">
6 <script src="/resources/testharness.js"></script>
7 <script src="/resources/testharnessreport.js"></script>
8 <script src="../../testcommon.js"></script>
9 <body>
10 <div id="log"></div>
11 <script>
12 'use strict';
13
14 promise_test(t => {
15   const div = createDiv(t);
16   const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
17                                       iterations: Infinity });
18
19   // Wait a frame because if currentTime is still 0 when we call
20   // reverse(), it will throw (per spec).
21   return animation.ready.then(waitForAnimationFrames(1)).then(() => {
22     assert_greater_than_equal(animation.currentTime, 0,
23       'currentTime expected to be greater than 0, one frame after starting');
24     animation.currentTime = 50 * MS_PER_SEC;
25     const previousPlaybackRate = animation.playbackRate;
26     animation.reverse();
27     assert_equals(animation.playbackRate, -previousPlaybackRate,
28       'playbackRate should be inverted');
29   });
30 }, 'Reversing an animation inverts the playback rate');
31
32 promise_test(t => {
33   const div = createDiv(t);
34   const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
35                                       iterations: Infinity });
36   animation.currentTime = 50 * MS_PER_SEC;
37   animation.pause();
38
39   return animation.ready.then(() => {
40     animation.reverse();
41     return animation.ready;
42   }).then(() => {
43     assert_equals(animation.playState, 'running',
44       'Animation.playState should be "running" after reverse()');
45   });
46 }, 'Reversing an animation plays a pausing animation');
47
48 test(t => {
49   const div = createDiv(t);
50   const animation = div.animate({}, 100 * MS_PER_SEC);
51   animation.currentTime = 50 * MS_PER_SEC;
52   animation.reverse();
53
54   assert_equals(animation.currentTime, 50 * MS_PER_SEC,
55     'The current time should not change it is in the middle of ' +
56     'the animation duration');
57 }, 'Reversing an animation maintains the same current time');
58
59 test(t => {
60   const div = createDiv(t);
61   const animation = div.animate({}, { duration: 200 * MS_PER_SEC,
62                                       delay: -100 * MS_PER_SEC });
63   assert_true(animation.pending,
64               'The animation is pending before we call reverse');
65
66   animation.reverse();
67
68   assert_true(animation.pending,
69               'The animation is still pending after calling reverse');
70 }, 'Reversing an animation does not cause it to leave the pending state');
71
72 promise_test(t => {
73   const div = createDiv(t);
74   const animation = div.animate({}, { duration: 200 * MS_PER_SEC,
75                                       delay: -100 * MS_PER_SEC });
76   let readyResolved = false;
77   animation.ready.then(() => { readyResolved = true; });
78
79   animation.reverse();
80
81   return Promise.resolve(() => {
82     assert_false(readyResolved,
83                  'ready promise should not have been resolved yet');
84   });
85 }, 'Reversing an animation does not cause it to resolve the ready promise');
86
87 test(t => {
88   const div = createDiv(t);
89   const animation = div.animate({}, 100 * MS_PER_SEC);
90   animation.currentTime = 200 * MS_PER_SEC;
91   animation.reverse();
92
93   assert_equals(animation.currentTime, 100 * MS_PER_SEC,
94     'reverse() should start playing from the animation effect end ' +
95     'if the playbackRate > 0 and the currentTime > effect end');
96 }, 'Reversing an animation when playbackRate > 0 and currentTime > ' +
97    'effect end should make it play from the end');
98
99 test(t => {
100   const div = createDiv(t);
101   const animation = div.animate({}, 100 * MS_PER_SEC);
102
103   animation.currentTime = -200 * MS_PER_SEC;
104   animation.reverse();
105
106   assert_equals(animation.currentTime, 100 * MS_PER_SEC,
107     'reverse() should start playing from the animation effect end ' +
108     'if the playbackRate > 0 and the currentTime < 0');
109 }, 'Reversing an animation when playbackRate > 0 and currentTime < 0 ' +
110    'should make it play from the end');
111
112 test(t => {
113   const div = createDiv(t);
114   const animation = div.animate({}, 100 * MS_PER_SEC);
115   animation.playbackRate = -1;
116   animation.currentTime = -200 * MS_PER_SEC;
117   animation.reverse();
118
119   assert_equals(animation.currentTime, 0,
120     'reverse() should start playing from the start of animation time ' +
121     'if the playbackRate < 0 and the currentTime < 0');
122 }, 'Reversing an animation when playbackRate < 0 and currentTime < 0 ' +
123    'should make it play from the start');
124
125 test(t => {
126   const div = createDiv(t);
127   const animation = div.animate({}, 100 * MS_PER_SEC);
128   animation.playbackRate = -1;
129   animation.currentTime = 200 * MS_PER_SEC;
130   animation.reverse();
131
132   assert_equals(animation.currentTime, 0,
133     'reverse() should start playing from the start of animation time ' +
134     'if the playbackRate < 0 and the currentTime > effect end');
135 }, 'Reversing an animation when playbackRate < 0 and currentTime > effect ' +
136    'end should make it play from the start');
137
138 test(t => {
139   const div = createDiv(t);
140   const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
141                                       iterations: Infinity });
142   animation.currentTime = -200 * MS_PER_SEC;
143
144   assert_throws('InvalidStateError',
145     () => { animation.reverse(); },
146     'reverse() should throw InvalidStateError ' +
147     'if the playbackRate > 0 and the currentTime < 0 ' +
148     'and the target effect is positive infinity');
149 }, 'Reversing an animation when playbackRate > 0 and currentTime < 0 ' +
150    'and the target effect end is positive infinity should throw an exception');
151
152 test(t => {
153   const animation = createDiv(t).animate({}, { duration: 100 * MS_PER_SEC,
154                                                iterations: Infinity });
155   animation.currentTime = -200 * MS_PER_SEC;
156
157   try { animation.reverse(); } catch(e) { }
158
159   assert_equals(animation.playbackRate, 1, 'playbackRate remains unchanged');
160 }, 'When reversing throws an exception, the playback rate remains unchanged');
161
162 test(t => {
163   const div = createDiv(t);
164   const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
165                                       iterations: Infinity });
166   animation.currentTime = -200 * MS_PER_SEC;
167   animation.playbackRate = 0;
168
169   try {
170     animation.reverse();
171   } catch (e) {
172     assert_unreached(`Unexpected exception when calling reverse(): ${e}`);
173   }
174 }, 'Reversing animation when playbackRate = 0 and currentTime < 0 ' +
175    'and the target effect end is positive infinity should NOT throw an ' +
176    'exception');
177
178 test(t => {
179   const div = createDiv(t);
180   const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
181                                       iterations: Infinity });
182   animation.playbackRate = -1;
183   animation.currentTime = -200 * MS_PER_SEC;
184   animation.reverse();
185
186   assert_equals(animation.currentTime, 0,
187     'reverse() should start playing from the start of animation time ' +
188     'if the playbackRate < 0 and the currentTime < 0 ' +
189     'and the target effect is positive infinity');
190 }, 'Reversing an animation when playbackRate < 0 and currentTime < 0 ' +
191    'and the target effect end is positive infinity should make it play ' +
192    'from the start');
193
194 test(t => {
195   const div = createDiv(t);
196   const animation = div.animate({}, 100 * MS_PER_SEC);
197   animation.playbackRate = 0;
198   animation.currentTime = 50 * MS_PER_SEC;
199   animation.reverse();
200
201   assert_equals(animation.playbackRate, 0,
202     'reverse() should preserve playbackRate if the playbackRate == 0');
203   assert_equals(animation.currentTime, 50 * MS_PER_SEC,
204     'reverse() should not affect the currentTime if the playbackRate == 0');
205   t.done();
206 }, 'Reversing when when playbackRate == 0 should preserve the current ' +
207    'time and playback rate');
208
209 test(t => {
210   const div = createDiv(t);
211   const animation =
212     new Animation(new KeyframeEffect(div, null, 100 * MS_PER_SEC), null);
213
214   assert_throws('InvalidStateError', () => { animation.reverse(); });
215 }, 'Reversing an animation without an active timeline throws an ' +
216    'InvalidStateError');
217
218 </script>
219 </body>