<!doctype html> <meta charset=utf-8> <script src="../testcommon.js"></script> <style> @keyframes animLeft { to { left: 100px } } @keyframes animTop { to { top: 100px } } @keyframes animBottom { to { bottom: 100px } } @keyframes animRight { to { right: 100px } } </style> <body> <script> 'use strict'; test(function(t) { assert_equals(document.getAnimations().length, 0, 'getAnimations returns an empty sequence for a document' + ' with no animations'); }, 'getAnimations for non-animated content'); test(function(t) { var div = addDiv(t); // Add an animation div.style.animation = 'animLeft 100s'; assert_equals(document.getAnimations().length, 1, 'getAnimations returns a running CSS Animation'); // Add another animation div.style.animation = 'animLeft 100s, animTop 100s'; assert_equals(document.getAnimations().length, 2, 'getAnimations returns two running CSS Animations'); // Remove both div.style.animation = ''; assert_equals(document.getAnimations().length, 0, 'getAnimations returns no running CSS Animations'); }, 'getAnimations for CSS Animations'); test(function(t) { var div = addDiv(t); div.style.animation = 'animLeft 100s, animTop 100s, animRight 100s, ' + 'animBottom 100s'; var animations = document.getAnimations(); assert_equals(animations.length, 4, 'getAnimations returns all running CSS Animations'); assert_equals(animations[0].animationName, 'animLeft', 'Order of first animation returned'); assert_equals(animations[1].animationName, 'animTop', 'Order of second animation returned'); assert_equals(animations[2].animationName, 'animRight', 'Order of third animation returned'); assert_equals(animations[3].animationName, 'animBottom', 'Order of fourth animation returned'); }, 'Order of CSS Animations - within an element'); test(function(t) { var div1 = addDiv(t, { style: 'animation: animLeft 100s' }); var div2 = addDiv(t, { style: 'animation: animLeft 100s' }); var div3 = addDiv(t, { style: 'animation: animLeft 100s' }); var div4 = addDiv(t, { style: 'animation: animLeft 100s' }); var animations = document.getAnimations(); assert_equals(animations.length, 4, 'getAnimations returns all running CSS Animations'); assert_equals(animations[0].effect.target, div1, 'Order of first animation returned'); assert_equals(animations[1].effect.target, div2, 'Order of second animation returned'); assert_equals(animations[2].effect.target, div3, 'Order of third animation returned'); assert_equals(animations[3].effect.target, div4, 'Order of fourth animation returned'); // Order should be depth-first pre-order so add some depth as follows: // // <parent> // / | // 2 3 // / \ // 1 4 // // Which should give: 2, 1, 4, 3 div2.appendChild(div1); div2.appendChild(div4); animations = document.getAnimations(); assert_equals(animations[0].effect.target, div2, 'Order of first animation returned after tree surgery'); assert_equals(animations[1].effect.target, div1, 'Order of second animation returned after tree surgery'); assert_equals(animations[2].effect.target, div4, 'Order of third animation returned after tree surgery'); assert_equals(animations[3].effect.target, div3, 'Order of fourth animation returned after tree surgery'); }, 'Order of CSS Animations - across elements'); test(function(t) { var div1 = addDiv(t, { style: 'animation: animLeft 100s, animTop 100s' }); var div2 = addDiv(t, { style: 'animation: animBottom 100s' }); var expectedResults = [ [ div1, 'animLeft' ], [ div1, 'animTop' ], [ div2, 'animBottom' ] ]; var animations = document.getAnimations(); assert_equals(animations.length, expectedResults.length, 'getAnimations returns all running CSS Animations'); animations.forEach(function(anim, i) { assert_equals(anim.effect.target, expectedResults[i][0], 'Target of animation in position ' + i); assert_equals(anim.animationName, expectedResults[i][1], 'Name of animation in position ' + i); }); // Modify tree structure and animation list div2.appendChild(div1); div1.style.animation = 'animLeft 100s, animRight 100s, animTop 100s'; expectedResults = [ [ div2, 'animBottom' ], [ div1, 'animLeft' ], [ div1, 'animRight' ], [ div1, 'animTop' ] ]; animations = document.getAnimations(); assert_equals(animations.length, expectedResults.length, 'getAnimations returns all running CSS Animations after ' + 'making changes'); animations.forEach(function(anim, i) { assert_equals(anim.effect.target, expectedResults[i][0], 'Target of animation in position ' + i + ' after changes'); assert_equals(anim.animationName, expectedResults[i][1], 'Name of animation in position ' + i + ' after changes'); }); }, 'Order of CSS Animations - across and within elements'); test(function(t) { var div = addDiv(t, { style: 'animation: animLeft 100s, animTop 100s' }); var animLeft = document.getAnimations()[0]; assert_equals(animLeft.animationName, 'animLeft', 'Originally, animLeft animation comes first'); // Disassociate animLeft from markup and restart div.style.animation = 'animTop 100s'; animLeft.play(); var animations = document.getAnimations(); assert_equals(animations.length, 2, 'getAnimations returns markup-bound and free animations'); assert_equals(animations[0].animationName, 'animTop', 'Markup-bound animations come first'); assert_equals(animations[1], animLeft, 'Free animations come last'); }, 'Order of CSS Animations - markup-bound vs free animations'); test(function(t) { var div = addDiv(t, { style: 'animation: animLeft 100s, animTop 100s' }); var animLeft = document.getAnimations()[0]; var animTop = document.getAnimations()[1]; // Disassociate both animations from markup and restart in opposite order div.style.animation = ''; animTop.play(); animLeft.play(); var animations = document.getAnimations(); assert_equals(animations.length, 2, 'getAnimations returns free animations'); assert_equals(animations[0], animTop, 'Free animations are returned in the order they are started'); assert_equals(animations[1], animLeft, 'Animations started later are returned later'); // Restarting an animation should have no effect animTop.cancel(); animTop.play(); assert_equals(document.getAnimations()[0], animTop, 'After restarting, the ordering of free animations' + ' does not change'); }, 'Order of CSS Animations - free animations'); test(function(t) { // Add an animation first var div = addDiv(t, { style: 'animation: animLeft 100s' }); div.style.top = '0px'; div.style.transition = 'all 100s'; flushComputedStyle(div); // *Then* add a transition div.style.top = '100px'; flushComputedStyle(div); // Although the transition was added later, it should come first in the list var animations = document.getAnimations(); assert_equals(animations.length, 2, 'Both CSS animations and transitions are returned'); assert_class_string(animations[0], 'CSSTransition', 'Transition comes first'); assert_class_string(animations[1], 'CSSAnimation', 'Animation comes second'); }, 'Order of CSS Animations and CSS Transitions'); test(function(t) { var div = addDiv(t, { style: 'animation: animLeft 100s forwards' }); div.getAnimations()[0].finish(); assert_equals(document.getAnimations().length, 1, 'Forwards-filling CSS animations are returned'); }, 'Finished but filling CSS Animations are returned'); test(function(t) { var div = addDiv(t, { style: 'animation: animLeft 100s' }); div.getAnimations()[0].finish(); assert_equals(document.getAnimations().length, 0, 'Non-filling finished CSS animations are not returned'); }, 'Finished but not filling CSS Animations are not returned'); test(function(t) { var div = addDiv(t, { style: 'animation: animLeft 100s 100s' }); assert_equals(document.getAnimations().length, 1, 'Yet-to-start CSS animations are returned'); }, 'Yet-to-start CSS Animations are returned'); test(function(t) { var div = addDiv(t, { style: 'animation: animLeft 100s' }); div.getAnimations()[0].cancel(); assert_equals(document.getAnimations().length, 0, 'CSS animations cancelled by the API are not returned'); }, 'CSS Animations cancelled via the API are not returned'); test(function(t) { var div = addDiv(t, { style: 'animation: animLeft 100s' }); var anim = div.getAnimations()[0]; anim.cancel(); anim.play(); assert_equals(document.getAnimations().length, 1, 'CSS animations cancelled and restarted by the API are ' + 'returned'); }, 'CSS Animations cancelled and restarted via the API are returned'); test(function(t) { addStyle(t, { '#parent::after': 'animation: animLeft 10s;', '#parent::before': 'animation: animRight 10s;' }); // create two divs with these arrangement: // parent // ::before, // ::after // | // child var parent = addDiv(t, { 'id': 'parent' }); var child = addDiv(t); parent.appendChild(child); [parent, child].forEach((div) => { div.setAttribute('style', 'animation: animBottom 10s'); }); var anims = document.getAnimations(); assert_equals(anims.length, 4, 'CSS animations on both pseudo-elements and elements ' + 'are returned'); assert_equals(anims[0].effect.target, parent, 'The animation targeting the parent element comes first'); assert_equals(anims[1].effect.target.type, '::before', 'The animation targeting the ::before element comes second'); assert_equals(anims[2].effect.target.type, '::after', 'The animation targeting the ::after element comes third'); assert_equals(anims[3].effect.target, child, 'The animation targeting the child element comes last'); }, 'CSS Animations targetting (pseudo-)elements should have correct order ' + 'after sorting'); done(); </script> </body>