mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-10 05:08:36 +02:00
Automatic update from web-platform-tests Add timeouts for EventWatchers on CSS animation tests (#22282) Previously the test harness could timeout while waiting on the event watcher. In this patch, a timeout was added to the watchers in cases where the events should fire on the next animation frame. With the change, we still see timeouts on individual tests, but no longer see the test harness timing out. Next steps: 1. Add animationcancel. For some reason, this event got overlooked previously and was never implemented. Adding this event resolves the majority of timeouts (confirmed in an experimental patch). 2. Reconnect and event delegate after calls to animation.effect. Currently, the lack of a delegate on the new effect halts the dispatching of subsequent animation events. Bug: 1059968 Change-Id: Ib5bf46762e316a5f3d5f33aa95bf74edaf42e773 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2105424 Reviewed-by: Yi Gu <yigu@chromium.org> Commit-Queue: Kevin Ellis <kevers@chromium.org> Cr-Commit-Position: refs/heads/master@{#750745} Co-authored-by: Kevin Ellis <kevers@chromium.org> -- wpt-commits: c1c943f3d9e3fe023e401a39db1a66e535a50561 wpt-pr: 22282
422 lines
13 KiB
HTML
422 lines
13 KiB
HTML
<!doctype html>
|
|
<meta charset=utf-8>
|
|
<title>Tests for CSS animation event dispatch</title>
|
|
<meta name="timeout" content="long">
|
|
<link rel="help" href="https://drafts.csswg.org/css-animations-2/#event-dispatch"/>
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="support/testcommon.js"></script>
|
|
<style>
|
|
@keyframes anim {
|
|
from { margin-left: 0px; }
|
|
to { margin-left: 100px; }
|
|
}
|
|
</style>
|
|
<div id="log"></div>
|
|
<script>
|
|
'use strict';
|
|
|
|
const setupAnimation = (t, animationStyle) => {
|
|
const div = addDiv(t, { style: 'animation: ' + animationStyle });
|
|
const watcher = new EventWatcher(t, div, [ 'animationstart',
|
|
'animationiteration',
|
|
'animationend',
|
|
'animationcancel' ],
|
|
fastEventsTimeout);
|
|
const animation = div.getAnimations()[0];
|
|
|
|
return { animation, watcher, div };
|
|
};
|
|
|
|
promise_test(async t => {
|
|
// Add 1ms delay to ensure that the delay is not included in the elapsedTime.
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 1ms');
|
|
|
|
const evt = await watcher.wait_for('animationstart');
|
|
assert_equals(evt.elapsedTime, 0.0);
|
|
}, 'Idle -> Active');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s');
|
|
|
|
// Seek to After phase.
|
|
animation.finish();
|
|
|
|
const events = await watcher.wait_for(['animationstart', 'animationend'], {
|
|
record: 'all',
|
|
});
|
|
assert_equals(events[0].elapsedTime, 0.0);
|
|
assert_equals(events[1].elapsedTime, 100);
|
|
}, 'Idle -> After');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s paused');
|
|
|
|
await animation.ready;
|
|
|
|
// Seek to Active phase.
|
|
animation.currentTime = 100 * MS_PER_SEC;
|
|
|
|
const evt = await watcher.wait_for('animationstart');
|
|
assert_equals(evt.elapsedTime, 0.0);
|
|
}, 'Before -> Active');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s paused');
|
|
const allEvents = watcher.wait_for(['animationstart', 'animationend'], {
|
|
record: 'all',
|
|
});
|
|
|
|
await animation.ready;
|
|
|
|
// Seek to After phase.
|
|
animation.finish();
|
|
|
|
const events = await allEvents;
|
|
assert_equals(events[0].elapsedTime, 0.0);
|
|
assert_equals(events[1].elapsedTime, 100.0);
|
|
}, 'Before -> After');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher, div } = setupAnimation(t, 'anim 100s paused');
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
// Make idle
|
|
div.style.display = 'none';
|
|
|
|
const evt = await watcher.wait_for('animationcancel');
|
|
assert_equals(evt.elapsedTime, 0.0);
|
|
}, 'Active -> Idle, display: none');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s');
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
animation.currentTime = 100.0;
|
|
|
|
// Make idle
|
|
animation.timeline = null;
|
|
|
|
const evt = await watcher.wait_for('animationcancel');
|
|
assert_time_equals_literal(evt.elapsedTime, 0.1);
|
|
}, 'Active -> Idle, setting Animation.timeline = null');
|
|
|
|
promise_test(async t => {
|
|
// We should NOT pause animation since calling cancel synchronously.
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s');
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
animation.currentTime = 50.0;
|
|
animation.cancel();
|
|
|
|
const evt = await watcher.wait_for('animationcancel');
|
|
assert_time_equals_literal(evt.elapsedTime, 0.05);
|
|
}, 'Active -> Idle, calling Animation.cancel()');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s paused');
|
|
|
|
// Seek to Active phase.
|
|
animation.currentTime = 100 * MS_PER_SEC;
|
|
await watcher.wait_for('animationstart');
|
|
|
|
// Seek to Before phase.
|
|
animation.currentTime = 0;
|
|
|
|
const evt = await watcher.wait_for('animationend');
|
|
assert_equals(evt.elapsedTime, 0.0);
|
|
}, 'Active -> Before');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s paused');
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
// Seek to After phase.
|
|
animation.finish();
|
|
|
|
const evt = await watcher.wait_for('animationend');
|
|
assert_equals(evt.elapsedTime, 100.0);
|
|
}, 'Active -> After');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s paused');
|
|
|
|
// Seek to After phase.
|
|
animation.finish();
|
|
await watcher.wait_for([ 'animationstart', 'animationend' ]);
|
|
|
|
// Seek to Before phase.
|
|
animation.currentTime = 0;
|
|
|
|
const events = await watcher.wait_for(['animationstart', 'animationend'], {
|
|
record: 'all',
|
|
});
|
|
assert_equals(events[0].elapsedTime, 100.0);
|
|
assert_equals(events[1].elapsedTime, 0.0);
|
|
}, 'After -> Before');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s paused');
|
|
|
|
// Seek to After phase.
|
|
animation.finish();
|
|
await watcher.wait_for([ 'animationstart', 'animationend' ]);
|
|
|
|
// Seek to Active phase.
|
|
animation.currentTime = 100 * MS_PER_SEC;
|
|
|
|
const evt = await watcher.wait_for('animationstart');
|
|
assert_equals(evt.elapsedTime, 100.0);
|
|
}, 'After -> Active');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s 3 paused');
|
|
|
|
await animation.ready;
|
|
|
|
// Seek to iteration 0 (no animationiteration event should be dispatched)
|
|
animation.currentTime = 100 * MS_PER_SEC;
|
|
await watcher.wait_for('animationstart');
|
|
|
|
// Seek to iteration 2
|
|
animation.currentTime = 300 * MS_PER_SEC;
|
|
let evt = await watcher.wait_for('animationiteration');
|
|
assert_equals(evt.elapsedTime, 200);
|
|
|
|
// Seek to After phase (no animationiteration event should be dispatched)
|
|
animation.currentTime = 400 * MS_PER_SEC;
|
|
evt = await watcher.wait_for('animationend');
|
|
assert_equals(evt.elapsedTime, 300);
|
|
}, 'Active -> Active (forwards)');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s 3');
|
|
|
|
// Seek to After phase.
|
|
animation.finish();
|
|
await watcher.wait_for([ 'animationstart', 'animationend' ]);
|
|
|
|
// Seek to iteration 2 (no animationiteration event should be dispatched)
|
|
animation.pause();
|
|
animation.currentTime = 300 * MS_PER_SEC;
|
|
await watcher.wait_for('animationstart');
|
|
|
|
// Seek to mid of iteration 0 phase.
|
|
animation.currentTime = 200 * MS_PER_SEC;
|
|
|
|
const evt = await watcher.wait_for('animationiteration');
|
|
assert_equals(evt.elapsedTime, 200.0);
|
|
|
|
// Seek to before phase (no animationiteration event should be dispatched)
|
|
animation.currentTime = 0;
|
|
await watcher.wait_for('animationend');
|
|
}, 'Active -> Active (backwards)');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher, div } = setupAnimation(t, 'anim 100s paused');
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
// Seek to Idle phase.
|
|
div.style.display = 'none';
|
|
flushComputedStyle(div);
|
|
|
|
await watcher.wait_for('animationcancel');
|
|
|
|
// Restart this animation.
|
|
div.style.display = '';
|
|
await watcher.wait_for('animationstart');
|
|
}, 'Active -> Idle -> Active: animationstart is fired by restarting animation');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s 2 paused');
|
|
|
|
// Make After.
|
|
animation.finish();
|
|
|
|
await watcher.wait_for([ 'animationstart', 'animationend' ]);
|
|
animation.playbackRate = -1;
|
|
|
|
let evt = await watcher.wait_for('animationstart');
|
|
assert_equals(evt.elapsedTime, 200);
|
|
|
|
// Seek to 1st iteration
|
|
animation.currentTime = 200 * MS_PER_SEC - 1;
|
|
|
|
evt = await watcher.wait_for('animationiteration');
|
|
assert_equals(evt.elapsedTime, 100);
|
|
|
|
// Seek to before
|
|
animation.currentTime = 100 * MS_PER_SEC - 1;
|
|
|
|
evt = await watcher.wait_for('animationend');
|
|
assert_equals(evt.elapsedTime, 0);
|
|
assert_equals(animation.playState, 'running'); // delay
|
|
}, 'Negative playbackRate sanity test(Before -> Active -> Before)');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s');
|
|
|
|
animation.currentTime = 150 * MS_PER_SEC;
|
|
animation.currentTime = 50 * MS_PER_SEC;
|
|
|
|
// Then wait a couple of frames and check that no event was dispatched.
|
|
await waitForAnimationFrames(2);
|
|
}, 'Redundant change, before -> active, then back');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s');
|
|
|
|
animation.currentTime = 250 * MS_PER_SEC;
|
|
animation.currentTime = 50 * MS_PER_SEC;
|
|
|
|
// Then wait a couple of frames and check that no event was dispatched.
|
|
await waitForAnimationFrames(2);
|
|
}, 'Redundant change, before -> after, then back');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s');
|
|
|
|
// Get us into the initial state:
|
|
animation.currentTime = 150 * MS_PER_SEC;
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
animation.currentTime = 50 * MS_PER_SEC;
|
|
animation.currentTime = 150 * MS_PER_SEC;
|
|
|
|
// Then wait a couple of frames and check that no event was dispatched.
|
|
await waitForAnimationFrames(2);
|
|
}, 'Redundant change, active -> before, then back');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s');
|
|
|
|
// Get us into the initial state:
|
|
animation.currentTime = 150 * MS_PER_SEC;
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
animation.currentTime = 250 * MS_PER_SEC;
|
|
animation.currentTime = 150 * MS_PER_SEC;
|
|
|
|
// Then wait a couple of frames and check that no event was dispatched.
|
|
await waitForAnimationFrames(2);
|
|
}, 'Redundant change, active -> after, then back');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s');
|
|
|
|
// Get us into the initial state:
|
|
animation.currentTime = 250 * MS_PER_SEC;
|
|
|
|
await watcher.wait_for(['animationstart', 'animationend']);
|
|
|
|
animation.currentTime = 50 * MS_PER_SEC;
|
|
animation.currentTime = 250 * MS_PER_SEC;
|
|
|
|
// Then wait a couple of frames and check that no event was dispatched.
|
|
await waitForAnimationFrames(2);
|
|
}, 'Redundant change, after -> before, then back');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s 100s');
|
|
|
|
// Get us into the initial state:
|
|
animation.currentTime = 250 * MS_PER_SEC;
|
|
|
|
await watcher.wait_for(['animationstart', 'animationend']);
|
|
|
|
animation.currentTime = 150 * MS_PER_SEC;
|
|
animation.currentTime = 250 * MS_PER_SEC;
|
|
|
|
// Then wait a couple of frames and check that no event was dispatched.
|
|
await waitForAnimationFrames(2);
|
|
}, 'Redundant change, after -> active, then back');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s');
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
// Make idle
|
|
animation.cancel();
|
|
await watcher.wait_for('animationcancel');
|
|
|
|
animation.cancel();
|
|
// Then wait a couple of frames and check that no event was dispatched.
|
|
await waitForAnimationFrames(2);
|
|
}, 'Call Animation.cancel after canceling animation.');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s');
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
// Make idle
|
|
animation.cancel();
|
|
animation.play();
|
|
await watcher.wait_for([ 'animationcancel', 'animationstart' ]);
|
|
}, 'Restart animation after canceling animation immediately.');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s');
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
// Make idle
|
|
animation.cancel();
|
|
animation.play();
|
|
animation.cancel();
|
|
await watcher.wait_for('animationcancel');
|
|
|
|
// Then wait a couple of frames and check that no event was dispatched.
|
|
await waitForAnimationFrames(2);
|
|
}, 'Call Animation.cancel after restarting animation immediately.');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s');
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
// Make idle
|
|
animation.timeline = null;
|
|
await watcher.wait_for('animationcancel');
|
|
|
|
animation.timeline = document.timeline;
|
|
animation.play();
|
|
await watcher.wait_for('animationstart');
|
|
}, 'Set timeline and play transition after clearing the timeline.');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s');
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
// Make idle
|
|
animation.cancel();
|
|
await watcher.wait_for('animationcancel');
|
|
|
|
animation.effect = null;
|
|
// Then wait a couple of frames and check that no event was dispatched.
|
|
await waitForAnimationFrames(2);
|
|
}, 'Set null target effect after canceling the animation.');
|
|
|
|
promise_test(async t => {
|
|
const { animation, watcher } = setupAnimation(t, 'anim 100s');
|
|
|
|
await watcher.wait_for('animationstart');
|
|
|
|
animation.effect = null;
|
|
await watcher.wait_for('animationend');
|
|
|
|
animation.cancel();
|
|
// Then wait a couple of frames and check that no event was dispatched.
|
|
await waitForAnimationFrames(2);
|
|
}, 'Cancel the animation after clearing the target effect.');
|
|
|
|
</script>
|