Bug 1302648 part 8 - Add animationcancel tests. r?birtles draft
authorMantaroh Yoshinaga <mantaroh@gmail.com>
Fri, 10 Feb 2017 12:32:45 +0900
changeset 481640 28a8bb9c048c323ecf532006ff7fb712e56c5c82
parent 481639 2396a5cbc7c13b3a5f7b4b5c15744b37a676136e
child 481641 1c0c591704923362a5cb797591598d8625f98b91
push id44889
push usermantaroh@gmail.com
push dateFri, 10 Feb 2017 08:41:14 +0000
reviewersbirtles
bugs1302648
milestone54.0a1
Bug 1302648 part 8 - Add animationcancel tests. r?birtles MozReview-Commit-ID: 44nT8BBNgzT
dom/animation/test/css-animations/file_animation-cancel.html
dom/animation/test/css-animations/file_event-dispatch.html
--- a/dom/animation/test/css-animations/file_animation-cancel.html
+++ b/dom/animation/test/css-animations/file_animation-cancel.html
@@ -39,46 +39,29 @@ promise_test(function(t) {
     assert_not_equals(getComputedStyle(div).transform, 'none',
                       'transform style is filling before cancelling');
     animation.cancel();
     assert_equals(getComputedStyle(div).transform, 'none',
                   'fill style is cleared after cancelling');
   });
 }, 'Animated style is cleared after cancelling a filling CSS animation');
 
-promise_test(function(t) {
-  var div = addDiv(t, { style: 'animation: translateAnim 100s' });
-  var animation = div.getAnimations()[0];
-  div.addEventListener('animationend', t.step_func(function() {
-    assert_unreached('Got unexpected end event on cancelled animation');
-  }));
-
-  return animation.ready.then(function() {
-    // Seek to just before the end then cancel
-    animation.currentTime = 99.9 * 1000;
-    animation.cancel();
-
-    // Then wait a couple of frames and check that no event was dispatched
-    return waitForAnimationFrames(2);
-  });
-}, 'Cancelled CSS animations do not dispatch events');
-
 test(function(t) {
   var div = addDiv(t, { style: 'animation: marginLeftAnim 100s linear' });
   var animation = div.getAnimations()[0];
   animation.cancel();
 
   assert_equals(getComputedStyle(div).marginLeft, '0px',
                 'margin-left style is not animated after cancelling');
 
   animation.currentTime = 50 * 1000;
   assert_equals(getComputedStyle(div).marginLeft, '50px',
                 'margin-left style is updated when cancelled animation is'
                 + ' seeked');
-}, 'After cancelling an animation, it can still be seeked');
+}, 'After canceling an animation, it can still be seeked');
 
 promise_test(function(t) {
   var div =
     addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
   var animation = div.getAnimations()[0];
 
   return animation.ready.then(function() {
     animation.cancel();
@@ -100,17 +83,16 @@ test(function(t) {
   var animation = div.getAnimations()[0];
   animation.cancel();
   assert_equals(getComputedStyle(div).marginLeft, '0px',
                 'margin-left style is not animated after cancelling');
 
   // Trigger a change to some animation properties and check that this
   // doesn't cause the animation to become live again
   div.style.animationDuration = '200s';
-  flushComputedStyle(div);
   assert_equals(getComputedStyle(div).marginLeft, '0px',
                 'margin-left style is still not animated after updating'
                 + ' animation-duration');
   assert_equals(animation.playState, 'idle',
                 'Animation is still idle after updating animation-duration');
 }, 'After cancelling an animation, updating animation properties doesn\'t make'
    + ' it live again');
 
@@ -143,12 +125,67 @@ test(function(t) {
   div.style.animationPlayState = 'running';
   assert_equals(animation.playState, 'idle',
                 'Animation is still idle after re-setting'
                 + ' animation-play-state: running');
 
 }, 'After cancelling an animation, updating animation-play-state doesn\'t'
    + ' make it live again');
 
+promise_test(function(t) {
+  var div = addDiv(t, { style: 'animation: translateAnim 10s both' });
+  div.style.marginLeft = '0px';
+
+  var animation = div.getAnimations()[0];
+
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'running');
+
+    div.style.animationName = 'none';
+    flushComputedStyle(div);
+    return waitForFrame();
+  }).then(function() {
+    assert_equals(animation.playState, 'idle');
+    assert_equals(getComputedStyle(div).marginLeft, '0px');
+  });
+}, 'Setting animation-name to \'none\' cancels the animation');
+
+promise_test(function(t) {
+  var div = addDiv(t, { style: 'animation: translateAnim 10s both' });
+  var animation = div.getAnimations()[0];
+
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'running');
+
+    div.style.display = 'none';
+    return waitForFrame();
+  }).then(function() {
+    assert_equals(animation.playState, 'idle');
+    assert_equals(getComputedStyle(div).marginLeft, '0px');
+  });
+}, 'Setting display:none on an element cancel its animations');
+
+promise_test(function(t) {
+  var parentDiv = addDiv(t);
+  var childDiv  = document.createElement('div');
+  parentDiv.appendChild(childDiv);
+
+  childDiv.setAttribute('style', 'animation: translateAnim 10s both');
+  flushComputedStyle(childDiv);
+
+  var animation = childDiv.getAnimations()[0];
+
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'running');
+
+    parentDiv.style.display = 'none';
+    return waitForFrame();
+  }).then(function() {
+    assert_equals(animation.playState, 'idle');
+    assert_equals(getComputedStyle(childDiv).marginLeft, '0px');
+  });
+}, 'Setting display:none on an ancestor element cancels animations on ' +
+   'descendants');
+
 done();
 </script>
 </body>
 </html>
