mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-10-22 02:25:05 +00:00
291 lines
10 KiB
HTML
291 lines
10 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset=utf-8>
|
|
<title>Tests for the effect of setting a CSS transition's
|
|
Animation.startTime</title>
|
|
<style>
|
|
|
|
.animated-div {
|
|
margin-left: 100px;
|
|
transition: margin-left 1000s linear 1000s;
|
|
}
|
|
|
|
</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 ANIM_DELAY_MS = 1000000; // 1000s
|
|
const ANIM_DUR_MS = 1000000; // 1000s
|
|
|
|
/**
|
|
* These helpers get the value that the startTime 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 startTimeForBeforePhase(timeline) {
|
|
return timeline.currentTime - ANIM_DELAY_MS / 2;
|
|
}
|
|
function startTimeForActivePhase(timeline) {
|
|
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS / 2;
|
|
}
|
|
function startTimeForAfterPhase(timeline) {
|
|
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS - ANIM_DELAY_MS / 2;
|
|
}
|
|
function startTimeForStartOfActiveInterval(timeline) {
|
|
return timeline.currentTime - ANIM_DELAY_MS;
|
|
}
|
|
function startTimeForFiftyPercentThroughActiveInterval(timeline) {
|
|
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.5;
|
|
}
|
|
function startTimeForEndOfActiveInterval(timeline) {
|
|
return timeline.currentTime - 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 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 the ready Promise's callbacks should happen
|
|
function checkStateOnReadyPromiseResolved(animation)
|
|
{
|
|
assert_less_than_equal(animation.startTime, animation.timeline.currentTime,
|
|
'Animation.startTime should be less than 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');
|
|
|
|
var div = animation.effect.target;
|
|
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
|
|
assert_equals(marginLeft, INITIAL_POSITION,
|
|
'the computed value of margin-left should be unaffected ' +
|
|
'by an animation with a delay on ready Promise resolve');
|
|
}
|
|
|
|
// Called when startTime is set to the time the active interval starts.
|
|
function checkStateAtActiveIntervalStartTime(animation)
|
|
{
|
|
// We don't test animation.startTime since our caller just set it.
|
|
|
|
assert_equals(animation.playState, 'running',
|
|
'Animation.playState 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.startTime 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 startTime is set to the time the active interval ends.
|
|
function checkStateAtActiveIntervalEndTime(animation)
|
|
{
|
|
// We don't test animation.startTime since our caller just set it.
|
|
|
|
assert_equals(animation.playState, 'finished',
|
|
'Animation.playState should be "finished" at the end of ' +
|
|
'the active interval');
|
|
|
|
var div = animation.effect.target;
|
|
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
|
|
assert_equals(marginLeft, END_POSITION,
|
|
'the computed value of margin-left should be the final transitioned-to ' +
|
|
'value at the end of the active duration');
|
|
}
|
|
|
|
test(function(t)
|
|
{
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
flushComputedStyle(div);
|
|
div.style.marginLeft = '200px'; // initiate transition
|
|
|
|
var animation = div.getAnimations()[0];
|
|
assert_equals(animation.startTime, null, 'startTime is unresolved');
|
|
}, 'startTime of a newly created transition is unresolved');
|
|
|
|
|
|
test(function(t)
|
|
{
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
flushComputedStyle(div);
|
|
div.style.marginLeft = '200px'; // initiate transition
|
|
|
|
var animation = div.getAnimations()[0];
|
|
var currentTime = animation.timeline.currentTime;
|
|
animation.startTime = currentTime;
|
|
assert_approx_equals(animation.startTime, currentTime, 0.0001, // rounding error
|
|
'Check setting of startTime actually works');
|
|
}, 'Sanity test to check round-tripping assigning to new animation\'s ' +
|
|
'startTime');
|
|
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
var eventWatcher = new EventWatcher(t, div, 'transitionend');
|
|
|
|
flushComputedStyle(div);
|
|
div.style.marginLeft = '200px'; // initiate transition
|
|
|
|
var animation = div.getAnimations()[0];
|
|
|
|
animation.ready.then(t.step_func(function() {
|
|
checkStateOnReadyPromiseResolved(animation);
|
|
|
|
animation.startTime = startTimeForStartOfActiveInterval(animation.timeline);
|
|
checkStateAtActiveIntervalStartTime(animation);
|
|
|
|
animation.startTime =
|
|
startTimeForFiftyPercentThroughActiveInterval(animation.timeline);
|
|
checkStateAtFiftyPctOfActiveInterval(animation);
|
|
|
|
animation.startTime = startTimeForEndOfActiveInterval(animation.timeline);
|
|
return eventWatcher.wait_for('transitionend');
|
|
})).then(t.step_func(function() {
|
|
checkStateAtActiveIntervalEndTime(animation);
|
|
})).catch(t.step_func(function(reason) {
|
|
assert_unreached(reason);
|
|
})).then(function() {
|
|
t.done();
|
|
});
|
|
}, 'Skipping forward through animation');
|
|
|
|
|
|
test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
var eventWatcher = new EventWatcher(t, div, 'transitionend');
|
|
|
|
flushComputedStyle(div);
|
|
div.style.marginLeft = '200px'; // initiate transition
|
|
|
|
var animation = div.getAnimations()[0];
|
|
|
|
// Unlike in the case of CSS animations, we cannot skip to the end and skip
|
|
// backwards since when we reach the end the transition effect is removed and
|
|
// changes to the Animation object no longer affect the element. For
|
|
// this reason we only skip forwards as far as the 90% through point.
|
|
|
|
animation.startTime =
|
|
startTimeForFiftyPercentThroughActiveInterval(animation.timeline);
|
|
checkStateAtFiftyPctOfActiveInterval(animation);
|
|
|
|
animation.startTime = startTimeForStartOfActiveInterval(animation.timeline);
|
|
|
|
// Despite going backwards from being in the active interval to being before
|
|
// it, we now expect an 'animationend' event because the animation should go
|
|
// from being active to inactive.
|
|
//
|
|
// Calling checkStateAtActiveIntervalStartTime will check computed style,
|
|
// causing computed style to be updated and the 'transitionend' event to
|
|
// be dispatched synchronously. We need to call waitForEvent first
|
|
// otherwise eventWatcher will assert that the event was unexpected.
|
|
eventWatcher.wait_for('transitionend').then(function() {
|
|
t.done();
|
|
});
|
|
checkStateAtActiveIntervalStartTime(animation);
|
|
}, 'Skipping backwards through transition');
|
|
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
|
|
flushComputedStyle(div);
|
|
div.style.marginLeft = '200px'; // initiate transition
|
|
|
|
var animation = div.getAnimations()[0];
|
|
|
|
var storedCurrentTime;
|
|
|
|
animation.ready.then(t.step_func(function() {
|
|
storedCurrentTime = animation.currentTime;
|
|
animation.startTime = null;
|
|
return animation.ready;
|
|
})).catch(t.step_func(function(reason) {
|
|
assert_unreached(reason);
|
|
})).then(t.step_func(function() {
|
|
assert_equals(animation.currentTime, storedCurrentTime,
|
|
'Test that hold time is correct');
|
|
t.done();
|
|
}));
|
|
}, 'Setting startTime to null');
|
|
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t, {'class': 'animated-div'});
|
|
|
|
flushComputedStyle(div);
|
|
div.style.marginLeft = '200px'; // initiate transition
|
|
|
|
var animation = div.getAnimations()[0];
|
|
|
|
animation.ready.then(t.step_func(function() {
|
|
var savedStartTime = animation.startTime;
|
|
|
|
assert_not_equals(animation.startTime, null,
|
|
'Animation.startTime not null on ready Promise resolve');
|
|
|
|
animation.pause();
|
|
return animation.ready;
|
|
})).then(t.step_func(function() {
|
|
assert_equals(animation.startTime, null,
|
|
'Animation.startTime is null after paused');
|
|
assert_equals(animation.playState, 'paused',
|
|
'Animation.playState is "paused" after pause() call');
|
|
})).catch(t.step_func(function(reason) {
|
|
assert_unreached(reason);
|
|
})).then(function() {
|
|
t.done();
|
|
});
|
|
}, 'Animation.startTime after paused');
|
|
|
|
done();
|
|
</script>
|
|
</body>
|
|
</html>
|