This patch also extends the tests for Element.getAnimations(). It doesn't actually exercise the code added (it's not actually called yet since it doesn't need to be for Element.getAnimations) but simply provides a useful regression and interop test.
310 lines
11 KiB
HTML
310 lines
11 KiB
HTML
<!doctype html>
|
|
<meta charset=utf-8>
|
|
<script src="../testcommon.js"></script>
|
|
<style>
|
|
@keyframes anim1 {
|
|
to { left: 100px }
|
|
}
|
|
@keyframes anim2 {
|
|
to { top: 100px }
|
|
}
|
|
@keyframes multiPropAnim {
|
|
to { background: green, opacity: 0.5, left: 100px, top: 100px }
|
|
}
|
|
@keyframes empty { }
|
|
</style>
|
|
<body>
|
|
<script>
|
|
'use strict';
|
|
|
|
test(function(t) {
|
|
var div = addDiv(t);
|
|
assert_equals(div.getAnimations().length, 0,
|
|
'getAnimations returns an empty sequence for an element'
|
|
+ ' with no animations');
|
|
}, 'getAnimations for non-animated content');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t);
|
|
|
|
// FIXME: This test does too many things. It should be split up.
|
|
|
|
// Add an animation
|
|
div.style.animation = 'anim1 100s';
|
|
var animations = div.getAnimations();
|
|
assert_equals(animations.length, 1,
|
|
'getAnimations returns an Animation running CSS Animations');
|
|
animations[0].ready.then(t.step_func(function() {
|
|
var startTime = animations[0].startTime;
|
|
assert_true(startTime > 0 && startTime <= document.timeline.currentTime,
|
|
'CSS animation has a sensible start time');
|
|
|
|
// Wait a moment then add a second animation.
|
|
//
|
|
// We wait for the next frame so that we can test that the start times of
|
|
// the animations differ.
|
|
return waitForFrame();
|
|
})).then(t.step_func(function() {
|
|
div.style.animation = 'anim1 100s, anim2 100s';
|
|
animations = div.getAnimations();
|
|
assert_equals(animations.length, 2,
|
|
'getAnimations returns one Animation for each value of'
|
|
+ ' animation-name');
|
|
// Wait until both Animations are ready
|
|
// (We don't make any assumptions about the order of the Animations since
|
|
// that is the purpose of the following test.)
|
|
return waitForAllAnimations(animations);
|
|
})).then(t.step_func(function() {
|
|
assert_true(animations[0].startTime < animations[1].startTime,
|
|
'Additional Animations for CSS animations start after the original'
|
|
+ ' animation and appear later in the list');
|
|
t.done();
|
|
}));
|
|
}, 'getAnimations for CSS Animations');
|
|
|
|
test(function(t) {
|
|
var div = addDiv(t, { style: 'animation: anim1 100s' });
|
|
assert_class_string(div.getAnimations()[0], 'CSSAnimation',
|
|
'Interface of returned animation is CSSAnimation');
|
|
}, 'getAnimations returns CSSAnimation objects for CSS Animations');
|
|
|
|
test(function(t) {
|
|
var div = addDiv(t);
|
|
|
|
// Add an animation that targets multiple properties
|
|
div.style.animation = 'multiPropAnim 100s';
|
|
assert_equals(div.getAnimations().length, 1,
|
|
'getAnimations returns only one Animation for a CSS Animation'
|
|
+ ' that targets multiple properties');
|
|
}, 'getAnimations for multi-property animations');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t);
|
|
|
|
// Add an animation
|
|
div.style.backgroundColor = 'red';
|
|
div.style.animation = 'anim1 100s';
|
|
window.getComputedStyle(div).backgroundColor;
|
|
|
|
// Wait until a frame after the animation starts, then add a transition
|
|
var animations = div.getAnimations();
|
|
animations[0].ready.then(waitForFrame).then(t.step_func(function() {
|
|
div.style.transition = 'all 100s';
|
|
div.style.backgroundColor = 'green';
|
|
|
|
animations = div.getAnimations();
|
|
assert_equals(animations.length, 2,
|
|
'getAnimations returns Animations for both animations and'
|
|
+ ' transitions that run simultaneously');
|
|
assert_class_string(animations[0], 'CSSTransition',
|
|
'First-returned animation is the CSS Transition');
|
|
assert_class_string(animations[1], 'CSSAnimation',
|
|
'Second-returned animation is the CSS Animation');
|
|
t.done();
|
|
}));
|
|
}, 'getAnimations for both CSS Animations and CSS Transitions at once');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t);
|
|
|
|
// Set up event listener
|
|
div.addEventListener('animationend', t.step_func(function() {
|
|
assert_equals(div.getAnimations().length, 0,
|
|
'getAnimations does not return Animations for finished '
|
|
+ ' (and non-forwards-filling) CSS Animations');
|
|
t.done();
|
|
}));
|
|
|
|
// Add a very short animation
|
|
div.style.animation = 'anim1 0.01s';
|
|
}, 'getAnimations for CSS Animations that have finished');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t);
|
|
|
|
// Set up event listener
|
|
div.addEventListener('animationend', t.step_func(function() {
|
|
assert_equals(div.getAnimations().length, 1,
|
|
'getAnimations returns Animations for CSS Animations that have'
|
|
+ ' finished but are filling forwards');
|
|
t.done();
|
|
}));
|
|
|
|
// Add a very short animation
|
|
div.style.animation = 'anim1 0.01s forwards';
|
|
}, 'getAnimations for CSS Animations that have finished but are'
|
|
+ ' forwards filling');
|
|
|
|
test(function(t) {
|
|
var div = addDiv(t);
|
|
div.style.animation = 'none 100s';
|
|
|
|
var animations = div.getAnimations();
|
|
assert_equals(animations.length, 0,
|
|
'getAnimations returns an empty sequence for an element'
|
|
+ ' with animation-name: none');
|
|
|
|
div.style.animation = 'none 100s, anim1 100s';
|
|
animations = div.getAnimations();
|
|
assert_equals(animations.length, 1,
|
|
'getAnimations returns Animations only for those CSS Animations whose'
|
|
+ ' animation-name is not none');
|
|
}, 'getAnimations for CSS Animations with animation-name: none');
|
|
|
|
test(function(t) {
|
|
var div = addDiv(t);
|
|
div.style.animation = 'missing 100s';
|
|
var animations = div.getAnimations();
|
|
assert_equals(animations.length, 0,
|
|
'getAnimations returns an empty sequence for an element'
|
|
+ ' with animation-name: missing');
|
|
|
|
div.style.animation = 'anim1 100s, missing 100s';
|
|
animations = div.getAnimations();
|
|
assert_equals(animations.length, 1,
|
|
'getAnimations returns Animations only for those CSS Animations whose'
|
|
+ ' animation-name is found');
|
|
}, 'getAnimations for CSS Animations with animation-name: missing');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t);
|
|
div.style.animation = 'anim1 100s, notyet 100s';
|
|
var animations = div.getAnimations();
|
|
assert_equals(animations.length, 1,
|
|
'getAnimations initally only returns Animations for CSS Animations whose'
|
|
+ ' animation-name is found');
|
|
|
|
animations[0].ready.then(waitForFrame).then(t.step_func(function() {
|
|
var keyframes = '@keyframes notyet { to { left: 100px; } }';
|
|
document.styleSheets[0].insertRule(keyframes, 0);
|
|
animations = div.getAnimations();
|
|
assert_equals(animations.length, 2,
|
|
'getAnimations includes Animation when @keyframes rule is added'
|
|
+ ' later');
|
|
return waitForAllAnimations(animations);
|
|
})).then(t.step_func(function() {
|
|
assert_true(animations[0].startTime < animations[1].startTime,
|
|
'Newly added animation has a later start time');
|
|
document.styleSheets[0].deleteRule(0);
|
|
t.done();
|
|
}));
|
|
}, 'getAnimations for CSS Animations where the @keyframes rule is added'
|
|
+ ' later');
|
|
|
|
test(function(t) {
|
|
var div = addDiv(t);
|
|
div.style.animation = 'anim1 100s, anim1 100s';
|
|
assert_equals(div.getAnimations().length, 2,
|
|
'getAnimations returns one Animation for each CSS animation-name'
|
|
+ ' even if the names are duplicated');
|
|
}, 'getAnimations for CSS Animations with duplicated animation-name');
|
|
|
|
test(function(t) {
|
|
var div = addDiv(t);
|
|
div.style.animation = 'empty 100s';
|
|
assert_equals(div.getAnimations().length, 1,
|
|
'getAnimations returns Animations for CSS animations with an'
|
|
+ ' empty keyframes rule');
|
|
}, 'getAnimations for CSS Animations with empty keyframes rule');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t);
|
|
div.style.animation = 'anim1 100s 100s';
|
|
var animations = div.getAnimations();
|
|
assert_equals(animations.length, 1,
|
|
'getAnimations returns animations for CSS animations whose'
|
|
+ ' delay makes them start later');
|
|
animations[0].ready.then(waitForFrame).then(t.step_func(function() {
|
|
assert_true(animations[0].startTime <= document.timeline.currentTime,
|
|
'For CSS Animations in delay phase, the start time of the Animation is'
|
|
+ ' not in the future');
|
|
t.done();
|
|
}));
|
|
}, 'getAnimations for CSS animations in delay phase');
|
|
|
|
test(function(t) {
|
|
var div = addDiv(t);
|
|
div.style.animation = 'anim1 0s 100s';
|
|
assert_equals(div.getAnimations().length, 1,
|
|
'getAnimations returns animations for CSS animations whose'
|
|
+ ' duration is zero');
|
|
div.remove();
|
|
}, 'getAnimations for zero-duration CSS Animations');
|
|
|
|
test(function(t) {
|
|
var div = addDiv(t);
|
|
div.style.animation = 'anim1 100s';
|
|
var originalAnimation = div.getAnimations()[0];
|
|
|
|
// Update pause state (an Animation change)
|
|
div.style.animationPlayState = 'paused';
|
|
var pendingAnimation = div.getAnimations()[0];
|
|
assert_equals(pendingAnimation.playState, 'pending',
|
|
'animation\'s play state is updated');
|
|
assert_equals(originalAnimation, pendingAnimation,
|
|
'getAnimations returns the same objects even when their'
|
|
+ ' play state changes');
|
|
|
|
// Update duration (an Animation change)
|
|
div.style.animationDuration = '200s';
|
|
var extendedAnimation = div.getAnimations()[0];
|
|
// FIXME: Check extendedAnimation.effect.timing.duration has changed once the
|
|
// API is available
|
|
assert_equals(originalAnimation, extendedAnimation,
|
|
'getAnimations returns the same objects even when their'
|
|
+ ' duration changes');
|
|
}, 'getAnimations returns objects with the same identity');
|
|
|
|
test(function(t) {
|
|
var div = addDiv(t);
|
|
div.style.animation = 'anim1 100s';
|
|
|
|
assert_equals(div.getAnimations().length, 1,
|
|
'getAnimations returns an animation before cancelling');
|
|
|
|
var animation = div.getAnimations()[0];
|
|
|
|
animation.cancel();
|
|
assert_equals(div.getAnimations().length, 0,
|
|
'getAnimations does not return cancelled animations');
|
|
|
|
animation.play();
|
|
assert_equals(div.getAnimations().length, 1,
|
|
'getAnimations returns cancelled animations that have been re-started');
|
|
|
|
}, 'getAnimations for CSS Animations that are cancelled');
|
|
|
|
async_test(function(t) {
|
|
var div = addDiv(t);
|
|
div.style.animation = 'anim2 100s';
|
|
|
|
div.getAnimations()[0].ready.then(t.step_func(function() {
|
|
// Prepend to the list and test that even though anim1 was triggered
|
|
// *after* anim2, it should come first because it appears first
|
|
// in the animation-name property.
|
|
div.style.animation = 'anim1 100s, anim2 100s';
|
|
var anims = div.getAnimations();
|
|
assert_equals(anims[0].animationName, 'anim1',
|
|
'animation order after prepending to list');
|
|
assert_equals(anims[1].animationName, 'anim2',
|
|
'animation order after prepending to list');
|
|
|
|
// Normally calling cancel and play would this push anim1 to the top of
|
|
// the stack but it shouldn't for CSS animations that map an the
|
|
// animation-name property.
|
|
var anim1 = anims[0];
|
|
anim1.cancel();
|
|
anim1.play();
|
|
anims = div.getAnimations();
|
|
assert_equals(anims[0].animationName, 'anim1',
|
|
'animation order after cancelling and restarting');
|
|
assert_equals(anims[1].animationName, 'anim2',
|
|
'animation order after cancelling and restarting');
|
|
t.done();
|
|
}));
|
|
}, 'getAnimations for CSS Animations follows animation-name order');
|
|
|
|
done();
|
|
</script>
|
|
</body>
|