diff options
Diffstat (limited to 'dom/animation/test/css-transitions/file_animation-currenttime.html')
-rw-r--r-- | dom/animation/test/css-transitions/file_animation-currenttime.html | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/dom/animation/test/css-transitions/file_animation-currenttime.html b/dom/animation/test/css-transitions/file_animation-currenttime.html new file mode 100644 index 000000000..2a0f105d2 --- /dev/null +++ b/dom/animation/test/css-transitions/file_animation-currenttime.html @@ -0,0 +1,307 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Tests for the effect of setting a CSS transition's + Animation.currentTime</title> + <style> + +.animated-div { + margin-left: 100px; + transition: margin-left 1000s linear 1000s; +} + + </style> + <script src="../testcommon.js"></script> + </head> + <body> + <script type="text/javascript"> + +'use strict'; + +// 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 ANIM_DELAY_MS = 1000000; // 1000s +const ANIM_DUR_MS = 1000000; // 1000s + +/** + * These helpers get the value that the currentTime needs to be set to, to put + * an animation that uses the above ANIM_DELAY_MS and ANIM_DUR_MS values into + * the middle of various phases or points through the active duration. + */ +function currentTimeForBeforePhase() { + return ANIM_DELAY_MS / 2; +} +function currentTimeForActivePhase() { + return ANIM_DELAY_MS + ANIM_DUR_MS / 2; +} +function currentTimeForAfterPhase() { + return ANIM_DELAY_MS + ANIM_DUR_MS + ANIM_DELAY_MS / 2; +} +function currentTimeForStartOfActiveInterval() { + return ANIM_DELAY_MS; +} +function currentTimeForFiftyPercentThroughActiveInterval() { + return ANIM_DELAY_MS + ANIM_DUR_MS * 0.5; +} +function currentTimeForEndOfActiveInterval() { + return ANIM_DELAY_MS + ANIM_DUR_MS; +} + + +// Expected computed 'margin-left' values at points during the active interval: +// When we assert_between_inclusive using these values we could in theory cause +// intermittent failure due to very long delays between paints, but since the +// active duration is 1000s long, a delay would need to be around 100s to cause +// that. If that's happening then there are likely other issues that should be +// fixed, so a failure to make us look into that seems like a good thing. +const INITIAL_POSITION = 100; +const TEN_PCT_POSITION = 110; +const FIFTY_PCT_POSITION = 150; +const END_POSITION = 200; + + +// The terms used for the naming of the following helper functions refer to +// terms used in the Web Animations specification for specific phases of an +// animation. The terms can be found here: +// +// http://w3c.github.io/web-animations/#animation-effect-phases-and-states + +// Called when currentTime is set to zero (the beginning of the start delay). +function checkStateOnSettingCurrentTimeToZero(animation) +{ + // We don't test animation.currentTime since our caller just set it. + + assert_equals(animation.playState, 'running', + 'Animation.playState should be "running" at the start of ' + + 'the start delay'); + + assert_equals(animation.effect.target.style.animationPlayState, 'running', + 'Animation.effect.target.style.animationPlayState should be ' + + '"running" at the start of the start delay'); + + var div = animation.effect.target; + var marginLeft = parseFloat(getComputedStyle(div).marginLeft); + assert_equals(marginLeft, UNANIMATED_POSITION, + 'the computed value of margin-left should be unaffected ' + + 'at the beginning of the start delay'); +} + +// Called when the ready Promise's callbacks should happen +function checkStateOnReadyPromiseResolved(animation) +{ + // the 0.0001 here is for rounding error + assert_less_than_equal(animation.currentTime, + animation.timeline.currentTime - animation.startTime + 0.0001, + 'Animation.currentTime should be less than the local time ' + + 'equivalent of the timeline\'s currentTime on the first paint tick ' + + 'after animation creation'); + + assert_equals(animation.playState, 'running', + 'Animation.playState should be "running" on the first paint ' + + 'tick after animation creation'); + + var div = animation.effect.target; + var marginLeft = parseFloat(getComputedStyle(div).marginLeft); + assert_equals(marginLeft, INITIAL_POSITION, + 'the computed value of margin-left should be unaffected ' + + 'by an animation with a delay on ready Promise resolve'); +} + +// Called when currentTime is set to the time the active interval starts. +function checkStateAtActiveIntervalStartTime(animation) +{ + // We don't test animation.currentTime since our caller just set it. + + assert_equals(animation.playState, 'running', + 'Animation.playState should be "running" at the start of ' + + 'the active interval'); + + var div = animation.effect.target; + var marginLeft = parseFloat(getComputedStyle(div).marginLeft); + assert_between_inclusive(marginLeft, INITIAL_POSITION, TEN_PCT_POSITION, + 'the computed value of margin-left should be close to the value at the ' + + 'beginning of the animation'); +} + +function checkStateAtFiftyPctOfActiveInterval(animation) +{ + // We don't test animation.currentTime since our caller just set it. + + var div = animation.effect.target; + var marginLeft = parseFloat(getComputedStyle(div).marginLeft); + assert_equals(marginLeft, FIFTY_PCT_POSITION, + 'the computed value of margin-left should be half way through the ' + + 'animation at the midpoint of the active interval'); +} + +// Called when currentTime is set to the time the active interval ends. +function checkStateAtActiveIntervalEndTime(animation) +{ + // We don't test animation.currentTime since our caller just set it. + + assert_equals(animation.playState, 'finished', + 'Animation.playState should be "finished" at the end of ' + + 'the active interval'); + + var div = animation.effect.target; + var marginLeft = parseFloat(getComputedStyle(div).marginLeft); + assert_equals(marginLeft, END_POSITION, + 'the computed value of margin-left should be the final transitioned-to ' + + 'value at the end of the active duration'); +} + +test(function(t) +{ + var div = addDiv(t, {'class': 'animated-div'}); + flushComputedStyle(div); + div.style.marginLeft = '200px'; // initiate transition + + var animation = div.getAnimations()[0]; + assert_equals(animation.currentTime, 0, 'currentTime should be zero'); +}, 'currentTime of a newly created transition is zero'); + + +test(function(t) +{ + var div = addDiv(t, {'class': 'animated-div'}); + flushComputedStyle(div); + div.style.marginLeft = '200px'; // initiate transition + + var animation = div.getAnimations()[0]; + + // So that animation is running instead of paused when we set currentTime: + animation.startTime = animation.timeline.currentTime; + + animation.currentTime = 10; + assert_equals(animation.currentTime, 10, + 'Check setting of currentTime actually works'); +}, 'Sanity test to check round-tripping assigning to new animation\'s ' + + 'currentTime'); + + +async_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + var eventWatcher = new EventWatcher(t, div, 'transitionend'); + + flushComputedStyle(div); + div.style.marginLeft = '200px'; // initiate transition + + var animation = div.getAnimations()[0]; + + animation.ready.then(t.step_func(function() { + checkStateOnReadyPromiseResolved(animation); + + animation.currentTime = currentTimeForStartOfActiveInterval(); + checkStateAtActiveIntervalStartTime(animation); + + animation.currentTime = currentTimeForFiftyPercentThroughActiveInterval(); + checkStateAtFiftyPctOfActiveInterval(animation); + + animation.currentTime = currentTimeForEndOfActiveInterval(); + return eventWatcher.wait_for('transitionend'); + })).then(t.step_func(function() { + checkStateAtActiveIntervalEndTime(animation); + })).catch(t.step_func(function(reason) { + assert_unreached(reason); + })).then(function() { + t.done(); + }); +}, 'Skipping forward through transition'); + + +test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + var eventWatcher = new EventWatcher(t, div, 'transitionend'); + + flushComputedStyle(div); + div.style.marginLeft = '200px'; // initiate transition + + var animation = div.getAnimations()[0]; + + // Unlike in the case of CSS animations, we cannot skip to the end and skip + // backwards since when we reach the end the transition effect is removed and + // changes to the Animation object no longer affect the element. For + // this reason we only skip forwards as far as the 50% through point. + + animation.ready.then(t.step_func(function() { + animation.currentTime = currentTimeForFiftyPercentThroughActiveInterval(); + checkStateAtFiftyPctOfActiveInterval(animation); + + animation.currentTime = currentTimeForStartOfActiveInterval(); + + // Despite going backwards from being in the active interval to being + // before it, we now expect a 'transitionend' event because the transition + // should go from being active to inactive. + // + // Calling checkStateAtActiveIntervalStartTime will check computed style, + // causing computed style to be updated and the 'transitionend' event to + // be dispatched synchronously. We need to call wait_for first + // otherwise eventWatcher will assert that the event was unexpected. + eventWatcher.wait_for('transitionend').then(function() { + t.done(); + }); + checkStateAtActiveIntervalStartTime(animation); + })); +}, 'Skipping backwards through transition'); + + +async_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + flushComputedStyle(div); + div.style.marginLeft = '200px'; // initiate transition + + var animation = div.getAnimations()[0]; + + animation.ready.then(t.step_func(function() { + var exception; + try { + animation.currentTime = null; + } catch (e) { + exception = e; + } + assert_equals(exception.name, 'TypeError', + 'Expect TypeError exception on trying to set ' + + 'Animation.currentTime to null'); + })).catch(t.step_func(function(reason) { + assert_unreached(reason); + })).then(function() { + t.done(); + }); +}, 'Setting currentTime to null'); + + +async_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + flushComputedStyle(div); + div.style.marginLeft = '200px'; // initiate transition + + var animation = div.getAnimations()[0]; + var pauseTime; + + animation.ready.then(t.step_func(function() { + assert_not_equals(animation.currentTime, null, + 'Animation.currentTime not null on ready Promise resolve'); + animation.pause(); + return animation.ready; + })).then(t.step_func(function() { + pauseTime = animation.currentTime; + return waitForFrame(); + })).then(t.step_func(function() { + assert_equals(animation.currentTime, pauseTime, + 'Animation.currentTime is unchanged after pausing'); + })).catch(t.step_func(function(reason) { + assert_unreached(reason); + })).then(function() { + t.done(); + }); +}, 'Animation.currentTime after pausing'); + +done(); + </script> + </body> +</html> |