gecko-dev/testing/web-platform/tests/css/css-animations/event-dispatch.tentative.html
Blink WPT Bot aecaf7389b Bug 1622890 [wpt PR 22282] - Add timeouts for EventWatchers on CSS animation tests, a=testonly
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
2020-03-21 00:32:29 +00:00

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>