| <!DOCTYPE html> |
| <meta charset=utf-8> |
| <title>Tests for discrete animation</title> |
| <link rel="help" href="https://drafts.csswg.org/web-animations/#play-state"> |
| <script src="../../resources/testharness.js"></script> |
| <script src="../../resources/testharnessreport.js"></script> |
| <script src="../../external/wpt/web-animations/testcommon.js"></script> |
| <body> |
| <script> |
| 'use strict'; |
| |
| function createIdleAnimation(t) { |
| var animation = createDiv(t).animate([], 100000); |
| animation.cancel(); |
| return animation; |
| } |
| |
| function createRunningAnimation(t) { |
| var animation = createIdleAnimation(t); |
| animation.play(); |
| animation.startTime = document.timeline.currentTime; |
| return animation; |
| } |
| |
| function createPendingStartTimeAnimation(t) { |
| var animation = createIdleAnimation(t); |
| animation.play(); |
| return animation; |
| } |
| |
| function createPausedAnimation(t) { |
| var animation = createIdleAnimation(t); |
| animation.pause(); |
| animation.currentTime = 0; |
| return animation; |
| } |
| |
| function createFinishedAnimation(t) { |
| var animation = createIdleAnimation(t); |
| animation.play(); |
| animation.finish(); |
| return animation; |
| } |
| |
| // Initial animation states |
| test(function(t) { |
| var animation = createIdleAnimation(t); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, null); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'idle'); |
| }, "Play state is idle after canceling an animation"); |
| |
| test(function(t) { |
| var animation = createPendingStartTimeAnimation(t); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 0); |
| assert_equals(animation.playState, 'running'); |
| }, "Play state is running after playing a canceled animation"); |
| |
| test(function(t) { |
| var animation = createRunningAnimation(t); |
| assert_times_equal(animation.startTime, document.timeline.currentTime - animation.currentTime); |
| assert_times_equal(animation.currentTime, 0); |
| assert_equals(animation.playState, 'running'); |
| }, "Play state is running after playing and setting start time of a canceled animation"); |
| |
| test(function(t) { |
| var animation = createPausedAnimation(t); |
| assert_equals(animation.startTime, null); |
| assert_times_equal(animation.currentTime, 0); |
| assert_equals(animation.playState, 'paused'); |
| }, "Play state is paused after pausing and setting current time of a canceled animation"); |
| |
| test(function(t) { |
| var animation = createFinishedAnimation(t); |
| assert_times_equal(animation.startTime, document.timeline.currentTime - animation.currentTime); |
| assert_equals(animation.currentTime, 100000); |
| assert_equals(animation.playState, 'finished'); |
| }, "Play state is finished after playing and finishing a cancelled animation"); |
| |
| // Changed animation states |
| test(function(t) { |
| var animation = createIdleAnimation(t); |
| animation.play(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 0); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling play() on an idle animation"); |
| |
| test(function(t) { |
| var animation = createIdleAnimation(t); |
| animation.pause(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 0); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| }, "Calling pause() on an idle animation"); |
| |
| test(function(t) { |
| var animation = createIdleAnimation(t); |
| animation.cancel(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, null); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'idle'); |
| }, "Calling cancel() on an idle animation"); |
| |
| test(function(t) { |
| var animation = createIdleAnimation(t); |
| animation.finish(); |
| assert_times_equal(animation.startTime, document.timeline.currentTime - animation.currentTime); |
| assert_equals(animation.currentTime, 100000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'finished'); |
| }, "Calling finish() on an idle animation"); |
| |
| test(function(t) { |
| var animation = createIdleAnimation(t); |
| animation.reverse(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 100000); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling reverse() on an idle animation"); |
| |
| test(function(t) { |
| var animation = createIdleAnimation(t); |
| animation.currentTime = 1000; |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| }, "Setting currentTime on an idle animation"); |
| |
| test(function(t) { |
| var animation = createIdleAnimation(t); |
| animation.startTime = document.timeline.currentTime - 1000; |
| assert_times_equal(animation.startTime, document.timeline.currentTime - 1000); |
| assert_times_equal(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting startTime on an idle animation"); |
| |
| test(function(t) { |
| var animation = createPendingStartTimeAnimation(t); |
| animation.play(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 0); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling play() on a pending starttime animation"); |
| |
| test(function(t) { |
| var animation = createPendingStartTimeAnimation(t); |
| animation.pause(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 0); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| }, "Calling pause() on a pending starttime animation"); |
| |
| test(function(t) { |
| var animation = createPendingStartTimeAnimation(t); |
| animation.cancel(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, null); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'idle'); |
| }, "Calling cancel() on a pending starttime animation"); |
| |
| test(function(t) { |
| var animation = createPendingStartTimeAnimation(t); |
| animation.finish(); |
| assert_times_equal(animation.startTime, document.timeline.currentTime - animation.currentTime); |
| assert_equals(animation.currentTime, 100000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'finished'); |
| }, "Calling finish() on a pending starttime animation"); |
| |
| test(function(t) { |
| var animation = createPendingStartTimeAnimation(t); |
| animation.reverse(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 100000); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling reverse() on a pending starttime animation"); |
| |
| test(function(t) { |
| var animation = createPendingStartTimeAnimation(t); |
| animation.currentTime = 1000; |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 1000); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting currentTime on a pending starttime animation"); |
| |
| test(function(t) { |
| var animation = createPendingStartTimeAnimation(t); |
| animation.startTime = document.timeline.currentTime - 1000; |
| assert_times_equal(animation.startTime, document.timeline.currentTime - 1000); |
| assert_times_equal(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting startTime on a pending starttime animation"); |
| |
| promise_test(async (t) => { |
| var animation = createRunningAnimation(t); |
| assert_false(animation.pending); |
| // Advance the animation from the start boundary. Otherwise the test is |
| // prone to flaking. The initial value of current time is 0 +/- epsilon. If |
| // negative, the hold time is reset and a pending play is triggered, clamped |
| // to the starting boundary per spec. Conversely, if the animation is playing |
| // and current time is within bounds, then play is a no-op. |
| await waitForAnimationFrames(1); |
| var startTime = animation.startTime; |
| var currentTime = animation.currentTime; |
| animation.play(); |
| assert_times_equal(animation.startTime, startTime); |
| assert_times_equal(animation.currentTime, currentTime); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting play() on a running animation"); |
| |
| async_test(function(t) { |
| var animation = createRunningAnimation(t); |
| animation.pause(); |
| assert_not_equals(animation.startTime, null); |
| assert_times_equal(animation.currentTime, 0); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| animation.ready.then(t.step_func_done(() => { |
| assert_equals(animation.startTime, null); |
| assert_greater_than_equal(animation.currentTime, 0); |
| assert_false(animation.pending); |
| })); |
| }, "Setting pause() on a running animation"); |
| |
| test(function(t) { |
| var animation = createRunningAnimation(t); |
| animation.cancel(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, null); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'idle'); |
| }, "Setting cancel() on a running animation"); |
| |
| test(function(t) { |
| var animation = createRunningAnimation(t); |
| animation.finish(); |
| assert_times_equal(animation.startTime, document.timeline.currentTime - animation.currentTime); |
| assert_equals(animation.currentTime, 100000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'finished'); |
| }, "Setting finish() on a running animation"); |
| |
| test(function(t) { |
| var animation = createRunningAnimation(t); |
| // Ensure the current time is precisely zero. We create a non-pending running |
| // animation by explicitly setting the start time to the timeline time. This |
| // is insufficient to ensure that we are precisely on the starting boundary |
| // due to floating point precision errors. If the resulting value of current |
| // time is slightly greater than zero, rather than snapping to the end point, |
| // the animation will simply reverse direction per spec. |
| animation.currentTime = 0; |
| animation.reverse(); |
| assert_equals(animation.startTime, null); |
| assert_times_equal(animation.currentTime, 100000); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting reverse() on a running animation"); |
| |
| test(function(t) { |
| var animation = createRunningAnimation(t); |
| animation.currentTime = 1000; |
| assert_times_equal(animation.startTime, document.timeline.currentTime - animation.currentTime); |
| assert_equals(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting currentTime on a running animation"); |
| |
| test(function(t) { |
| var animation = createRunningAnimation(t); |
| animation.startTime = document.timeline.currentTime - 1000; |
| assert_times_equal(animation.startTime, document.timeline.currentTime - 1000); |
| assert_times_equal(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting startTime on a running animation"); |
| |
| test(function(t) { |
| var animation = createPausedAnimation(t); |
| animation.play(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 0); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling play() on a paused animation"); |
| |
| test(function(t) { |
| var animation = createPausedAnimation(t); |
| // Calling pause on an animation that is already paused or pause-pending is a |
| // no-op. |
| animation.pause(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 0); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| }, "Calling pause() on a paused animation"); |
| |
| test(function(t) { |
| var animation = createPausedAnimation(t); |
| animation.cancel(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, null); |
| assert_equals(animation.playState, 'idle'); |
| }, "Calling cancel() on a paused animation"); |
| |
| test(function(t) { |
| var animation = createPausedAnimation(t); |
| animation.finish(); |
| assert_times_equal(animation.startTime, document.timeline.currentTime - animation.currentTime); |
| assert_equals(animation.currentTime, 100000); |
| assert_equals(animation.playState, 'finished'); |
| }, "Calling finish() on a paused animation"); |
| |
| test(function(t) { |
| var animation = createPausedAnimation(t); |
| animation.reverse(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 100000); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling reverse() on a paused animation"); |
| |
| test(function(t) { |
| var animation = createPausedAnimation(t); |
| animation.currentTime = 1000; |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 1000); |
| assert_equals(animation.playState, 'paused'); |
| }, "Setting currentTime on a paused animation"); |
| |
| test(function(t) { |
| var animation = createPausedAnimation(t); |
| animation.startTime = document.timeline.currentTime - 1000; |
| assert_times_equal(animation.startTime, document.timeline.currentTime - 1000); |
| assert_times_equal(animation.currentTime, 1000); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting startTime on a paused animation"); |
| |
| test(function(t) { |
| var animation = createFinishedAnimation(t); |
| animation.play(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 0); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling play() on a finished animation"); |
| |
| async_test(function(t) { |
| var animation = createFinishedAnimation(t); |
| animation.pause(); |
| assert_not_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 100000); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'paused'); |
| animation.ready.then(t.step_func_done(() => { |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 100000); |
| assert_false(animation.pending); |
| })); |
| }, "Calling pause() on a finished animation"); |
| |
| test(function(t) { |
| var animation = createFinishedAnimation(t); |
| animation.cancel(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, null); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'idle'); |
| }, "Calling cancel() on a finished animation"); |
| |
| test(function(t) { |
| var animation = createFinishedAnimation(t); |
| animation.finish(); |
| assert_times_equal(animation.startTime, document.timeline.currentTime - animation.currentTime); |
| assert_equals(animation.currentTime, 100000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'finished'); |
| }, "Calling finish() on a finished animation"); |
| |
| test(function(t) { |
| var animation = createFinishedAnimation(t); |
| animation.reverse(); |
| assert_equals(animation.startTime, null); |
| assert_equals(animation.currentTime, 100000); |
| assert_true(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Calling reverse() on a finished animation"); |
| |
| test(function(t) { |
| var animation = createFinishedAnimation(t); |
| animation.currentTime = 1000; |
| assert_times_equal(animation.startTime, document.timeline.currentTime - animation.currentTime); |
| assert_equals(animation.currentTime, 1000); |
| assert_false(animation.pending); |
| assert_equals(animation.playState, 'running'); |
| }, "Setting currentTime on a finished animation"); |
| |
| async_test(function(t) { |
| var animation = createIdleAnimation(t); |
| animation.play(); |
| var animationCurrentTime = animation.currentTime; |
| var timelineCurrentTime = document.timeline.currentTime; |
| animation.ready.then(t.step_func_done(() => { |
| assert_equals(animation.playState, 'running'); |
| assert_time_greater_than_equal(animation.startTime, |
| timelineCurrentTime); |
| assert_time_greater_than_equal(animation.currentTime, |
| animationCurrentTime); |
| })); |
| }, "PlayState is 'running' while playing a cancelled animation"); |
| |
| async_test(function(t) { |
| let animation = createRunningAnimation(t); |
| animation.pause(); |
| let animationCurrentTime = animation.currentTime; |
| animation.ready.then(t.step_func_done(() => { |
| assert_equals(animation.playState, 'paused'); |
| assert_equals(animation.startTime, null); |
| assert_time_greater_than_equal(animation.currentTime, |
| animationCurrentTime); |
| })); |
| }, "PlayState is 'running' while pausing a running animation"); |
| </script> |