| <!doctype html> |
| <meta charset=utf-8> |
| <script src="../../../resources/testharness.js"></script> |
| <script src="../../../resources/testharnessreport.js"></script> |
| <script src="../resources/testcommon.js"></script> |
| <style> |
| @keyframes animLeft { |
| to { left: 100px } |
| } |
| @keyframes animTop { |
| to { top: 100px } |
| } |
| @keyframes animBottom { |
| to { bottom: 100px } |
| } |
| @keyframes animRight { |
| to { right: 100px } |
| } |
| ::before { |
| content: '' |
| } |
| ::after { |
| content: '' |
| } |
| </style> |
| <body> |
| <div id="log"></div> |
| <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, { 'id': 'child' }); |
| 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].animationName, 'animRight', |
| 'The animation targeting the ::before element comes second'); |
| assert_equals(anims[2].animationName, 'animLeft', |
| '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'); |
| |
| </script> |
| </body> |