[Web Animations] Turn Web Animations with CSS integration on for test runners
[WebKit-https.git] / LayoutTests / imported / mozilla / css-animations / test_event-dispatch.html
1 <!doctype html><!-- webkit-test-runner [ enableWebAnimationsCSSIntegration=true ] -->
2 <meta charset=utf-8>
3 <title>Tests for CSS animation event dispatch</title>
4 <link rel="help" href="https://drafts.csswg.org/css-animations-2/#event-dispatch"/>
5 <script src="../../../resources/testharness.js"></script>
6 <script src="../../../resources/testharnessreport.js"></script>
7 <script src="../resources/testcommon.js"></script>
8 <style>
9   @keyframes anim {
10     from { margin-left: 0px; }
11     to { margin-left: 100px; }
12   }
13 </style>
14 <body>
15 <div id="log"></div>
16 <script>
17 'use strict';
18
19 /**
20  * Helper class to record the elapsedTime member of each event.
21  * The EventWatcher class in testharness.js allows us to wait on
22  * multiple events in a certain order but only records the event
23  * parameters of the most recent event.
24  */
25 function AnimationEventHandler(target) {
26   this.target = target;
27   this.target.onanimationstart = evt => {
28    this.animationstart = evt.elapsedTime;
29   };
30   this.target.onanimationiteration = evt => {
31     this.animationiteration = evt.elapsedTime;
32   };
33   this.target.onanimationend = evt => {
34     this.animationend = evt.elapsedTime;
35   };
36   this.target.onanimationcancel = evt => {
37     this.animationcancel = evt.elapsedTime;
38   };
39 }
40 AnimationEventHandler.prototype.clear = () => {
41   this.animationstart     = undefined;
42   this.animationiteration = undefined;
43   this.animationend       = undefined;
44   this.animationcancel    = undefined;
45 }
46
47 function setupAnimation(t, animationStyle) {
48   const div = addDiv(t, { style: 'animation: ' + animationStyle });
49   // Note that this AnimationEventHandler should be created before EventWatcher
50   // to capture all events in the handler prior to the EventWatcher since
51   // testharness.js proceeds when the EventWatcher received watching events.
52   const handler = new AnimationEventHandler(div);
53   const watcher = new EventWatcher(t, div, [ 'animationstart',
54                                            'animationiteration',
55                                            'animationend',
56                                            'animationcancel' ]);
57   const animation = div.getAnimations()[0];
58
59   return { animation, watcher, div, handler };
60 }
61
62 promise_test(t => {
63   // Add 1ms delay to ensure that the delay is not included in the elapsedTime.
64   const { animation, watcher } = setupAnimation(t, 'anim 100s 1ms');
65
66   return watcher.wait_for('animationstart').then(evt => {
67     assert_equals(evt.elapsedTime, 0.0);
68   });
69 }, 'Idle -> Active');
70
71 promise_test(t => {
72   const { animation, watcher, div, handler } = setupAnimation(t, 'anim 100s');
73
74   // Seek to After phase.
75   animation.finish();
76   return watcher.wait_for([ 'animationstart',
77                             'animationend' ]).then(() => {
78     assert_equals(handler.animationstart, 0.0);
79     assert_equals(handler.animationend, 100);
80   });
81 }, 'Idle -> After');
82
83 promise_test(t => {
84   const { animation, watcher } =
85     setupAnimation(t, 'anim 100s 100s paused');
86
87   return animation.ready.then(() => {
88     // Seek to Active phase.
89     animation.currentTime = 100 * MS_PER_SEC;
90     return watcher.wait_for('animationstart');
91   }).then(evt => {
92     assert_equals(evt.elapsedTime, 0.0);
93   });
94 }, 'Before -> Active');
95
96 promise_test(t => {
97   const { animation, watcher, div, handler } =
98     setupAnimation(t, 'anim 100s 100s paused');
99
100   return animation.ready.then(() => {
101     // Seek to After phase.
102     animation.finish();
103     return watcher.wait_for([ 'animationstart', 'animationend' ]);
104   }).then(evt => {
105     assert_equals(handler.animationstart, 0.0);
106     assert_equals(handler.animationend, 100.0);
107   });
108 }, 'Before -> After');
109
110 promise_test(t => {
111   const { animation, watcher, div } = setupAnimation(t, 'anim 100s paused');
112
113   return watcher.wait_for('animationstart').then(evt => {
114     // Make idle
115     div.style.display = 'none';
116     return watcher.wait_for('animationcancel');
117   }).then(evt => {
118     assert_equals(evt.elapsedTime, 0.0);
119   });
120 }, 'Active -> Idle, display: none');
121
122 promise_test(t => {
123   const { animation, watcher, div } = setupAnimation(t, 'anim 100s');
124
125   return watcher.wait_for('animationstart').then(evt => {
126     animation.currentTime = 100.0;
127     // Make idle
128     animation.timeline = null;
129     return watcher.wait_for('animationcancel');
130   }).then(evt => {
131     assert_time_equals_literal(evt.elapsedTime, 0.1);
132   });
133 }, 'Active -> Idle, setting Animation.timeline = null');
134
135 promise_test(t => {
136   // we should NOT pause animation since calling cancel synchronously.
137   const { animation, watcher, div } = setupAnimation(t, 'anim 100s');
138
139   return watcher.wait_for('animationstart').then(evt => {
140     animation.currentTime = 50.0;
141     animation.cancel();
142     return watcher.wait_for('animationcancel');
143   }).then(evt => {
144     assert_time_equals_literal(evt.elapsedTime, 0.05);
145   });
146 }, 'Active -> Idle, calling Animation.cancel()');
147
148 promise_test(t => {
149   const { animation, watcher } =
150     setupAnimation(t, 'anim 100s 100s paused');
151
152   // Seek to Active phase.
153   animation.currentTime = 100 * MS_PER_SEC;
154   return watcher.wait_for('animationstart').then(() => {
155     // Seek to Before phase.
156     animation.currentTime = 0;
157     return watcher.wait_for('animationend');
158   }).then(evt => {
159     assert_equals(evt.elapsedTime, 0.0);
160   });
161 }, 'Active -> Before');
162
163 promise_test(t => {
164   const { animation, watcher } = setupAnimation(t, 'anim 100s paused');
165
166   return watcher.wait_for('animationstart').then(evt => {
167     // Seek to After phase.
168     animation.finish();
169     return watcher.wait_for('animationend');
170   }).then(evt => {
171     assert_equals(evt.elapsedTime, 100.0);
172   });
173 }, 'Active -> After');
174
175 promise_test(t => {
176   const { animation, watcher, div, handler } =
177     setupAnimation(t, 'anim 100s 100s paused');
178
179   // Seek to After phase.
180   animation.finish();
181   return watcher.wait_for([ 'animationstart',
182                             'animationend' ]).then(() => {
183     // Seek to Before phase.
184     animation.currentTime = 0;
185     handler.clear();
186     return watcher.wait_for([ 'animationstart', 'animationend' ]);
187   }).then(() => {
188     assert_equals(handler.animationstart, 100.0);
189     assert_equals(handler.animationend, 0.0);
190   });
191 }, 'After -> Before');
192
193 promise_test(t => {
194   const { animation, watcher, div } =
195     setupAnimation(t, 'anim 100s 100s paused');
196
197   // Seek to After phase.
198   animation.finish();
199   return watcher.wait_for([ 'animationstart',
200                             'animationend' ]).then(() => {
201     // Seek to Active phase.
202     animation.currentTime = 100 * MS_PER_SEC;
203     return watcher.wait_for('animationstart');
204   }).then(evt => {
205     assert_equals(evt.elapsedTime, 100.0);
206   });
207 }, 'After -> Active');
208
209 promise_test(t => {
210   const { animation, watcher, div }
211     = setupAnimation(t, 'anim 100s 100s 3 paused');
212
213   return animation.ready.then(() => {
214     // Seek to iteration 0 (no animationiteration event should be dispatched)
215     animation.currentTime = 100 * MS_PER_SEC;
216     return watcher.wait_for('animationstart');
217   }).then(evt => {
218     // Seek to iteration 2
219     animation.currentTime = 300 * MS_PER_SEC;
220     return watcher.wait_for('animationiteration');
221   }).then(evt => {
222     assert_equals(evt.elapsedTime, 200);
223     // Seek to After phase (no animationiteration event should be dispatched)
224     animation.currentTime = 400 * MS_PER_SEC;
225     return watcher.wait_for('animationend');
226   }).then(evt => {
227     assert_equals(evt.elapsedTime, 300);
228   });
229 }, 'Active -> Active (forwards)');
230
231 promise_test(t => {
232   const { animation, watcher } = setupAnimation(t, 'anim 100s 100s 3');
233
234   // Seek to After phase.
235   animation.finish();
236   return watcher.wait_for([ 'animationstart',
237                             'animationend' ]).then(() => {
238     // Seek to iteration 2 (no animationiteration event should be dispatched)
239     animation.pause();
240     animation.currentTime = 300 * MS_PER_SEC;
241     return watcher.wait_for('animationstart');
242   }).then(() => {
243     // Seek to mid of iteration 0 phase.
244     animation.currentTime = 200 * MS_PER_SEC;
245     return watcher.wait_for('animationiteration');
246   }).then(evt => {
247     assert_equals(evt.elapsedTime, 200.0);
248     // Seek to before phase (no animationiteration event should be dispatched)
249     animation.currentTime = 0;
250     return watcher.wait_for('animationend');
251   });
252 }, 'Active -> Active (backwards)');
253
254 promise_test(t => {
255   const { animation, watcher, div } =
256     setupAnimation(t, 'anim 100s paused');
257   return watcher.wait_for('animationstart').then(evt => {
258     // Seek to Idle phase.
259     div.style.display = 'none';
260     flushComputedStyle(div);
261
262     return watcher.wait_for('animationcancel');
263   }).then(() => {
264     // Restart this animation.
265     div.style.display = '';
266     return watcher.wait_for('animationstart');
267   });
268 }, 'Active -> Idle -> Active: animationstart is fired by restarting animation');
269
270 promise_test(t => {
271   const { animation, watcher } =
272     setupAnimation(t, 'anim 100s 100s 2 paused');
273
274   // Make After.
275   animation.finish();
276   return watcher.wait_for([ 'animationstart',
277                             'animationend' ]).then(evt => {
278     animation.playbackRate = -1;
279     return watcher.wait_for('animationstart');
280   }).then(evt => {
281     assert_equals(evt.elapsedTime, 200);
282     // Seek to 1st iteration
283     animation.currentTime = 200 * MS_PER_SEC - 1;
284     return watcher.wait_for('animationiteration');
285   }).then(evt => {
286     assert_equals(evt.elapsedTime, 100);
287     // Seek to before
288     animation.currentTime = 100 * MS_PER_SEC - 1;
289     return watcher.wait_for('animationend');
290   }).then(evt => {
291     assert_equals(evt.elapsedTime, 0);
292     assert_equals(animation.playState, 'running'); // delay
293   });
294 }, 'Negative playbackRate sanity test(Before -> Active -> Before)');
295
296 promise_test(t => {
297   const { animation, watcher } = setupAnimation(t, 'anim 100s');
298
299   return watcher.wait_for('animationstart').then(evt => {
300     // Make idle
301     animation.cancel();
302     return watcher.wait_for('animationcancel');
303   }).then(evt => {
304     animation.cancel();
305     // Then wait a couple of frames and check that no event was dispatched.
306     return waitForAnimationFrames(2);
307   });
308 }, 'Call Animation.cancel after cancelling animation.');
309
310 // FIXME: timeout
311 promise_test(t => {
312   const { animation, watcher, div } = setupAnimation(t, 'anim 1s');
313
314   return watcher.wait_for('animationstart').then(evt => {
315     // Make idle
316
317     animation.cancel();
318     animation.play();
319     return watcher.wait_for([ 'animationcancel',
320                               'animationstart' ]);
321   });
322 }, 'Restart animation after cancelling animation immediately.');
323
324 promise_test(t => {
325   const { animation, watcher } = setupAnimation(t, 'anim 100s');
326
327   return watcher.wait_for('animationstart').then(evt => {
328     // Make idle
329     animation.cancel();
330     animation.play();
331     animation.cancel();
332     return watcher.wait_for('animationcancel');
333   }).then(evt => {
334     // Then wait a couple of frames and check that no event was dispatched.
335     return waitForAnimationFrames(2);
336   });
337 }, 'Call Animation.cancel after restarting animation immediately.');
338
339 promise_test(t => {
340   const { animation, watcher } = setupAnimation(t, 'anim 100s');
341
342   return watcher.wait_for('animationstart').then(evt => {
343     // Make idle
344     animation.timeline = null;
345     return watcher.wait_for('animationcancel');
346   }).then(evt => {
347     animation.timeline = document.timeline;
348     animation.play();
349     return watcher.wait_for('animationstart');
350   });
351 }, 'Set timeline and play transition after clearing the timeline.');
352
353 promise_test(t => {
354   const { animation, watcher } = setupAnimation(t, 'anim 100s');
355
356   return watcher.wait_for('animationstart').then(evt => {
357     // Make idle
358     animation.cancel();
359     return watcher.wait_for('animationcancel');
360   }).then(evt => {
361     animation.effect = null;
362     // Then wait a couple of frames and check that no event was dispatched.
363     return waitForAnimationFrames(2);
364   });
365 }, 'Set null target effect after cancelling the animation.');
366
367 promise_test(t => {
368   const { animation, watcher } = setupAnimation(t, 'anim 100s');
369
370   return watcher.wait_for('animationstart').then(evt => {
371     animation.effect = null;
372     return watcher.wait_for('animationend');
373   }).then(evt => {
374     animation.cancel();
375     // Then wait a couple of frames and check that no event was dispatched.
376     return waitForAnimationFrames(2);
377   });
378 }, 'Cancel the animation after clearing the target effect.');
379
380 </script>
381 </body>
382 </html>