| Index: third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation/finished.html | 
| diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation/finished.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation/finished.html | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..dfd6581604e8ce54513df0594241ac761ed032bb | 
| --- /dev/null | 
| +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation/finished.html | 
| @@ -0,0 +1,371 @@ | 
| +<!DOCTYPE html> | 
| +<meta charset=utf-8> | 
| +<title>Animation.finished</title> | 
| +<link rel="help" href="https://w3c.github.io/web-animations/#dom-animation-finished"> | 
| +<script src="../../../../resources/testharness.js"></script> | 
| +<script src="../../../../resources/testharnessreport.js"></script> | 
| +<script src="../testcommon.js"></script> | 
| +<link rel="stylesheet" href="../../../../resources/testharness.css"> | 
| +<body> | 
| +<div id="log"></div> | 
| +<script> | 
| +"use strict"; | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  var previousFinishedPromise = animation.finished; | 
| +  return animation.ready.then(function() { | 
| +    assert_equals(animation.finished, previousFinishedPromise, | 
| +                  'Finished promise is the same object when playing starts'); | 
| +    animation.pause(); | 
| +    assert_equals(animation.finished, previousFinishedPromise, | 
| +                  'Finished promise does not change when pausing'); | 
| +    animation.play(); | 
| +    assert_equals(animation.finished, previousFinishedPromise, | 
| +                  'Finished promise does not change when play() unpauses'); | 
| + | 
| +    animation.currentTime = 100 * MS_PER_SEC; | 
| + | 
| +    return animation.finished; | 
| +  }).then(function() { | 
| +    assert_equals(animation.finished, previousFinishedPromise, | 
| +                  'Finished promise is the same object when playing completes'); | 
| +  }); | 
| +}, 'Test pausing then playing does not change the finished promise'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  var previousFinishedPromise = animation.finished; | 
| +  animation.finish(); | 
| +  return animation.finished.then(function() { | 
| +    assert_equals(animation.finished, previousFinishedPromise, | 
| +                  'Finished promise is the same object when playing completes'); | 
| +    animation.play(); | 
| +    assert_not_equals(animation.finished, previousFinishedPromise, | 
| +                  'Finished promise changes when replaying animation'); | 
| + | 
| +    previousFinishedPromise = animation.finished; | 
| +    animation.play(); | 
| +    assert_equals(animation.finished, previousFinishedPromise, | 
| +                  'Finished promise is the same after redundant play() call'); | 
| + | 
| +  }); | 
| +}, 'Test restarting a finished animation'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  var previousFinishedPromise; | 
| +  animation.finish(); | 
| +  return animation.finished.then(function() { | 
| +    previousFinishedPromise = animation.finished; | 
| +    animation.playbackRate = -1; | 
| +    assert_not_equals(animation.finished, previousFinishedPromise, | 
| +                      'Finished promise should be replaced when reversing a ' + | 
| +                      'finished promise'); | 
| +    animation.currentTime = 0; | 
| +    return animation.finished; | 
| +  }).then(function() { | 
| +    previousFinishedPromise = animation.finished; | 
| +    animation.play(); | 
| +    assert_not_equals(animation.finished, previousFinishedPromise, | 
| +                      'Finished promise is replaced after play() call on ' + | 
| +                      'finished, reversed animation'); | 
| +  }); | 
| +}, 'Test restarting a reversed finished animation'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  var previousFinishedPromise = animation.finished; | 
| +  animation.finish(); | 
| +  return animation.finished.then(function() { | 
| +    animation.currentTime = 100 * MS_PER_SEC + 1000; | 
| +    assert_equals(animation.finished, previousFinishedPromise, | 
| +                  'Finished promise is unchanged jumping past end of ' + | 
| +                  'finished animation'); | 
| +  }); | 
| +}, 'Test redundant finishing of animation'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  // Setup callback to run if finished promise is resolved | 
| +  var finishPromiseResolved = false; | 
| +  animation.finished.then(function() { | 
| +    finishPromiseResolved = true; | 
| +  }); | 
| +  return animation.ready.then(function() { | 
| +    // Jump to mid-way in interval and pause | 
| +    animation.currentTime = 100 * MS_PER_SEC / 2; | 
| +    animation.pause(); | 
| +    return animation.ready; | 
| +  }).then(function() { | 
| +    // Jump to the end | 
| +    // (But don't use finish() since that should unpause as well) | 
| +    animation.currentTime = 100 * MS_PER_SEC; | 
| +    return waitForAnimationFrames(2); | 
| +  }).then(function() { | 
| +    assert_false(finishPromiseResolved, | 
| +                 'Finished promise should not resolve when paused'); | 
| +  }); | 
| +}, 'Finished promise does not resolve when paused'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  // Setup callback to run if finished promise is resolved | 
| +  var finishPromiseResolved = false; | 
| +  animation.finished.then(function() { | 
| +    finishPromiseResolved = true; | 
| +  }); | 
| +  return animation.ready.then(function() { | 
| +    // Jump to mid-way in interval and pause | 
| +    animation.currentTime = 100 * MS_PER_SEC / 2; | 
| +    animation.pause(); | 
| +    // Jump to the end | 
| +    animation.currentTime = 100 * MS_PER_SEC; | 
| +    return waitForAnimationFrames(2); | 
| +  }).then(function() { | 
| +    assert_false(finishPromiseResolved, | 
| +                 'Finished promise should not resolve when pause-pending'); | 
| +  }); | 
| +}, 'Finished promise does not resolve when pause-pending'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  animation.finish(); | 
| +  return animation.finished.then(function(resolvedAnimation) { | 
| +    assert_equals(resolvedAnimation, animation, | 
| +                  'Object identity of animation passed to Promise callback' | 
| +                  + ' matches the animation object owning the Promise'); | 
| +  }); | 
| +}, 'The finished promise is fulfilled with its Animation'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  var previousFinishedPromise = animation.finished; | 
| + | 
| +  // Set up listeners on finished promise | 
| +  var retPromise = animation.finished.then(function() { | 
| +    assert_unreached('finished promise was fulfilled'); | 
| +  }).catch(function(err) { | 
| +    assert_equals(err.name, 'AbortError', | 
| +                  'finished promise is rejected with AbortError'); | 
| +    assert_not_equals(animation.finished, previousFinishedPromise, | 
| +                      'Finished promise should change after the original is ' + | 
| +                      'rejected'); | 
| +  }); | 
| + | 
| +  animation.cancel(); | 
| + | 
| +  return retPromise; | 
| +}, 'finished promise is rejected when an animation is cancelled by calling ' + | 
| +   'cancel()'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  var previousFinishedPromise = animation.finished; | 
| +  animation.finish(); | 
| +  return animation.finished.then(function() { | 
| +    animation.cancel(); | 
| +    assert_not_equals(animation.finished, previousFinishedPromise, | 
| +                      'A new finished promise should be created when' | 
| +                      + ' cancelling a finished animation'); | 
| +  }); | 
| +}, 'cancelling an already-finished animation replaces the finished promise'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  animation.cancel(); | 
| +  // The spec says we still create a new finished promise and reject the old | 
| +  // one even if we're already idle. That behavior might change, but for now | 
| +  // test that we do that. | 
| +  var retPromise = animation.finished.catch(function(err) { | 
| +    assert_equals(err.name, 'AbortError', | 
| +                  'finished promise is rejected with AbortError'); | 
| +  }); | 
| + | 
| +  // Redundant call to cancel(); | 
| +  var previousFinishedPromise = animation.finished; | 
| +  animation.cancel(); | 
| +  assert_not_equals(animation.finished, previousFinishedPromise, | 
| +                    'A redundant call to cancel() should still generate a new' | 
| +                    + ' finished promise'); | 
| +  return retPromise; | 
| +}, 'cancelling an idle animation still replaces the finished promise'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  const HALF_DUR = 100 * MS_PER_SEC / 2; | 
| +  const QUARTER_DUR = 100 * MS_PER_SEC / 4; | 
| +  var gotNextFrame = false; | 
| +  var currentTimeBeforeShortening; | 
| +  animation.currentTime = HALF_DUR; | 
| +  return animation.ready.then(function() { | 
| +    currentTimeBeforeShortening = animation.currentTime; | 
| +    animation.effect.timing.duration = QUARTER_DUR; | 
| +    // Below we use gotNextFrame to check that shortening of the animation | 
| +    // duration causes the finished promise to resolve, rather than it just | 
| +    // getting resolved on the next animation frame. This relies on the fact | 
| +    // that the promises are resolved as a micro-task before the next frame | 
| +    // happens. | 
| +    waitForAnimationFrames(1).then(function() { | 
| +      gotNextFrame = true; | 
| +    }); | 
| + | 
| +    return animation.finished; | 
| +  }).then(function() { | 
| +    assert_false(gotNextFrame, 'shortening of the animation duration should ' + | 
| +                               'resolve the finished promise'); | 
| +    assert_equals(animation.currentTime, currentTimeBeforeShortening, | 
| +                  'currentTime should be unchanged when duration shortened'); | 
| +    var previousFinishedPromise = animation.finished; | 
| +    animation.effect.timing.duration = 100 * MS_PER_SEC; | 
| +    assert_not_equals(animation.finished, previousFinishedPromise, | 
| +                      'Finished promise should change after lengthening the ' + | 
| +                      'duration causes the animation to become active'); | 
| +  }); | 
| +}, 'Test finished promise changes for animation duration changes'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  var retPromise = animation.ready.then(function() { | 
| +    animation.playbackRate = 0; | 
| +    animation.currentTime = 100 * MS_PER_SEC + 1000; | 
| +    return waitForAnimationFrames(2); | 
| +  }); | 
| + | 
| +  animation.finished.then(t.step_func(function() { | 
| +    assert_unreached('finished promise should not resolve when playbackRate ' + | 
| +                     'is zero'); | 
| +  })); | 
| + | 
| +  return retPromise; | 
| +}, 'Test finished promise changes when playbackRate == 0'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  return animation.ready.then(function() { | 
| +    animation.playbackRate = -1; | 
| +    return animation.finished; | 
| +  }); | 
| +}, 'Test finished promise resolves when reaching to the natural boundary.'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  var previousFinishedPromise = animation.finished; | 
| +  animation.finish(); | 
| +  return animation.finished.then(function() { | 
| +    animation.currentTime = 0; | 
| +    assert_not_equals(animation.finished, previousFinishedPromise, | 
| +                      'Finished promise should change once a prior ' + | 
| +                      'finished promise resolved and the animation ' + | 
| +                      'falls out finished state'); | 
| +  }); | 
| +}, 'Test finished promise changes when a prior finished promise resolved ' + | 
| +   'and the animation falls out finished state'); | 
| + | 
| +test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  var previousFinishedPromise = animation.finished; | 
| +  animation.currentTime = 100 * MS_PER_SEC; | 
| +  animation.currentTime = 100 * MS_PER_SEC / 2; | 
| +  assert_equals(animation.finished, previousFinishedPromise, | 
| +                'No new finished promise generated when finished state ' + | 
| +                'is checked asynchronously'); | 
| +}, 'Test no new finished promise generated when finished state ' + | 
| +   'is checked asynchronously'); | 
| + | 
| +test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  var previousFinishedPromise = animation.finished; | 
| +  animation.finish(); | 
| +  animation.currentTime = 100 * MS_PER_SEC / 2; | 
| +  assert_not_equals(animation.finished, previousFinishedPromise, | 
| +                    'New finished promise generated when finished state ' + | 
| +                    'is checked synchronously'); | 
| +}, 'Test new finished promise generated when finished state ' + | 
| +   'is checked synchronously'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  var resolvedFinished = false; | 
| +  animation.finished.then(function() { | 
| +    resolvedFinished = true; | 
| +  }); | 
| +  return animation.ready.then(function() { | 
| +    animation.finish(); | 
| +    animation.currentTime = 100 * MS_PER_SEC / 2; | 
| +  }).then(function() { | 
| +    assert_true(resolvedFinished, | 
| +      'Animation.finished should be resolved even if ' + | 
| +      'the finished state is changed soon'); | 
| +  }); | 
| + | 
| +}, 'Test synchronous finished promise resolved even if finished state ' + | 
| +   'is changed soon'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  var resolvedFinished = false; | 
| +  animation.finished.then(function() { | 
| +    resolvedFinished = true; | 
| +  }); | 
| + | 
| +  return animation.ready.then(function() { | 
| +    animation.currentTime = 100 * MS_PER_SEC; | 
| +    animation.finish(); | 
| +  }).then(function() { | 
| +    assert_true(resolvedFinished, | 
| +      'Animation.finished should be resolved soon after finish() is ' + | 
| +      'called even if there are other asynchronous promises just before it'); | 
| +  }); | 
| +}, 'Test synchronous finished promise resolved even if asynchronous ' + | 
| +   'finished promise happens just before synchronous promise'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  animation.finished.then(t.step_func(function() { | 
| +    assert_unreached('Animation.finished should not be resolved'); | 
| +  })); | 
| + | 
| +  return animation.ready.then(function() { | 
| +    animation.currentTime = 100 * MS_PER_SEC; | 
| +    animation.currentTime = 100 * MS_PER_SEC / 2; | 
| +  }); | 
| +}, 'Test finished promise is not resolved when the animation ' + | 
| +   'falls out finished state immediately'); | 
| + | 
| +promise_test(function(t) { | 
| +  var div = createDiv(t); | 
| +  var animation = div.animate({}, 100 * MS_PER_SEC); | 
| +  return animation.ready.then(function() { | 
| +    animation.currentTime = 100 * MS_PER_SEC; | 
| +    animation.finished.then(t.step_func(function() { | 
| +      assert_unreached('Animation.finished should not be resolved'); | 
| +    })); | 
| +    animation.currentTime = 0; | 
| +  }); | 
| + | 
| +}, 'Test finished promise is not resolved once the animation ' + | 
| +   'falls out finished state even though the current finished ' + | 
| +   'promise is generated soon after animation state became finished'); | 
| + | 
| +</script> | 
| +</body> | 
|  |