cancel-animation.html (7141B)
1 <!DOCTYPE html> 2 <meta charset=utf-8> 3 <title>Canceling an animation</title> 4 <link rel="help" 5 href="https://drafts.csswg.org/web-animations/#canceling-an-animation-section"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 <script src="/web-animations/testcommon.js"></script> 9 <script src="testcommon.js"></script> 10 <style> 11 .scroller { 12 overflow: auto; 13 height: 100px; 14 width: 100px; 15 will-change: transform; 16 } 17 18 .contents { 19 height: 1000px; 20 width: 100%; 21 } 22 </style> 23 <body> 24 <script> 25 'use strict'; 26 27 promise_test(async t => { 28 let animation; 29 // Wait for new animation frame which allows the timeline to compute new 30 // current time. 31 await runAndWaitForFrameUpdate(() => { 32 animation = createScrollLinkedAnimation(t); 33 }); 34 animation.play(); 35 animation.cancel(); 36 37 assert_equals(animation.startTime, null, 38 'The start time of a canceled animation should be unresolved'); 39 assert_equals(animation.currentTime, null, 40 'The hold time of a canceled animation should be unresolved'); 41 }, 'Canceling an animation should cause its start time and hold time to be' 42 + ' unresolved'); 43 44 promise_test(async t => { 45 const animation = createScrollLinkedAnimation(t); 46 // Wait for new animation frame which allows the timeline to compute new 47 // current time. 48 await waitForNextFrame(); 49 animation.play(); 50 const retPromise = animation.ready.then(() => { 51 assert_unreached('ready promise was fulfilled'); 52 }).catch(err => { 53 assert_equals(err.name, 'AbortError', 54 'ready promise is rejected with AbortError'); 55 }); 56 57 animation.cancel(); 58 59 return retPromise; 60 }, 'A play-pending ready promise should be rejected when the animation is' 61 + ' canceled'); 62 63 promise_test(async t => { 64 const animation = createScrollLinkedAnimation(t); 65 // Wait for new animation frame which allows the timeline to compute new 66 // current time. 67 await waitForNextFrame(); 68 animation.play(); 69 await animation.ready; 70 71 // Make it pause-pending 72 animation.pause(); 73 74 // We need to store the original ready promise since cancel() will 75 // replace it 76 const originalPromise = animation.ready; 77 animation.cancel(); 78 79 await promise_rejects_dom(t, 'AbortError', originalPromise, 80 'Cancel should abort ready promise'); 81 }, 'A pause-pending ready promise should be rejected when the animation is' 82 + ' canceled'); 83 84 promise_test(async t => { 85 const animation = createScrollLinkedAnimation(t); 86 // Wait for new animation frame which allows the timeline to compute new 87 // current time. 88 await waitForNextFrame(); 89 animation.play(); 90 animation.cancel(); 91 const promiseResult = await animation.ready; 92 assert_equals(promiseResult, animation); 93 }, 'When an animation is canceled, it should create a resolved Promise'); 94 95 promise_test(async t => { 96 const animation = createScrollLinkedAnimation(t); 97 // Wait for new animation frame which allows the timeline to compute new 98 // current time. 99 await waitForNextFrame(); 100 animation.play(); 101 const promise = animation.ready; 102 animation.cancel(); 103 assert_not_equals(animation.ready, promise); 104 promise_rejects_dom(t, 'AbortError', promise, 105 'Cancel should abort ready promise'); 106 }, 'The ready promise should be replaced when the animation is canceled'); 107 108 promise_test(async t => { 109 const animation = createScrollLinkedAnimation(t); 110 // Wait for new animation frame which allows the timeline to compute new 111 // current time. 112 await waitForNextFrame(); 113 assert_equals(animation.playState, 'idle', 114 'The animation should be initially idle'); 115 116 animation.finished.then(t.step_func(() => { 117 assert_unreached('Finished promise should not resolve'); 118 }), t.step_func(() => { 119 assert_unreached('Finished promise should not reject'); 120 })); 121 122 animation.cancel(); 123 124 return waitForAnimationFrames(3); 125 }, 'The finished promise should NOT be rejected if the animation is already' 126 + ' idle'); 127 128 promise_test(async t => { 129 const animation = createScrollLinkedAnimation(t); 130 // Wait for new animation frame which allows the timeline to compute new 131 // current time. 132 await waitForNextFrame(); 133 assert_equals(animation.playState, 'idle', 134 'The animation should be initially idle'); 135 136 animation.oncancel = t.step_func(() => { 137 assert_unreached('Cancel event should not be fired'); 138 }); 139 140 animation.cancel(); 141 142 return waitForAnimationFrames(3); 143 }, 'The cancel event should NOT be fired if the animation is already idle'); 144 145 promise_test(async t => { 146 const animation = createScrollLinkedAnimation(t); 147 // Wait for new animation frame which allows the timeline to compute new 148 // current time. 149 await waitForNextFrame(); 150 animation.play(); 151 animation.effect.target.remove(); 152 153 const eventWatcher = new EventWatcher(t, animation, 'cancel'); 154 155 await animation.ready; 156 animation.cancel(); 157 158 await eventWatcher.wait_for('cancel'); 159 160 assert_equals(animation.effect.target.parentNode, null, 161 'cancel event should be fired for the animation on an orphaned element'); 162 }, 'Canceling an animation should fire cancel event on orphaned element'); 163 164 promise_test(async t => { 165 const animation = createScrollLinkedAnimation(t); 166 const scroller = animation.timeline.source; 167 168 // Wait for new animation frame which allows the timeline to compute new 169 // current time. 170 await waitForNextFrame(); 171 animation.play(); 172 await animation.ready; 173 174 // Make the scroll timeline inactive. 175 await runAndWaitForFrameUpdate(() => { 176 scroller.style.overflow = 'visible'; 177 }); 178 assert_equals(animation.timeline.currentTime, null, 179 'Sanity check the timeline is inactive.'); 180 animation.cancel(); 181 assert_equals(animation.startTime, null, 182 'The start time of a canceled animation should be unresolved'); 183 assert_equals(animation.currentTime, null, 184 'The current time of a canceled animation should be unresolved'); 185 }, 'Canceling an animation with inactive timeline should cause its start time' 186 + ' and hold time to be unresolved'); 187 188 promise_test(async t => { 189 const animation = createScrollLinkedAnimation(t); 190 const scroller = animation.timeline.source; 191 192 // Wait for new animation frame which allows the timeline to compute new 193 // current time. 194 await waitForNextFrame(); 195 animation.play(); 196 await animation.ready; 197 198 // Make the scroll timeline inactive. 199 await runAndWaitForFrameUpdate(() => { 200 scroller.style.overflow = 'visible'; 201 }); 202 assert_equals(animation.timeline.currentTime, null, 203 'Sanity check the timeline is inactive.'); 204 205 const eventWatcher = new EventWatcher(t, animation, 'cancel'); 206 animation.cancel(); 207 const cancelEvent = await eventWatcher.wait_for('cancel'); 208 209 assert_equals(cancelEvent.currentTime, null, 210 'event.currentTime should be unresolved when the timeline is inactive.'); 211 assert_equals(cancelEvent.timelineTime, null, 212 'event.timelineTime should be unresolved when the timeline is inactive'); 213 }, 'oncancel event is fired when the timeline is inactive.'); 214 215 </script> 216 </body>