CSSAnimation-effect.tentative.html (7490B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <title>CSSAnimation.effect</title> 4 <meta name="timeout" content="long"> 5 <!-- TODO: Add a more specific link for this once it is specified. --> 6 <link rel="help" href="https://drafts.csswg.org/css-animations-2/#cssanimation"> 7 <script src="/resources/testharness.js"></script> 8 <script src="/resources/testharnessreport.js"></script> 9 <script src="support/testcommon.js"></script> 10 <style> 11 @keyframes anim { 12 from { 13 margin-left: 0px; 14 } 15 to { 16 margin-left: 100px; 17 } 18 } 19 </style> 20 <div id="log"></div> 21 <script> 22 'use strict'; 23 24 promise_test(async t => { 25 const div = addDiv(t); 26 div.style.animation = 'anim 100s'; 27 28 const watcher = new EventWatcher(t, div, [ 'animationend', 29 'animationcancel' ], 30 fastEventsTimeout); 31 const animation = div.getAnimations()[0]; 32 await animation.ready; 33 34 animation.currentTime = 50 * MS_PER_SEC; 35 animation.effect = null; 36 assert_equals(animation.playState, 'finished'); 37 assert_equals(getComputedStyle(div).marginLeft, '0px'); 38 await watcher.wait_for('animationend'); 39 }, 'Setting a null effect on a running animation fires an animationend event'); 40 41 promise_test(async t => { 42 const div = addDiv(t); 43 div.style.animation = 'anim 100s'; 44 45 const animation = div.getAnimations()[0]; 46 await animation.ready; 47 48 animation.currentTime = 50 * MS_PER_SEC; 49 animation.effect = new KeyframeEffect(div, 50 { left: [ '0px' , '100px'] }, 51 100 * MS_PER_SEC); 52 assert_equals(getComputedStyle(div).marginLeft, '0px'); 53 assert_equals(getComputedStyle(div).left, '50px'); 54 }, 'Replacing an animation\'s effect with an effect that targets a different ' + 55 'property should update both properties'); 56 57 promise_test(async t => { 58 const div = addDiv(t); 59 div.style.animation = 'anim 100s'; 60 61 const animation = div.getAnimations()[0]; 62 await animation.ready; 63 64 animation.currentTime = 50 * MS_PER_SEC; 65 animation.effect = new KeyframeEffect(div, 66 { left: [ '0px' , '100px'] }, 67 20 * MS_PER_SEC); 68 assert_equals(animation.playState, 'finished'); 69 }, 'Replacing an animation\'s effect with a shorter one that should have ' + 70 'already finished, the animation finishes immediately'); 71 72 promise_test(async t => { 73 const div = addDiv(t); 74 div.style.animation = 'anim 100s'; 75 76 const animation = div.getAnimations()[0]; 77 assert_true(animation.pending); 78 79 animation.effect = new KeyframeEffect(div, 80 { left: [ '0px' , '100px'] }, 81 100 * MS_PER_SEC); 82 assert_true(animation.pending); 83 84 await animation.ready; 85 86 assert_false(animation.pending); 87 }, 'A play-pending animation\'s effect whose effect is replaced still exits ' + 88 'the pending state'); 89 90 promise_test(async t => { 91 const div1 = addDiv(t); 92 const div2 = addDiv(t); 93 94 const watcher1 = new EventWatcher(t, div1, 'animationstart', 95 fastEventsTimeout); 96 // Watch |div2| as well to ensure it does *not* get events. 97 const watcher2 = new EventWatcher(t, div2, 'animationstart'); 98 99 div1.style.animation = 'anim 100s'; 100 101 const animation = div1.getAnimations()[0]; 102 animation.effect = new KeyframeEffect(div2, 103 { left: [ '0px', '100px' ] }, 104 100 * MS_PER_SEC); 105 106 await watcher1.wait_for('animationstart'); 107 108 assert_equals(animation.effect.target, div2); 109 110 // Then wait a couple of frames and check that no event was dispatched. 111 await waitForAnimationFrames(2); 112 }, 'CSS animation events are dispatched at the original element even after' 113 + ' setting an effect with a different target element'); 114 115 promise_test(async t => { 116 const div = addDiv(t); 117 const watcher = new EventWatcher(t, div, [ 'animationstart', 118 'animationend', 119 'animationcancel' ], 120 fastEventsTimeout); 121 div.style.animation = 'anim 100s'; 122 const animation = div.getAnimations()[0]; 123 animation.finish(); 124 125 await watcher.wait_for([ 'animationstart', 'animationend' ]); 126 // Set a longer effect 127 animation.effect = new KeyframeEffect(div, 128 { left: [ '0px', '100px' ] }, 129 200 * MS_PER_SEC); 130 await watcher.wait_for('animationstart'); 131 }, 'After replacing a finished animation\'s effect with a longer one ' + 132 'it fires an animationstart event'); 133 134 test(t => { 135 const div = addDiv(t); 136 div.style.animation = 'anim 100s'; 137 div.style.animationComposition = 'add'; 138 const animation = div.getAnimations()[0]; 139 assert_equals(animation.effect.composite, 'add'); 140 }, 'Setting animation-composition sets the composite property on the effect'); 141 142 test(t => { 143 const div = addDiv(t); 144 145 // Create custom keyframes so we can tweak them 146 const stylesheet = document.styleSheets[0]; 147 const keyframes = '@keyframes anim-custom { to { left: 100px } }'; 148 const ruleIndex = stylesheet.insertRule(keyframes, 0); 149 const keyframesRule = stylesheet.cssRules[ruleIndex]; 150 151 t.add_cleanup(function() { 152 stylesheet.deleteRule(ruleIndex); 153 }); 154 155 div.style.animation = 'anim-custom 100s'; 156 157 // Replace the effect 158 const animation = div.getAnimations()[0]; 159 animation.effect = new KeyframeEffect( 160 div, 161 { left: '200px' }, 162 200 * MS_PER_SEC 163 ); 164 165 // Update the timing properties 166 div.style.animationDuration = '4s'; 167 div.style.animationIterationCount = '6'; 168 div.style.animationDirection = 'reverse'; 169 div.style.animationDelay = '8s'; 170 div.style.animationFillMode = 'both'; 171 div.style.animationPlayState = 'paused'; 172 div.style.animationComposition = 'add'; 173 div.style.animationTimeline = 'none'; 174 175 // Update the keyframes 176 keyframesRule.deleteRule(0); 177 keyframesRule.appendRule('to { left: 300px }'); 178 179 // Check nothing (except the play state) changed 180 assert_equals( 181 animation.effect.getTiming().duration, 182 200 * MS_PER_SEC, 183 'duration should be the value set by the API' 184 ); 185 assert_equals( 186 animation.effect.getTiming().iterations, 187 1, 188 'iterations should be the value set by the API' 189 ); 190 assert_equals( 191 animation.effect.getTiming().direction, 192 'normal', 193 'direction should be the value set by the API' 194 ); 195 assert_equals( 196 animation.effect.getTiming().delay, 197 0, 198 'delay should be the value set by the API' 199 ); 200 assert_equals( 201 animation.effect.getTiming().fill, 202 'auto', 203 'fill should be the value set by the API' 204 ); 205 assert_equals( 206 animation.effect.getKeyframes()[0].left, 207 '200px', 208 'keyframes should be the value set by the API' 209 ); 210 assert_equals( 211 animation.effect.composite, 212 'replace', 213 'composite should be the value set by the API' 214 ); 215 216 // Unlike the other properties animation-play-state and animation-timeline map 217 // to the Animation, not the KeyframeEffect, so they should be overridden. 218 assert_equals( 219 animation.playState, 220 'paused', 221 'play state should be the value set by style' 222 ); 223 assert_equals( 224 animation.timeline, 225 null, 226 'timeline should be the value set by style' 227 ); 228 }, 'Replacing the effect of a CSSAnimation causes subsequent changes to' 229 + ' corresponding animation-* properties to be ignored'); 230 231 </script>