mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-11-19 18:38:36 +00:00
590 lines
21 KiB
HTML
590 lines
21 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset=utf-8>
|
|
<title>Tests for the effect of setting a CSS animation's
|
|
Animation.currentTime</title>
|
|
<style>
|
|
|
|
.animated-div {
|
|
margin-left: 10px;
|
|
/* Make it easier to calculate expected values: */
|
|
animation-timing-function: linear ! important;
|
|
}
|
|
|
|
@keyframes anim {
|
|
from { margin-left: 100px; }
|
|
to { margin-left: 200px; }
|
|
}
|
|
|
|
</style>
|
|
<script src="../testcommon.js"></script>
|
|
</head>
|
|
<body>
|
|
<script type="text/javascript">
|
|
|
|
'use strict';
|
|
|
|
// TODO: add equivalent tests without an animation-delay, but first we need to
|
|
// change the timing of animationstart dispatch. (Right now the animationstart
|
|
// event will fire before the ready Promise is resolved if there is no
|
|
// animation-delay.)
|
|
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1134163
|
|
|
|
// TODO: Once the computedTiming property is implemented, add checks to the
|
|
// checker helpers to ensure that computedTiming's properties are updated as
|
|
// expected.
|
|
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1108055
|
|
|
|
|
|
const CSS_ANIM_EVENTS =
|
|
['animationstart', 'animationiteration', 'animationend'];
|
|
const ANIM_DELAY_MS = 1000000; // 1000s
|
|
const ANIM_DUR_MS = 1000000; // 1000s
|
|
const ANIM_PROPERTY_VAL = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
|
|
|
/**
|
|
* These helpers get the value that the currentTime needs to be set to, to put
|
|
* an animation that uses the above ANIM_DELAY_MS and ANIM_DUR_MS values into
|
|
* the middle of various phases or points through the active duration.
|
|
*/
|
|
function currentTimeForBeforePhase(timeline) {
|
|
return ANIM_DELAY_MS / 2;
|
|
}
|
|
function currentTimeForActivePhase(timeline) {
|
|
return ANIM_DELAY_MS + ANIM_DUR_MS / 2;
|
|
}
|
|
function currentTimeForAfterPhase(timeline) {
|
|
return ANIM_DELAY_MS + ANIM_DUR_MS + ANIM_DELAY_MS / 2;
|
|
}
|
|
function currentTimeForStartOfActiveInterval(timeline) {
|
|
return ANIM_DELAY_MS;
|
|
}
|
|
function currentTimeForFiftyPercentThroughActiveInterval(timeline) {
|
|
return ANIM_DELAY_MS + ANIM_DUR_MS * 0.5;
|
|
}
|
|
function currentTimeForEndOfActiveInterval(timeline) {
|
|
return ANIM_DELAY_MS + ANIM_DUR_MS;
|
|
}
|
|
|
|
|
|
// Expected computed 'margin-left' values at points during the active interval:
|
|
// When we assert_between_inclusive using these values we could in theory cause
|
|
// intermittent failure due to very long delays between paints, but since the
|
|
// active duration is 1000s long, a delay would need to be around 100s to cause
|
|
// that. If that's happening then there are likely other issues that should be
|
|
// fixed, so a failure to make us look into that seems like a good thing.
|
|
const UNANIMATED_POSITION = 10;
|
|
const INITIAL_POSITION = 100;
|
|
const TEN_PCT_POSITION = 110;
|
|
const FIFTY_PCT_POSITION = 150;
|
|
const END_POSITION = 200;
|
|
|
|
// The terms used for the naming of the following helper functions refer to
|
|
// terms used in the Web Animations specification for specific phases of an
|
|
// animation. The terms can be found here:
|
|
//
|
|
// https://w3c.github.io/web-animations/#animation-effect-phases-and-states
|
|
//
|
|
// Note the distinction between the "animation start time" which occurs before
|
|
// the start delay and the start of the active interval which occurs after it.
|
|
|
|
// Called when currentTime is set to zero (the beginning of the start delay).
|
|
function checkStateOnSettingCurrentTimeToZero(animation)
|
|
{
|
|
// We don't test animation.currentTime since our caller just set it.
|
|
|
|
assert_equals(animation.playState, 'running',
|
|
'Animation.playState should be "running" at the start of ' +
|
|
'the start delay');
|
|
|
|
assert_equals(animation.effect.target.style.animationPlayState, 'running',
|
|
'Animation.effect.target.style.animationPlayState should be ' +
|
|
'"running" at the start of the start delay');
|
|
|
|
var div = animation.effect.target;
|
|
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
|
|
assert_equals(marginLeft, UNANIMATED_POSITION,
|
|
'the computed value of margin-left should be unaffected ' +
|
|
'at the beginning of the start delay');
|
|
}
|
|
|
|
// Called when the ready Promise's callbacks should happen
|
|
function checkStateOnReadyPromiseResolved(animation)
|
|
{
|
|
// the 0.0001 here is for rounding error
|
|
assert_less_than_equal(animation.currentTime,
|
|
animation.timeline.currentTime - animation.startTime + 0.0001,
|
|
'Animation.currentTime should be less than the local time ' +
|
|
'equivalent of the timeline\'s currentTime on the first paint tick ' +
|
|
'after animation creation');
|
|
|
|
assert_equals(animation.playState, 'running',
|
|
'Animation.playState should be "running" on the first paint ' +
|
|
'tick after animation creation');
|
|
|
|
assert_equals(animation.effect.target.style.animationPlayState, 'running',
|
|
'Animation.effect.target.style.animationPlayState should be ' +
|
|
'"running" on the first paint tick after animation creation');
|
|
|
|
var div = animation.effect.target;
|
|
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
|
|
assert_equals(marginLeft, UNANIMATED_POSITION,
|
|
'the computed value of margin-left should be unaffected ' +
|
|
'by an animation with a delay on ready Promise resolve');
|
|
}
|
|
|
|
// Called when currentTime is set to the time the active interval starts.
|
|
function checkStateAtActiveIntervalStartTime(animation)
|
|
{
|
|
// We don't test animation.currentTime since our caller just set it.
|
|
|
|
assert_equals(animation.playState, 'running',
|
|
'Animation.playState should be "running" at the start of ' +
|
|
'the active interval');
|
|
|
|
assert_equals(animation.effect.target.style.animationPlayState, 'running',
|
|
'Animation.effect.target.style.animationPlayState should be ' +
|
|
'"running" at the start of the active interval');
|
|
|
|
var div = animation.effect.target;
|
|
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
|
|
assert_between_inclusive(marginLeft, INITIAL_POSITION, TEN_PCT_POSITION,
|
|
'the computed value of margin-left should be close to the value at the ' +
|
|
'beginning of the animation');
|
|
}
|
|
|
|
function checkStateAtFiftyPctOfActiveInterval(animation)
|
|
{
|
|
// We don't test animation.currentTime since our caller just set it.
|
|
|
|
var div = animation.effect.target;
|
|
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
|
|
assert_equals(marginLeft, FIFTY_PCT_POSITION,
|
|
'the computed value of margin-left should be half way through the ' +
|
|
'animation at the midpoint of the active interval');
|
|
}
|
|
|
|
// Called when currentTime is set to the time the active interval ends.
|
|
function checkStateAtActiveIntervalEndTime(animation)
|
|
{
|
|
// We don't test animation.currentTime since our caller just set it.
|
|
|
|
assert_equals(animation.playState, 'finished',
|
|
'Animation.playState should be "finished" at the end of ' +
|
|
'the active interval');
|
|
|
|
assert_equals(animation.effect.target.style.animationPlayState, "running",
|
|
'Animation.effect.target.style.animationPlayState should be ' +
|
|
'"finished" at the end of the active interval');
|
|
|
|
var div = animation.effect.target;
|
|
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
|
|
assert_equals(marginLeft, UNANIMATED_POSITION,
|
|
'the computed value of margin-left should be unaffected ' +
|
|
'by the animation at the end of the active duration when the ' +
|
|
'animation-fill-mode is none');
|
|
}
|
|
|
|
|
|
test(function(t)
|
|
{
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
|
|
var animation = div.getAnimations()[0];
|
|
|
|
// Animations shouldn't start until the next paint tick, so:
|
|
assert_equals(animation.currentTime, 0,
|
|
'Animation.currentTime should be zero when an animation ' +
|
|
'is initially created');
|
|
|
|
assert_equals(animation.playState, "pending",
|
|
'Animation.playState should be "pending" when an animation ' +
|
|
'is initially created');
|
|
|
|
assert_equals(animation.effect.target.style.animationPlayState, 'running',
|
|
'Animation.effect.target.style.animationPlayState should be ' +
|
|
'"running" when an animation is initially created');
|
|
|
|
// XXX Ideally we would have a test to check the ready Promise is initially
|
|
// unresolved, but currently there is no Web API to do that. Waiting for the
|
|
// ready Promise with a timeout doesn't work because the resolved callback
|
|
// will be called (async) regardless of whether the Promise was resolved in
|
|
// the past or is resolved in the future.
|
|
|
|
// So that animation is running instead of paused when we set currentTime:
|
|
animation.startTime = animation.timeline.currentTime;
|
|
|
|
assert_approx_equals(animation.currentTime, 0, 0.0001, // rounding error
|
|
'Check setting of currentTime actually works');
|
|
|
|
checkStateOnSettingCurrentTimeToZero(animation);
|
|
}, 'Sanity test to check round-tripping assigning to new animation\'s ' +
|
|
'currentTime');
|
|
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
|
|
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
|
|
var animation = div.getAnimations()[0];
|
|
|
|
animation.ready.then(t.step_func(function() {
|
|
checkStateOnReadyPromiseResolved(animation);
|
|
|
|
animation.currentTime =
|
|
currentTimeForStartOfActiveInterval(animation.timeline);
|
|
return eventWatcher.wait_for('animationstart');
|
|
})).then(t.step_func(function() {
|
|
checkStateAtActiveIntervalStartTime(animation);
|
|
|
|
animation.currentTime =
|
|
currentTimeForFiftyPercentThroughActiveInterval(animation.timeline);
|
|
checkStateAtFiftyPctOfActiveInterval(animation);
|
|
|
|
animation.currentTime =
|
|
currentTimeForEndOfActiveInterval(animation.timeline);
|
|
return eventWatcher.wait_for('animationend');
|
|
})).then(t.step_func(function() {
|
|
checkStateAtActiveIntervalEndTime(animation);
|
|
})).catch(t.step_func(function(reason) {
|
|
assert_unreached(reason);
|
|
})).then(function() {
|
|
t.done();
|
|
});
|
|
}, 'Skipping forward through animation');
|
|
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
|
|
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
|
|
var animation = div.getAnimations()[0];
|
|
|
|
// So that animation is running instead of paused when we set currentTime:
|
|
animation.startTime = animation.timeline.currentTime;
|
|
|
|
animation.currentTime = currentTimeForEndOfActiveInterval(animation.timeline);
|
|
|
|
var previousTimelineTime = animation.timeline.currentTime;
|
|
|
|
// Skipping over the active interval will dispatch an 'animationstart' then
|
|
// an 'animationend' event. We need to wait for these events before we start
|
|
// testing going backwards since EventWatcher will fail the test if it gets
|
|
// an event that we haven't told it about.
|
|
eventWatcher.wait_for(['animationstart',
|
|
'animationend']).then(t.step_func(function() {
|
|
assert_true(document.timeline.currentTime - previousTimelineTime <
|
|
ANIM_DUR_MS,
|
|
'Sanity check that seeking worked rather than the events ' +
|
|
'firing after normal playback through the very long ' +
|
|
'animation duration');
|
|
|
|
// Now we can start the tests for skipping backwards, but first we check
|
|
// that after the events we're still in the same end time state:
|
|
checkStateAtActiveIntervalEndTime(animation);
|
|
|
|
animation.currentTime =
|
|
currentTimeForFiftyPercentThroughActiveInterval(animation.timeline);
|
|
|
|
// Despite going backwards from after the end of the animation (to being
|
|
// in the active interval), we now expect an 'animationstart' event
|
|
// because the animation should go from being inactive to active.
|
|
//
|
|
// Calling checkStateAtFiftyPctOfActiveInterval will check computed style,
|
|
// causing computed style to be updated and the 'animationstart' event to
|
|
// be dispatched synchronously. We need to call wait_for first
|
|
// otherwise eventWatcher will assert that the event was unexpected.
|
|
var promise = eventWatcher.wait_for('animationstart');
|
|
checkStateAtFiftyPctOfActiveInterval(animation);
|
|
return promise;
|
|
})).then(t.step_func(function() {
|
|
animation.currentTime =
|
|
currentTimeForStartOfActiveInterval(animation.timeline);
|
|
checkStateAtActiveIntervalStartTime(animation);
|
|
|
|
animation.currentTime = 0;
|
|
// Despite going backwards from just after the active interval starts to
|
|
// the animation start time, we now expect an animationend event
|
|
// because we went from inside to outside the active interval.
|
|
return eventWatcher.wait_for('animationend');
|
|
})).then(t.step_func(function() {
|
|
checkStateOnReadyPromiseResolved(animation);
|
|
})).catch(t.step_func(function(reason) {
|
|
assert_unreached(reason);
|
|
})).then(function() {
|
|
t.done();
|
|
});
|
|
|
|
// This must come after we've set up the Promise chain, since requesting
|
|
// computed style will force events to be dispatched.
|
|
// XXX For some reason this fails occasionally (either the animation.playState
|
|
// check or the marginLeft check).
|
|
//checkStateAtActiveIntervalEndTime(animation);
|
|
}, 'Skipping backwards through animation');
|
|
|
|
|
|
// Next we have multiple tests to check that redundant currentTime changes do
|
|
// NOT dispatch events. It's impossible to distinguish between events not being
|
|
// dispatched and events just taking an incredibly long time to dispatch
|
|
// without waiting an infinitely long time. Obviously we don't want to do that
|
|
// (block this test from finishing forever), so instead we just listen for
|
|
// events until two animation frames (i.e. requestAnimationFrame callbacks)
|
|
// have happened, then assume that no events will ever be dispatched for the
|
|
// redundant changes if no events were detected in that time.
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
var animation = div.getAnimations()[0];
|
|
|
|
animation.currentTime = currentTimeForActivePhase(animation.timeline);
|
|
animation.currentTime = currentTimeForBeforePhase(animation.timeline);
|
|
|
|
waitForAnimationFrames(2).then(function() {
|
|
t.done();
|
|
});
|
|
}, 'Redundant change, before -> active, then back');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
var animation = div.getAnimations()[0];
|
|
|
|
animation.currentTime = currentTimeForAfterPhase(animation.timeline);
|
|
animation.currentTime = currentTimeForBeforePhase(animation.timeline);
|
|
|
|
waitForAnimationFrames(2).then(function() {
|
|
t.done();
|
|
});
|
|
}, 'Redundant change, before -> after, then back');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
var animation = div.getAnimations()[0];
|
|
|
|
eventWatcher.wait_for('animationstart').then(function() {
|
|
animation.currentTime = currentTimeForBeforePhase(animation.timeline);
|
|
animation.currentTime = currentTimeForActivePhase(animation.timeline);
|
|
|
|
waitForAnimationFrames(2).then(function() {
|
|
t.done();
|
|
});
|
|
});
|
|
// get us into the initial state:
|
|
animation.currentTime = currentTimeForActivePhase(animation.timeline);
|
|
}, 'Redundant change, active -> before, then back');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
var animation = div.getAnimations()[0];
|
|
|
|
eventWatcher.wait_for('animationstart').then(function() {
|
|
animation.currentTime = currentTimeForAfterPhase(animation.timeline);
|
|
animation.currentTime = currentTimeForActivePhase(animation.timeline);
|
|
|
|
waitForAnimationFrames(2).then(function() {
|
|
t.done();
|
|
});
|
|
});
|
|
// get us into the initial state:
|
|
animation.currentTime = currentTimeForActivePhase(animation.timeline);
|
|
}, 'Redundant change, active -> after, then back');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
var animation = div.getAnimations()[0];
|
|
|
|
eventWatcher.wait_for(['animationstart',
|
|
'animationend']).then(function() {
|
|
animation.currentTime = currentTimeForBeforePhase(animation.timeline);
|
|
animation.currentTime = currentTimeForAfterPhase(animation.timeline);
|
|
|
|
waitForAnimationFrames(2).then(function() {
|
|
t.done();
|
|
});
|
|
});
|
|
// get us into the initial state:
|
|
animation.currentTime = currentTimeForAfterPhase(animation.timeline);
|
|
}, 'Redundant change, after -> before, then back');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
var animation = div.getAnimations()[0];
|
|
|
|
eventWatcher.wait_for(['animationstart',
|
|
'animationend']).then(function() {
|
|
animation.currentTime = currentTimeForActivePhase(animation.timeline);
|
|
animation.currentTime = currentTimeForAfterPhase(animation.timeline);
|
|
|
|
waitForAnimationFrames(2).then(function() {
|
|
t.done();
|
|
});
|
|
});
|
|
// get us into the initial state:
|
|
animation.currentTime = currentTimeForAfterPhase(animation.timeline);
|
|
}, 'Redundant change, after -> active, then back');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
var animation = div.getAnimations()[0];
|
|
|
|
animation.pause();
|
|
animation.currentTime = currentTimeForAfterPhase(animation.timeline);
|
|
|
|
eventWatcher.wait_for(['animationstart',
|
|
'animationend']).then(t.step_func(function() {
|
|
animation.currentTime = currentTimeForActivePhase(animation.timeline);
|
|
return eventWatcher.wait_for('animationstart');
|
|
})).then(t.step_func(function() {
|
|
t.done();
|
|
}));
|
|
|
|
}, 'Seeking finished -> paused dispatches animationstart');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
|
|
var animation = div.getAnimations()[0];
|
|
|
|
animation.ready.then(t.step_func(function() {
|
|
var exception;
|
|
try {
|
|
animation.currentTime = null;
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
assert_equals(exception.name, 'TypeError',
|
|
'Expect TypeError exception on trying to set ' +
|
|
'Animation.currentTime to null');
|
|
})).catch(t.step_func(function(reason) {
|
|
assert_unreached(reason);
|
|
})).then(function() {
|
|
t.done();
|
|
});
|
|
}, 'Setting currentTime to null');
|
|
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
div.style.animation = 'anim 100s';
|
|
|
|
var animation = div.getAnimations()[0];
|
|
var pauseTime;
|
|
|
|
animation.ready.then(t.step_func(function() {
|
|
assert_not_equals(animation.currentTime, null,
|
|
'Animation.currentTime not null on ready Promise resolve');
|
|
animation.pause();
|
|
return animation.ready;
|
|
})).then(t.step_func(function() {
|
|
pauseTime = animation.currentTime;
|
|
return waitForFrame();
|
|
})).then(t.step_func(function() {
|
|
assert_equals(animation.currentTime, pauseTime,
|
|
'Animation.currentTime is unchanged after pausing');
|
|
})).catch(t.step_func(function(reason) {
|
|
assert_unreached(reason);
|
|
})).then(function() {
|
|
t.done();
|
|
});
|
|
}, 'Animation.currentTime after pausing');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
|
|
var animation = div.getAnimations()[0];
|
|
|
|
animation.ready.then(function() {
|
|
// just before animation ends:
|
|
animation.currentTime = ANIM_DELAY_MS + ANIM_DUR_MS - 1;
|
|
|
|
return waitForAnimationFrames(2);
|
|
}).then(t.step_func(function() {
|
|
assert_equals(animation.currentTime, ANIM_DELAY_MS + ANIM_DUR_MS,
|
|
'Animation.currentTime should not continue to increase after the ' +
|
|
'animation has finished');
|
|
t.done();
|
|
}));
|
|
}, 'Animation.currentTime clamping');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
div.style.animation = ANIM_PROPERTY_VAL;
|
|
|
|
var animation = div.getAnimations()[0];
|
|
|
|
animation.ready.then(function() {
|
|
// play backwards:
|
|
animation.playbackRate = -1;
|
|
|
|
// just before animation ends (at the "start"):
|
|
animation.currentTime = 1;
|
|
|
|
return waitForAnimationFrames(2);
|
|
}).then(t.step_func(function() {
|
|
assert_equals(animation.currentTime, 0,
|
|
'Animation.currentTime should not continue to decrease after an ' +
|
|
'animation running in reverse has finished and currentTime is zero');
|
|
t.done();
|
|
}));
|
|
}, 'Animation.currentTime clamping for reversed animation');
|
|
|
|
test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
div.style.animation = 'anim 100s';
|
|
|
|
var animation = div.getAnimations()[0];
|
|
animation.cancel();
|
|
assert_equals(animation.currentTime, null,
|
|
'The currentTime of a cancelled animation should be null');
|
|
}, 'Animation.currentTime after cancelling');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
div.style.animation = 'anim 100s';
|
|
|
|
var animation = div.getAnimations()[0];
|
|
animation.ready.then(t.step_func(function() {
|
|
animation.finish();
|
|
|
|
// Initiate a pause then abort it
|
|
animation.pause();
|
|
animation.play();
|
|
|
|
// Wait to return to running state
|
|
return animation.ready;
|
|
})).then(t.step_func(function() {
|
|
assert_true(animation.currentTime < 100 * 1000,
|
|
'After aborting a pause when finished, the currentTime should'
|
|
+ ' jump back towards the start of the animation');
|
|
t.done();
|
|
}));
|
|
}, 'After aborting a pause when finished, the call to play() should rewind'
|
|
+ ' the current time');
|
|
|
|
done();
|
|
</script>
|
|
</body>
|
|
</html>
|