summaryrefslogtreecommitdiffstats
path: root/dom/animation/test/css-transitions/file_animation-currenttime.html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/animation/test/css-transitions/file_animation-currenttime.html')
-rw-r--r--dom/animation/test/css-transitions/file_animation-currenttime.html307
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>