--- a/dom/animation/test/css-animations/file_event-dispatch.html
+++ b/dom/animation/test/css-animations/file_event-dispatch.html
@@ -25,28 +25,33 @@ function AnimationEventHandler(target) {
    this.animationstart = evt.elapsedTime;
   }.bind(this);
   this.target.onanimationiteration = function(evt) {
     this.animationiteration = evt.elapsedTime;
   }.bind(this);
   this.target.onanimationend = function(evt) {
     this.animationend = evt.elapsedTime;
   }.bind(this);
+  this.target.onanimationcancel = function(evt) {
+    this.animationcancel = evt.elapsedTime;
+  }.bind(this);
 }
 AnimationEventHandler.prototype.clear = function() {
-  this.animationstart = undefined;
+  this.animationstart     = undefined;
   this.animationiteration = undefined;
-  this.animationend = undefined;
+  this.animationend       = undefined;
+  this.animationcancel    = undefined;
 }
 
 function setupAnimation(t, animationStyle) {
   var div = addDiv(t, { style: "animation: " + animationStyle });
   var watcher = new EventWatcher(t, div, [ 'animationstart',
                                            'animationiteration',
-                                           'animationend' ]);
+                                           'animationend',
+                                           'animationcancel' ]);
   var animation = div.getAnimations()[0];
 
   return [animation, watcher, div];
 }
 
 promise_test(function(t) {
   // Add 1ms delay to ensure that the delay is not included in the elapsedTime.
   const [animation, watcher] = setupAnimation(t, 'anim 100s 1ms');
@@ -93,16 +98,54 @@ promise_test(function(t) {
     return watcher.wait_for([ 'animationstart', 'animationend' ]);
   }).then(function(evt) {
     assert_equals(handler.animationstart, 0.0);
     assert_equals(handler.animationend, 100.0);
   });
 }, 'Before -> After');
 
 promise_test(function(t) {
+  const [animation, watcher, div] = setupAnimation(t, 'anim 100s paused');
+
+  return watcher.wait_for('animationstart').then(function(evt) {
+    // Make idle
+    div.style.display = 'none';
+    return watcher.wait_for('animationcancel');
+  }).then(function(evt) {
+    assert_equals(evt.elapsedTime, 0.0);
+  });
+}, 'Active -> Idle, display: none');
+
+promise_test(function(t) {
+  const [animation, watcher, div] = setupAnimation(t, 'anim 100s');
+
+  return watcher.wait_for('animationstart').then(function(evt) {
+    animation.currentTime = 100.0;
+    // Make idle
+    animation.timeline = null;
+    return watcher.wait_for('animationcancel');
+  }).then(function(evt) {
+    assert_times_equal(evt.elapsedTime, 0.1);
+  });
+}, 'Active -> Idle, setting Animation.timeline = null');
+
+promise_test(function(t) {
+  // we should NOT pause animation since calling cancel synchronously.
+  const [animation, watcher, div] = setupAnimation(t, 'anim 100s');
+
+  return watcher.wait_for('animationstart').then(function(evt) {
+    animation.currentTime = 50.0;
+    animation.cancel();
+    return watcher.wait_for('animationcancel');
+  }).then(function(evt) {
+    assert_times_equal(evt.elapsedTime, 0.05);
+  });
+}, 'Active -> Idle, calling Animation.cancel()');
+
+promise_test(function(t) {
   const [animation, watcher] =
     setupAnimation(t, 'anim 100s 100s paused');
 
   // Seek to Active phase.
   animation.currentTime = 100 * MS_PER_SEC;
   return watcher.wait_for('animationstart').then(function() {
     // Seek to Before phase.
     animation.currentTime = 0;
@@ -211,18 +254,18 @@ promise_test(function(t) {
 promise_test(function(t) {
   const [animation, watcher, div] =
     setupAnimation(t, 'anim 100s paused');
   return watcher.wait_for('animationstart').then(function(evt) {
     // Seek to Idle phase.
     div.style.display = 'none';
     flushComputedStyle(div);
 
-    // FIXME: bug 1302648: Add test for animationcancel event here.
-
+    return watcher.wait_for('animationcancel');
+  }).then(function() {
     // Restart this animation.
     div.style.display = '';
     return watcher.wait_for('animationstart');
   });
 }, 'Active -> Idle -> Active: animationstart is fired by restarting animation');
 
 promise_test(function(t) {
   const [animation, watcher] =
@@ -245,12 +288,94 @@ promise_test(function(t) {
     animation.currentTime = 100 * MS_PER_SEC - 1;
     return watcher.wait_for('animationend');
   }).then(function(evt) {
     assert_equals(evt.elapsedTime, 0);
     assert_equals(animation.playState, 'running'); // delay
   });
 }, 'Negative playbackRate sanity test(Before -> Active -> Before)');
 
+promise_test(function(t) {
+  const [animation, watcher] = setupAnimation(t, 'anim 100s');
+
+  return watcher.wait_for('animationstart').then(function(evt) {
+    // Make idle
+    animation.cancel();
+    return watcher.wait_for('animationcancel');
+  }).then(function(evt) {
+    animation.cancel();
+    // Then wait a couple of frames and check that no event was dispatched.
+    return waitForAnimationFrames(2);
+  });
+}, 'Call Animation.cancel after cancelling animation.');
+
+promise_test(function(t) {
+  const [animation, watcher] = setupAnimation(t, 'anim 100s');
+
+  return watcher.wait_for('animationstart').then(function(evt) {
+    // Make idle
+    animation.cancel();
+    animation.play();
+    return watcher.wait_for([ 'animationcancel',
+                              'animationstart' ]);
+  });
+}, 'Restart animation after cancelling animation immediately.');
+
+promise_test(function(t) {
+  const [animation, watcher] = setupAnimation(t, 'anim 100s');
+
+  return watcher.wait_for('animationstart').then(function(evt) {
+    // Make idle
+    animation.cancel();
+    animation.play();
+    animation.cancel();
+    return watcher.wait_for('animationcancel');
+  }).then(function(evt) {
+    // Then wait a couple of frames and check that no event was dispatched.
+    return waitForAnimationFrames(2);
+  });
+}, 'Call Animation.cancel after restarting animation immediately.');
+
+promise_test(function(t) {
+  const [animation, watcher] = setupAnimation(t, 'anim 100s');
+
+  return watcher.wait_for('animationstart').then(function(evt) {
+    // Make idle
+    animation.timeline = null;
+    return watcher.wait_for('animationcancel');
+  }).then(function(evt) {
+    animation.timeline = document.timeline;
+    animation.play();
+    return watcher.wait_for('animationstart');
+  });
+}, 'Set timeline and play transition after clearing the timeline.');
+
+promise_test(function(t) {
+  const [animation, watcher] = setupAnimation(t, 'anim 100s');
+
+  return watcher.wait_for('animationstart').then(function(evt) {
+    // Make idle
+    animation.cancel();
+    return watcher.wait_for('animationcancel');
+  }).then(function(evt) {
+    animation.effect = null;
+    // Then wait a couple of frames and check that no event was dispatched.
+    return waitForAnimationFrames(2);
+  });
+}, 'Set null target effect after cancelling the animation.');
+
+promise_test(function(t) {
+  const [animation, watcher] = setupAnimation(t, 'anim 100s');
+
+  return watcher.wait_for('animationstart').then(function(evt) {
+    animation.effect = null;
+    return watcher.wait_for('animationend');
+  }).then(function(evt) {
+    animation.cancel();
+    // Then wait a couple of frames and check that no event was dispatched.
+    return waitForAnimationFrames(2);
+  });
+}, 'Cancel the animation after clearing the target effect.');
+
 done();
 </script>
 </body>
 </html>