| OLD | NEW |
| (Empty) | |
| 1 <!DOCTYPE html> |
| 2 <meta charset=utf-8> |
| 3 <title>Animation.finished</title> |
| 4 <link rel="help" href="https://w3c.github.io/web-animations/#dom-animation-finis
hed"> |
| 5 <script src="../../../../resources/testharness.js"></script> |
| 6 <script src="../../../../resources/testharnessreport.js"></script> |
| 7 <script src="../testcommon.js"></script> |
| 8 <link rel="stylesheet" href="../../../../resources/testharness.css"> |
| 9 <body> |
| 10 <div id="log"></div> |
| 11 <script> |
| 12 "use strict"; |
| 13 |
| 14 promise_test(function(t) { |
| 15 var div = createDiv(t); |
| 16 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 17 var previousFinishedPromise = animation.finished; |
| 18 return animation.ready.then(function() { |
| 19 assert_equals(animation.finished, previousFinishedPromise, |
| 20 'Finished promise is the same object when playing starts'); |
| 21 animation.pause(); |
| 22 assert_equals(animation.finished, previousFinishedPromise, |
| 23 'Finished promise does not change when pausing'); |
| 24 animation.play(); |
| 25 assert_equals(animation.finished, previousFinishedPromise, |
| 26 'Finished promise does not change when play() unpauses'); |
| 27 |
| 28 animation.currentTime = 100 * MS_PER_SEC; |
| 29 |
| 30 return animation.finished; |
| 31 }).then(function() { |
| 32 assert_equals(animation.finished, previousFinishedPromise, |
| 33 'Finished promise is the same object when playing completes'); |
| 34 }); |
| 35 }, 'Test pausing then playing does not change the finished promise'); |
| 36 |
| 37 promise_test(function(t) { |
| 38 var div = createDiv(t); |
| 39 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 40 var previousFinishedPromise = animation.finished; |
| 41 animation.finish(); |
| 42 return animation.finished.then(function() { |
| 43 assert_equals(animation.finished, previousFinishedPromise, |
| 44 'Finished promise is the same object when playing completes'); |
| 45 animation.play(); |
| 46 assert_not_equals(animation.finished, previousFinishedPromise, |
| 47 'Finished promise changes when replaying animation'); |
| 48 |
| 49 previousFinishedPromise = animation.finished; |
| 50 animation.play(); |
| 51 assert_equals(animation.finished, previousFinishedPromise, |
| 52 'Finished promise is the same after redundant play() call'); |
| 53 |
| 54 }); |
| 55 }, 'Test restarting a finished animation'); |
| 56 |
| 57 promise_test(function(t) { |
| 58 var div = createDiv(t); |
| 59 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 60 var previousFinishedPromise; |
| 61 animation.finish(); |
| 62 return animation.finished.then(function() { |
| 63 previousFinishedPromise = animation.finished; |
| 64 animation.playbackRate = -1; |
| 65 assert_not_equals(animation.finished, previousFinishedPromise, |
| 66 'Finished promise should be replaced when reversing a ' + |
| 67 'finished promise'); |
| 68 animation.currentTime = 0; |
| 69 return animation.finished; |
| 70 }).then(function() { |
| 71 previousFinishedPromise = animation.finished; |
| 72 animation.play(); |
| 73 assert_not_equals(animation.finished, previousFinishedPromise, |
| 74 'Finished promise is replaced after play() call on ' + |
| 75 'finished, reversed animation'); |
| 76 }); |
| 77 }, 'Test restarting a reversed finished animation'); |
| 78 |
| 79 promise_test(function(t) { |
| 80 var div = createDiv(t); |
| 81 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 82 var previousFinishedPromise = animation.finished; |
| 83 animation.finish(); |
| 84 return animation.finished.then(function() { |
| 85 animation.currentTime = 100 * MS_PER_SEC + 1000; |
| 86 assert_equals(animation.finished, previousFinishedPromise, |
| 87 'Finished promise is unchanged jumping past end of ' + |
| 88 'finished animation'); |
| 89 }); |
| 90 }, 'Test redundant finishing of animation'); |
| 91 |
| 92 promise_test(function(t) { |
| 93 var div = createDiv(t); |
| 94 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 95 // Setup callback to run if finished promise is resolved |
| 96 var finishPromiseResolved = false; |
| 97 animation.finished.then(function() { |
| 98 finishPromiseResolved = true; |
| 99 }); |
| 100 return animation.ready.then(function() { |
| 101 // Jump to mid-way in interval and pause |
| 102 animation.currentTime = 100 * MS_PER_SEC / 2; |
| 103 animation.pause(); |
| 104 return animation.ready; |
| 105 }).then(function() { |
| 106 // Jump to the end |
| 107 // (But don't use finish() since that should unpause as well) |
| 108 animation.currentTime = 100 * MS_PER_SEC; |
| 109 return waitForAnimationFrames(2); |
| 110 }).then(function() { |
| 111 assert_false(finishPromiseResolved, |
| 112 'Finished promise should not resolve when paused'); |
| 113 }); |
| 114 }, 'Finished promise does not resolve when paused'); |
| 115 |
| 116 promise_test(function(t) { |
| 117 var div = createDiv(t); |
| 118 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 119 // Setup callback to run if finished promise is resolved |
| 120 var finishPromiseResolved = false; |
| 121 animation.finished.then(function() { |
| 122 finishPromiseResolved = true; |
| 123 }); |
| 124 return animation.ready.then(function() { |
| 125 // Jump to mid-way in interval and pause |
| 126 animation.currentTime = 100 * MS_PER_SEC / 2; |
| 127 animation.pause(); |
| 128 // Jump to the end |
| 129 animation.currentTime = 100 * MS_PER_SEC; |
| 130 return waitForAnimationFrames(2); |
| 131 }).then(function() { |
| 132 assert_false(finishPromiseResolved, |
| 133 'Finished promise should not resolve when pause-pending'); |
| 134 }); |
| 135 }, 'Finished promise does not resolve when pause-pending'); |
| 136 |
| 137 promise_test(function(t) { |
| 138 var div = createDiv(t); |
| 139 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 140 animation.finish(); |
| 141 return animation.finished.then(function(resolvedAnimation) { |
| 142 assert_equals(resolvedAnimation, animation, |
| 143 'Object identity of animation passed to Promise callback' |
| 144 + ' matches the animation object owning the Promise'); |
| 145 }); |
| 146 }, 'The finished promise is fulfilled with its Animation'); |
| 147 |
| 148 promise_test(function(t) { |
| 149 var div = createDiv(t); |
| 150 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 151 var previousFinishedPromise = animation.finished; |
| 152 |
| 153 // Set up listeners on finished promise |
| 154 var retPromise = animation.finished.then(function() { |
| 155 assert_unreached('finished promise was fulfilled'); |
| 156 }).catch(function(err) { |
| 157 assert_equals(err.name, 'AbortError', |
| 158 'finished promise is rejected with AbortError'); |
| 159 assert_not_equals(animation.finished, previousFinishedPromise, |
| 160 'Finished promise should change after the original is ' + |
| 161 'rejected'); |
| 162 }); |
| 163 |
| 164 animation.cancel(); |
| 165 |
| 166 return retPromise; |
| 167 }, 'finished promise is rejected when an animation is cancelled by calling ' + |
| 168 'cancel()'); |
| 169 |
| 170 promise_test(function(t) { |
| 171 var div = createDiv(t); |
| 172 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 173 var previousFinishedPromise = animation.finished; |
| 174 animation.finish(); |
| 175 return animation.finished.then(function() { |
| 176 animation.cancel(); |
| 177 assert_not_equals(animation.finished, previousFinishedPromise, |
| 178 'A new finished promise should be created when' |
| 179 + ' cancelling a finished animation'); |
| 180 }); |
| 181 }, 'cancelling an already-finished animation replaces the finished promise'); |
| 182 |
| 183 promise_test(function(t) { |
| 184 var div = createDiv(t); |
| 185 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 186 animation.cancel(); |
| 187 // The spec says we still create a new finished promise and reject the old |
| 188 // one even if we're already idle. That behavior might change, but for now |
| 189 // test that we do that. |
| 190 var retPromise = animation.finished.catch(function(err) { |
| 191 assert_equals(err.name, 'AbortError', |
| 192 'finished promise is rejected with AbortError'); |
| 193 }); |
| 194 |
| 195 // Redundant call to cancel(); |
| 196 var previousFinishedPromise = animation.finished; |
| 197 animation.cancel(); |
| 198 assert_not_equals(animation.finished, previousFinishedPromise, |
| 199 'A redundant call to cancel() should still generate a new' |
| 200 + ' finished promise'); |
| 201 return retPromise; |
| 202 }, 'cancelling an idle animation still replaces the finished promise'); |
| 203 |
| 204 promise_test(function(t) { |
| 205 var div = createDiv(t); |
| 206 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 207 const HALF_DUR = 100 * MS_PER_SEC / 2; |
| 208 const QUARTER_DUR = 100 * MS_PER_SEC / 4; |
| 209 var gotNextFrame = false; |
| 210 var currentTimeBeforeShortening; |
| 211 animation.currentTime = HALF_DUR; |
| 212 return animation.ready.then(function() { |
| 213 currentTimeBeforeShortening = animation.currentTime; |
| 214 animation.effect.timing.duration = QUARTER_DUR; |
| 215 // Below we use gotNextFrame to check that shortening of the animation |
| 216 // duration causes the finished promise to resolve, rather than it just |
| 217 // getting resolved on the next animation frame. This relies on the fact |
| 218 // that the promises are resolved as a micro-task before the next frame |
| 219 // happens. |
| 220 waitForAnimationFrames(1).then(function() { |
| 221 gotNextFrame = true; |
| 222 }); |
| 223 |
| 224 return animation.finished; |
| 225 }).then(function() { |
| 226 assert_false(gotNextFrame, 'shortening of the animation duration should ' + |
| 227 'resolve the finished promise'); |
| 228 assert_equals(animation.currentTime, currentTimeBeforeShortening, |
| 229 'currentTime should be unchanged when duration shortened'); |
| 230 var previousFinishedPromise = animation.finished; |
| 231 animation.effect.timing.duration = 100 * MS_PER_SEC; |
| 232 assert_not_equals(animation.finished, previousFinishedPromise, |
| 233 'Finished promise should change after lengthening the ' + |
| 234 'duration causes the animation to become active'); |
| 235 }); |
| 236 }, 'Test finished promise changes for animation duration changes'); |
| 237 |
| 238 promise_test(function(t) { |
| 239 var div = createDiv(t); |
| 240 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 241 var retPromise = animation.ready.then(function() { |
| 242 animation.playbackRate = 0; |
| 243 animation.currentTime = 100 * MS_PER_SEC + 1000; |
| 244 return waitForAnimationFrames(2); |
| 245 }); |
| 246 |
| 247 animation.finished.then(t.step_func(function() { |
| 248 assert_unreached('finished promise should not resolve when playbackRate ' + |
| 249 'is zero'); |
| 250 })); |
| 251 |
| 252 return retPromise; |
| 253 }, 'Test finished promise changes when playbackRate == 0'); |
| 254 |
| 255 promise_test(function(t) { |
| 256 var div = createDiv(t); |
| 257 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 258 return animation.ready.then(function() { |
| 259 animation.playbackRate = -1; |
| 260 return animation.finished; |
| 261 }); |
| 262 }, 'Test finished promise resolves when reaching to the natural boundary.'); |
| 263 |
| 264 promise_test(function(t) { |
| 265 var div = createDiv(t); |
| 266 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 267 var previousFinishedPromise = animation.finished; |
| 268 animation.finish(); |
| 269 return animation.finished.then(function() { |
| 270 animation.currentTime = 0; |
| 271 assert_not_equals(animation.finished, previousFinishedPromise, |
| 272 'Finished promise should change once a prior ' + |
| 273 'finished promise resolved and the animation ' + |
| 274 'falls out finished state'); |
| 275 }); |
| 276 }, 'Test finished promise changes when a prior finished promise resolved ' + |
| 277 'and the animation falls out finished state'); |
| 278 |
| 279 test(function(t) { |
| 280 var div = createDiv(t); |
| 281 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 282 var previousFinishedPromise = animation.finished; |
| 283 animation.currentTime = 100 * MS_PER_SEC; |
| 284 animation.currentTime = 100 * MS_PER_SEC / 2; |
| 285 assert_equals(animation.finished, previousFinishedPromise, |
| 286 'No new finished promise generated when finished state ' + |
| 287 'is checked asynchronously'); |
| 288 }, 'Test no new finished promise generated when finished state ' + |
| 289 'is checked asynchronously'); |
| 290 |
| 291 test(function(t) { |
| 292 var div = createDiv(t); |
| 293 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 294 var previousFinishedPromise = animation.finished; |
| 295 animation.finish(); |
| 296 animation.currentTime = 100 * MS_PER_SEC / 2; |
| 297 assert_not_equals(animation.finished, previousFinishedPromise, |
| 298 'New finished promise generated when finished state ' + |
| 299 'is checked synchronously'); |
| 300 }, 'Test new finished promise generated when finished state ' + |
| 301 'is checked synchronously'); |
| 302 |
| 303 promise_test(function(t) { |
| 304 var div = createDiv(t); |
| 305 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 306 var resolvedFinished = false; |
| 307 animation.finished.then(function() { |
| 308 resolvedFinished = true; |
| 309 }); |
| 310 return animation.ready.then(function() { |
| 311 animation.finish(); |
| 312 animation.currentTime = 100 * MS_PER_SEC / 2; |
| 313 }).then(function() { |
| 314 assert_true(resolvedFinished, |
| 315 'Animation.finished should be resolved even if ' + |
| 316 'the finished state is changed soon'); |
| 317 }); |
| 318 |
| 319 }, 'Test synchronous finished promise resolved even if finished state ' + |
| 320 'is changed soon'); |
| 321 |
| 322 promise_test(function(t) { |
| 323 var div = createDiv(t); |
| 324 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 325 var resolvedFinished = false; |
| 326 animation.finished.then(function() { |
| 327 resolvedFinished = true; |
| 328 }); |
| 329 |
| 330 return animation.ready.then(function() { |
| 331 animation.currentTime = 100 * MS_PER_SEC; |
| 332 animation.finish(); |
| 333 }).then(function() { |
| 334 assert_true(resolvedFinished, |
| 335 'Animation.finished should be resolved soon after finish() is ' + |
| 336 'called even if there are other asynchronous promises just before it'); |
| 337 }); |
| 338 }, 'Test synchronous finished promise resolved even if asynchronous ' + |
| 339 'finished promise happens just before synchronous promise'); |
| 340 |
| 341 promise_test(function(t) { |
| 342 var div = createDiv(t); |
| 343 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 344 animation.finished.then(t.step_func(function() { |
| 345 assert_unreached('Animation.finished should not be resolved'); |
| 346 })); |
| 347 |
| 348 return animation.ready.then(function() { |
| 349 animation.currentTime = 100 * MS_PER_SEC; |
| 350 animation.currentTime = 100 * MS_PER_SEC / 2; |
| 351 }); |
| 352 }, 'Test finished promise is not resolved when the animation ' + |
| 353 'falls out finished state immediately'); |
| 354 |
| 355 promise_test(function(t) { |
| 356 var div = createDiv(t); |
| 357 var animation = div.animate({}, 100 * MS_PER_SEC); |
| 358 return animation.ready.then(function() { |
| 359 animation.currentTime = 100 * MS_PER_SEC; |
| 360 animation.finished.then(t.step_func(function() { |
| 361 assert_unreached('Animation.finished should not be resolved'); |
| 362 })); |
| 363 animation.currentTime = 0; |
| 364 }); |
| 365 |
| 366 }, 'Test finished promise is not resolved once the animation ' + |
| 367 'falls out finished state even though the current finished ' + |
| 368 'promise is generated soon after animation state became finished'); |
| 369 |
| 370 </script> |
| 371 </body> |
| OLD | NEW |