CSSTransition-effect.tentative.html (7355B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <title>CSSTransition.effect</title> 4 <!-- TODO: Add a more specific link for this once it is specified. --> 5 <link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 <script src='support/helper.js'></script> 9 <div id="log"></div> 10 <script> 11 'use strict'; 12 13 function singleFrame() { 14 return new Promise((resolve, reject) => { 15 requestAnimationFrame(resolve); 16 }); 17 } 18 19 test(t => { 20 const div = addDiv(t); 21 div.style.left = '0px'; 22 23 div.style.transition = 'left 100s'; 24 getComputedStyle(div).left; 25 div.style.left = '100px'; 26 27 const transition = div.getAnimations()[0]; 28 29 transition.effect = null; 30 31 assert_equals(transition.transitionProperty, 'left'); 32 }, 'After setting a transition\'s effect to null, it still reports the' 33 + ' original transition property'); 34 35 promise_test(async t => { 36 const div = addDiv(t); 37 div.style.left = '0px'; 38 39 div.style.transition = 'left 100s'; 40 getComputedStyle(div).left; 41 div.style.left = '100px'; 42 43 const transition = div.getAnimations()[0]; 44 await transition.ready; 45 46 transition.effect = null; 47 assert_equals(transition.playState, 'finished'); 48 }, 'After setting a transition\'s effect to null, it becomes finished'); 49 50 promise_test(async t => { 51 const div = addDiv(t); 52 div.style.left = '0px'; 53 54 div.style.transition = 'left 100s'; 55 getComputedStyle(div).left; 56 div.style.left = '100px'; 57 58 const transition = div.getAnimations()[0]; 59 await transition.ready; 60 61 transition.effect = null; 62 assert_equals(getComputedStyle(div).left, '100px'); 63 }, 'After setting a transition\'s effect to null, style is updated'); 64 65 // This is a regression test for https://crbug.com/964113, where Chromium would 66 // crash if the running transition's effect was set to null and a new transition 67 // was started before the running one could finish. 68 promise_test(async t => { 69 const div = addDiv(t); 70 div.style.left = '0px'; 71 72 div.style.transition = 'left 100s'; 73 getComputedStyle(div).left; 74 div.style.left = '100px'; 75 76 assert_equals(div.getAnimations().length, 1); 77 78 const transition = div.getAnimations()[0]; 79 await transition.ready; 80 81 // Without yielding to the rendering loop, set the current transition's 82 // effect to null and start a new transition. This should work correctly. 83 transition.effect = null; 84 85 div.style.left = '150px'; 86 87 // This will run style update. 88 const animations = div.getAnimations(); 89 assert_equals(animations.length, 1); 90 91 const new_transition = animations[0]; 92 await new_transition.ready; 93 94 assert_not_equals(getComputedStyle(div).left, '150px'); 95 }, 'After setting a transition\'s effect to null, a new transition can be started'); 96 97 // This is a regression test for https://crbug.com/992668, where Chromium would 98 // crash if the running transition's effect was set to null and the transition 99 // was interrupted before it could finish due to the null effect. 100 promise_test(async t => { 101 const div = addDiv(t); 102 div.style.left = '0px'; 103 104 div.style.transition = 'left 100s'; 105 getComputedStyle(div).left; 106 div.style.left = '100px'; 107 108 assert_equals(div.getAnimations().length, 1); 109 110 const transition = div.getAnimations()[0]; 111 await transition.ready; 112 113 // The transition needs to have a non-zero currentTime for the interruption 114 // reversal logic to apply. 115 while (getComputedStyle(div).left == '0px') { 116 await singleFrame(); 117 } 118 assert_not_equals(transition.currentTime, 0); 119 120 // Without yielding to the rendering loop, set the current transition's 121 // effect to null and interrupt the transition. This should work correctly. 122 transition.effect = null; 123 div.style.left = '0px'; 124 125 // Yield to the rendering loop. This should not crash. 126 await singleFrame(); 127 }, 'After setting a transition\'s effect to null, it should be possible to ' 128 + 'interrupt that transition'); 129 130 promise_test(async t => { 131 const div = addDiv(t); 132 div.style.left = '0px'; 133 div.style.width = '0px'; 134 135 div.style.transition = 'left 100s'; 136 getComputedStyle(div).left; 137 div.style.left = '100px'; 138 139 const transition = div.getAnimations()[0]; 140 await transition.ready; 141 142 transition.currentTime = 50 * MS_PER_SEC; 143 transition.effect = new KeyframeEffect(div, 144 { left: [ '0px' , '100px'] }, 145 20 * MS_PER_SEC); 146 147 assert_equals(transition.playState, 'finished'); 148 }, 'After setting a new keyframe effect with a shorter duration,' 149 + ' the transition becomes finished'); 150 151 promise_test(async t => { 152 const div = addDiv(t); 153 div.style.left = '0px'; 154 div.style.width = '0px'; 155 156 div.style.transition = 'left 100s'; 157 getComputedStyle(div).left; 158 div.style.left = '100px'; 159 160 const transition = div.getAnimations()[0]; 161 transition.effect = new KeyframeEffect(div, 162 { marginLeft: [ '0px' , '100px'] }, 163 100 * MS_PER_SEC); 164 assert_equals(transition.transitionProperty, 'left'); 165 }, 'After setting a new keyframe effect targeting different properties,' 166 + ' the transition continues to report the original transition property'); 167 168 promise_test(async t => { 169 const div = addDiv(t); 170 div.style.left = '0px'; 171 div.style.width = '0px'; 172 173 div.style.transition = 'left 100s'; 174 getComputedStyle(div).left; 175 div.style.left = '100px'; 176 177 const transition = div.getAnimations()[0]; 178 assert_true(transition.pending); 179 180 transition.effect = new KeyframeEffect(div, 181 { marginLeft: [ '0px' , '100px'] }, 182 100 * MS_PER_SEC); 183 assert_true(transition.pending); 184 185 // As a sanity check, check that the transition actually exits the 186 // pending state. 187 await transition.ready; 188 assert_false(transition.pending); 189 }, 'After setting a new keyframe effect on a play-pending transition,' 190 + ' the transition remains pending'); 191 192 test(t => { 193 const div = addDiv(t); 194 195 div.style.left = '0px'; 196 getComputedStyle(div).transitionProperty; 197 div.style.transition = 'left 100s'; 198 div.style.left = '100px'; 199 200 const transition = div.getAnimations()[0]; 201 transition.effect = null; 202 203 assert_equals(transition.transitionProperty, 'left'); 204 }, 'A transition with no effect still returns the original transitionProperty'); 205 206 test(t => { 207 const div = addDiv(t); 208 209 div.style.left = '0px'; 210 getComputedStyle(div).transitionProperty; 211 div.style.transition = 'left 100s'; 212 div.style.left = '100px'; 213 214 const transition = div.getAnimations()[0]; 215 216 // Seek to the middle and get the portion. 217 transition.currentTime = 50 * MS_PER_SEC; 218 const portion = transition.effect.getComputedTiming().progress; 219 220 // Replace the effect but keep the original timing 221 transition.effect = new KeyframeEffect( 222 div, 223 { top: ['200px', '300px', '100px'] }, 224 transition.effect.getTiming() 225 ); 226 227 // Reverse the transition 228 div.style.left = '0px'; 229 const reversedTransition = div.getAnimations()[0]; 230 231 const expectedDuration = 100 * MS_PER_SEC * portion; 232 assert_approx_equals( 233 reversedTransition.effect.getComputedTiming().activeDuration, 234 expectedDuration, 235 1 236 ); 237 }, 'A transition with a replaced effect still exhibits the regular transition' 238 + ' reversing behavior'); 239 240 </script>