diff options
Diffstat (limited to 'dom/animation/test/css-animations/file_animation-starttime.html')
-rw-r--r-- | dom/animation/test/css-animations/file_animation-starttime.html | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/dom/animation/test/css-animations/file_animation-starttime.html b/dom/animation/test/css-animations/file_animation-starttime.html new file mode 100644 index 0000000000..46144464c0 --- /dev/null +++ b/dom/animation/test/css-animations/file_animation-starttime.html @@ -0,0 +1,383 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Tests for the effect of setting a CSS animation's + Animation.startTime</title> + <style> + +.animated-div { + margin-left: 10px; + /* Make it easier to calculate expected values: */ + animation-timing-function: linear ! important; +} + +@keyframes anim { + from { margin-left: 100px; } + to { margin-left: 200px; } +} + + </style> + <script src="../testcommon.js"></script> + </head> + <body> + <script type="text/javascript"> + +'use strict'; + +// TODO: We should separate this test(Testing for CSS Animation events / +// Testing for start time of Web Animation). +// e.g: +// CSS Animation events test: +// - check the firing an event after setting an Animation.startTime +// The start time of Web Animation test: +// - check an start time value on several situation(init / processing..) +// - Based on W3C Spec, check the behavior of setting current time. + +// TODO: Once the computedTiming property is implemented, add checks to the +// checker helpers to ensure that computedTiming's properties are updated as +// expected. +// See https://bugzilla.mozilla.org/show_bug.cgi?id=1108055 + +const CSS_ANIM_EVENTS = + ['animationstart', 'animationiteration', 'animationend']; + +test(function(t) +{ + var div = addDiv(t, { 'style': 'animation: anim 100s' }); + var animation = div.getAnimations()[0]; + + assert_equals(animation.startTime, null, 'startTime is unresolved'); +}, 'startTime of a newly created (play-pending) animation is unresolved'); + +test(function(t) +{ + var div = addDiv(t, { 'style': 'animation: anim 100s paused' }); + var animation = div.getAnimations()[0]; + assert_equals(animation.startTime, null, 'startTime is unresolved'); +}, 'startTime of a newly created (pause-pending) animation is unresolved'); + +promise_test(function(t) +{ + var div = addDiv(t, { 'style': 'animation: anim 100s' }); + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + assert_true(animation.startTime > 0, + 'startTime is resolved when running'); + }); +}, 'startTime is resolved when running'); + +promise_test(function(t) +{ + var div = addDiv(t, { 'style': 'animation: anim 100s paused' }); + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + assert_equals(animation.startTime, null, + 'startTime is unresolved when paused'); + }); +}, 'startTime is unresolved when paused'); + +promise_test(function(t) +{ + var div = addDiv(t, { 'style': 'animation: anim 100s' }); + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + div.style.animationPlayState = 'paused'; + getComputedStyle(div).animationPlayState; + + assert_not_equals(animation.startTime, null, + 'startTime is resolved when pause-pending'); + + div.style.animationPlayState = 'running'; + getComputedStyle(div).animationPlayState; + + assert_not_equals(animation.startTime, null, + 'startTime is preserved when a pause is aborted'); + }); +}, 'startTime while pause-pending and play-pending'); + +promise_test(function(t) { + var div = addDiv(t, { 'style': 'animation: anim 100s' }); + var animation = div.getAnimations()[0]; + // Seek to end to put us in the finished state + animation.currentTime = 100 * MS_PER_SEC; + + return animation.ready.then(function() { + // Call play() which puts us back in the running state + animation.play(); + + assert_equals(animation.startTime, null, 'startTime is unresolved'); + }); +}, 'startTime while play-pending from finished state'); + +test(function(t) { + var div = addDiv(t, { 'style': 'animation: anim 100s' }); + var animation = div.getAnimations()[0]; + animation.finish(); + // Call play() which puts us back in the running state + animation.play(); + + assert_equals(animation.startTime, null, 'startTime is unresolved'); +}, 'startTime while play-pending from finished state using finish()'); + +promise_test(function(t) { + var div = addDiv(t, { style: 'animation: anim 100s' }); + var animation = div.getAnimations()[0]; + + assert_equals(animation.startTime, null, 'The initial startTime is null'); + var initialTimelineTime = document.timeline.currentTime; + + return animation.ready.then(function() { + assert_true(animation.startTime > initialTimelineTime, + 'After the animation has started, startTime is greater than ' + + 'the time when it was started'); + var startTimeBeforePausing = animation.startTime; + + div.style.animationPlayState = 'paused'; + // Flush styles just in case querying animation.startTime doesn't flush + // styles (which would be a bug in of itself and could mask a further bug + // by causing startTime to appear to not change). + getComputedStyle(div).animationPlayState; + + assert_equals(animation.startTime, startTimeBeforePausing, + 'The startTime does not change when pausing-pending'); + return animation.ready; + }).then(function() { + assert_equals(animation.startTime, null, + 'After actually pausing, the startTime of an animation ' + + 'is null'); + }); +}, 'Pausing should make the startTime become null'); + +test(function(t) +{ + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = 'anim 100s 100s'; + var animation = div.getAnimations()[0]; + var currentTime = animation.timeline.currentTime; + animation.startTime = currentTime; + + assert_times_equal(animation.startTime, currentTime, + 'Check setting of startTime actually works'); +}, 'Sanity test to check round-tripping assigning to a new animation\'s ' + + 'startTime'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS); + div.style.animation = 'anim 100s 100s'; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + assert_less_than_equal(animation.startTime, animation.timeline.currentTime, + 'Animation.startTime should be less than the timeline\'s ' + + 'currentTime on the first paint tick after animation creation'); + + animation.startTime = animation.timeline.currentTime - 100 * MS_PER_SEC; + return eventWatcher.wait_for('animationstart'); + }).then(function() { + animation.startTime = animation.timeline.currentTime - 200 * MS_PER_SEC; + return eventWatcher.wait_for('animationend'); + }); +}, 'Skipping forward through animation'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS); + div.style.animation = 'anim 100s 100s'; + var animation = div.getAnimations()[0]; + animation.startTime = animation.timeline.currentTime - 200 * MS_PER_SEC; + var previousTimelineTime = animation.timeline.currentTime; + + return eventWatcher.wait_for(['animationstart', + 'animationend']).then(function() { + assert_true(document.timeline.currentTime - previousTimelineTime < + 100 * MS_PER_SEC, + 'Sanity check that seeking worked rather than the events ' + + 'firing after normal playback through the very long ' + + 'animation duration'); + + animation.startTime = animation.timeline.currentTime - 150 * MS_PER_SEC; + + // Despite going backwards from after the end of the animation (to being + // in the active interval), we now expect an 'animationstart' event + // because the animation should go from being inactive to active. + return eventWatcher.wait_for('animationstart'); + }).then(function() { + animation.startTime = animation.timeline.currentTime; + + // Despite going backwards from just after the active interval starts to + // the animation start time, we now expect an animationend event + // because we went from inside to outside the active interval. + return eventWatcher.wait_for('animationend'); + }).then(function() { + assert_less_than_equal(animation.startTime, animation.timeline.currentTime, + 'Animation.startTime should be less than the timeline\'s ' + + 'currentTime on the first paint tick after animation creation'); + }); +}, 'Skipping backwards through animation'); + +// Next we have multiple tests to check that redundant startTime changes do NOT +// dispatch events. It's impossible to distinguish between events not being +// dispatched and events just taking an incredibly long time to dispatch +// without waiting an infinitely long time. Obviously we don't want to do that +// (block this test from finishing forever), so instead we just listen for +// events until two animation frames (i.e. requestAnimationFrame callbacks) +// have happened, then assume that no events will ever be dispatched for the +// redundant changes if no events were detected in that time. + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + animation.startTime = animation.timeline.currentTime - 150 * MS_PER_SEC; + animation.startTime = animation.timeline.currentTime - 50 * MS_PER_SEC; + + return waitForAnimationFrames(2); +}, 'Redundant change, before -> active, then back'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + animation.startTime = animation.timeline.currentTime - 250 * MS_PER_SEC; + animation.startTime = animation.timeline.currentTime - 50 * MS_PER_SEC; + + return waitForAnimationFrames(2); +}, 'Redundant change, before -> after, then back'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + var retPromise = eventWatcher.wait_for('animationstart').then(function() { + animation.startTime = animation.timeline.currentTime - 50 * MS_PER_SEC; + animation.startTime = animation.timeline.currentTime - 150 * MS_PER_SEC; + + return waitForAnimationFrames(2); + }); + // get us into the initial state: + animation.startTime = animation.timeline.currentTime - 150 * MS_PER_SEC; + + return retPromise; +}, 'Redundant change, active -> before, then back'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + var retPromise = eventWatcher.wait_for('animationstart').then(function() { + animation.startTime = animation.timeline.currentTime - 250 * MS_PER_SEC; + animation.startTime = animation.timeline.currentTime - 150 * MS_PER_SEC; + + return waitForAnimationFrames(2); + }); + // get us into the initial state: + animation.startTime = animation.timeline.currentTime - 150 * MS_PER_SEC; + + return retPromise; +}, 'Redundant change, active -> after, then back'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + var retPromise = eventWatcher.wait_for(['animationstart', + 'animationend']).then(function() { + animation.startTime = animation.timeline.currentTime - 50 * MS_PER_SEC; + animation.startTime = animation.timeline.currentTime - 250 * MS_PER_SEC; + + return waitForAnimationFrames(2); + }); + // get us into the initial state: + animation.startTime = animation.timeline.currentTime - 250 * MS_PER_SEC; + + return retPromise; +}, 'Redundant change, after -> before, then back'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + var retPromise = eventWatcher.wait_for(['animationstart', + 'animationend']).then(function() { + animation.startTime = animation.timeline.currentTime - 150 * MS_PER_SEC; + animation.startTime = animation.timeline.currentTime - 250 * MS_PER_SEC; + + return waitForAnimationFrames(2); + + }); + // get us into the initial state: + animation.startTime = animation.timeline.currentTime - 250 * MS_PER_SEC; + + return retPromise; +}, 'Redundant change, after -> active, then back'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = 'anim 100s 100s'; + var animation = div.getAnimations()[0]; + var storedCurrentTime; + + return animation.ready.then(function() { + storedCurrentTime = animation.currentTime; + animation.startTime = null; + return animation.ready; + }).then(function() { + assert_equals(animation.currentTime, storedCurrentTime, + 'Test that hold time is correct'); + }); +}, 'Setting startTime to null'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = 'anim 100s'; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + var savedStartTime = animation.startTime; + + assert_not_equals(animation.startTime, null, + 'Animation.startTime not null on ready Promise resolve'); + + animation.pause(); + return animation.ready; + }).then(function() { + assert_equals(animation.startTime, null, + 'Animation.startTime is null after paused'); + assert_equals(animation.playState, 'paused', + 'Animation.playState is "paused" after pause() call'); + }); +}, 'Animation.startTime after pausing'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = 'anim 100s'; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + animation.cancel(); + assert_equals(animation.startTime, null, + 'The startTime of a cancelled animation should be null'); + }); +}, 'Animation.startTime after cancelling'); + +done(); + </script> + </body> +</html> |