Bug 1264125 part 8 - Add transitioncancel tests. r?birtles draft
authorMantaroh Yoshinaga <mantaroh@gmail.com>
Tue, 20 Dec 2016 16:39:46 +0900
changeset 451405 0e0e67dffdd2957abcc64c55b46e1ff573cabc7b
parent 451401 5b5d7a7f57fa84174ef317a20eec6df36fe8351e
child 451406 adf15b34fe32ec2f274e41a213543886d87243a3
push id39155
push usermantaroh@gmail.com
push dateTue, 20 Dec 2016 07:41:01 +0000
reviewersbirtles
bugs1264125
milestone53.0a1
Bug 1264125 part 8 - Add transitioncancel tests. r?birtles MozReview-Commit-ID: 3iq57bQjEVd
dom/animation/test/css-transitions/file_animation-cancel.html
dom/animation/test/css-transitions/file_csstransition-events.html
dom/animation/test/css-transitions/file_event-dispatch.html
dom/animation/test/css-transitions/file_setting-effect.html
dom/animation/test/css-transitions/test_csstransition-events.html
dom/animation/test/css-transitions/test_event-dispatch.html
dom/animation/test/mochitest.ini
--- a/dom/animation/test/css-transitions/file_animation-cancel.html
+++ b/dom/animation/test/css-transitions/file_animation-cancel.html
@@ -6,17 +6,16 @@
 'use strict';
 
 promise_test(function(t) {
   var div = addDiv(t, { style: 'margin-left: 0px' });
   flushComputedStyle(div);
 
   div.style.transition = 'margin-left 100s';
   div.style.marginLeft = '1000px';
-  flushComputedStyle(div);
 
   var animation = div.getAnimations()[0];
   return animation.ready.then(waitForFrame).then(function() {
     assert_not_equals(getComputedStyle(div).marginLeft, '1000px',
                       'transform style is animated before cancelling');
     animation.cancel();
     assert_equals(getComputedStyle(div).marginLeft, div.style.marginLeft,
                   'transform style is no longer animated after cancelling');
@@ -24,63 +23,38 @@ promise_test(function(t) {
 }, 'Animated style is cleared after cancelling a running CSS transition');
 
 promise_test(function(t) {
   var div = addDiv(t, { style: 'margin-left: 0px' });
   flushComputedStyle(div);
 
   div.style.transition = 'margin-left 100s';
   div.style.marginLeft = '1000px';
-  flushComputedStyle(div);
-
-  div.addEventListener('transitionend', function() {
-    assert_unreached('Got unexpected end event on cancelled transition');
-  });
-
-  var animation = div.getAnimations()[0];
-  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 transitions do not dispatch events');
-
-promise_test(function(t) {
-  var div = addDiv(t, { style: 'margin-left: 0px' });
-  flushComputedStyle(div);
-
-  div.style.transition = 'margin-left 100s';
-  div.style.marginLeft = '1000px';
-  flushComputedStyle(div);
 
   var animation = div.getAnimations()[0];
   return animation.ready.then(function() {
     animation.cancel();
     assert_equals(getComputedStyle(div).marginLeft, '1000px',
                   'margin-left style is not animated after cancelling');
     animation.play();
     assert_equals(getComputedStyle(div).marginLeft, '0px',
                   'margin-left style is animated after re-starting transition');
     return animation.ready;
   }).then(function() {
     assert_equals(animation.playState, 'running',
                   'Transition succeeds in running after being re-started');
   });
-}, 'After cancelling a transition, it can still be re-used');
+}, 'After canceling a transition, it can still be re-used');
 
 promise_test(function(t) {
   var div = addDiv(t, { style: 'margin-left: 0px' });
   flushComputedStyle(div);
 
   div.style.transition = 'margin-left 100s';
   div.style.marginLeft = '1000px';
-  flushComputedStyle(div);
 
   var animation = div.getAnimations()[0];
   return animation.ready.then(function() {
     animation.finish();
     animation.cancel();
     assert_equals(getComputedStyle(div).marginLeft, '1000px',
                   'margin-left style is not animated after cancelling');
     animation.play();
@@ -94,17 +68,16 @@ promise_test(function(t) {
 }, 'After cancelling a finished transition, it can still be re-used');
 
 test(function(t) {
   var div = addDiv(t, { style: 'margin-left: 0px' });
   flushComputedStyle(div);
 
   div.style.transition = 'margin-left 100s';
   div.style.marginLeft = '1000px';
-  flushComputedStyle(div);
 
   var animation = div.getAnimations()[0];
   animation.cancel();
   assert_equals(getComputedStyle(div).marginLeft, '1000px',
                 'margin-left style is not animated after cancelling');
 
   // Trigger a change to a transition property and check that this
   // doesn't cause the animation to become live again
@@ -119,17 +92,16 @@ test(function(t) {
    + ' it live again');
 
 promise_test(function(t) {
   var div = addDiv(t, { style: 'margin-left: 0px' });
   flushComputedStyle(div);
 
   div.style.transition = 'margin-left 100s';
   div.style.marginLeft = '1000px';
-  flushComputedStyle(div);
 
   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');
@@ -142,24 +114,120 @@ promise_test(function(t) {
   var childDiv = document.createElement('div');
   parentDiv.appendChild(childDiv);
   childDiv.setAttribute('style', 'margin-left: 0px');
 
   flushComputedStyle(childDiv);
 
   childDiv.style.transition = 'margin-left 100s';
   childDiv.style.marginLeft = '1000px';
-  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, '1000px');
   });
 }, 'Setting display:none cancels transitions on a child element');
 
+promise_test(function(t) {
+  var div = addDiv(t, { style: 'margin-left: 0px' });
+  flushComputedStyle(div);
+
+  div.style.transition = 'margin-left 100s';
+  div.style.marginLeft = '1000px';
+
+  var animation = div.getAnimations()[0];
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'running');
+    // Set an unrecognized property value
+    div.style.transitionProperty = 'none';
+    flushComputedStyle(div);
+    return waitForFrame();
+  }).then(function() {
+    assert_equals(animation.playState, 'idle');
+    assert_equals(getComputedStyle(div).marginLeft, '1000px');
+  });
+}, 'Removing a property from transition-property cancels transitions on that '+
+   'property');
+
+promise_test(function(t) {
+  var div = addDiv(t, { style: 'margin-left: 0px' });
+  flushComputedStyle(div);
+
+  div.style.transition = 'margin-left 100s';
+  div.style.marginLeft = '1000px';
+
+  var animation = div.getAnimations()[0];
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'running');
+    div.style.transition = 'margin-top 10s -10s'; // combined duration is zero
+    flushComputedStyle(div);
+    return waitForFrame();
+  }).then(function() {
+    assert_equals(animation.playState, 'idle');
+    assert_equals(getComputedStyle(div).marginLeft, '1000px');
+  });
+}, 'Setting zero combined duration');
+
+promise_test(function(t) {
+  var div = addDiv(t, { style: 'margin-left: 0px' });
+  flushComputedStyle(div);
+
+  div.style.transition = 'margin-left 100s';
+  div.style.marginLeft = '1000px';
+
+  var animation = div.getAnimations()[0];
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'running');
+    div.style.marginLeft = '2000px';
+    flushComputedStyle(div);
+    return waitForFrame();
+  }).then(function() {
+    assert_equals(animation.playState, 'idle');
+  });
+}, 'Changing style to another interpolable value cancels the original ' +
+   'transition');
+
+promise_test(function(t) {
+  var div = addDiv(t, { style: 'margin-left: 0px' });
+  flushComputedStyle(div);
+
+  div.style.transition = 'margin-left 100s';
+  div.style.marginLeft = '1000px';
+
+  var animation = div.getAnimations()[0];
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'running');
+    div.style.marginLeft = 'auto';
+    flushComputedStyle(div);
+    return waitForFrame();
+  }).then(function() {
+    assert_equals(div.getAnimations().length, 0,
+                  'There should be no transitions');
+    assert_equals(animation.playState, 'idle');
+  });
+}, 'An after-change style value can\'t be interpolated');
+
+promise_test(function(t) {
+  var div = addDiv(t, { style: 'margin-left: 0px' });
+  flushComputedStyle(div);
+
+  div.style.transition = 'margin-left 100s';
+  div.style.marginLeft = '1000px';
+
+  var animation = div.getAnimations()[0];
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'running');
+    div.style.marginLeft = '0px';
+    flushComputedStyle(div);
+    return waitForFrame();
+  }).then(function() {
+    assert_equals(animation.playState, 'idle');
+  });
+}, 'Reversing a running transition cancels the original transition');
+
 done();
 </script>
 </body>
rename from dom/animation/test/css-transitions/file_csstransition-events.html
rename to dom/animation/test/css-transitions/file_event-dispatch.html
--- a/dom/animation/test/css-transitions/file_csstransition-events.html
+++ b/dom/animation/test/css-transitions/file_event-dispatch.html
@@ -19,205 +19,456 @@ function TransitionEventHandler(target) 
     this.transitionrun = evt.elapsedTime;
   }.bind(this);
   this.target.ontransitionstart = function(evt) {
     this.transitionstart = evt.elapsedTime;
   }.bind(this);
   this.target.ontransitionend = function(evt) {
     this.transitionend = evt.elapsedTime;
   }.bind(this);
+  this.target.ontransitioncancel = function(evt) {
+    this.transitioncancel = evt.elapsedTime;
+  }.bind(this);
 }
 
 TransitionEventHandler.prototype.clear = function() {
-  this.transitionrun   = undefined;
-  this.transitionstart = undefined;
-  this.transitionend   = undefined;
+  this.transitionrun    = undefined;
+  this.transitionstart  = undefined;
+  this.transitionend    = undefined;
+  this.transitioncancel = undefined;
 };
 
 function setupTransition(t, transitionStyle) {
-  var div, watcher, handler, transition;
-  transitionStyle = transitionStyle || 'transition: margin-left 100s 100s';
-  div = addDiv(t, { style: transitionStyle });
-  watcher = new EventWatcher(t, div, [ 'transitionrun',
-                                       'transitionstart',
-                                       'transitionend' ]);
-  handler = new TransitionEventHandler(div);
+  var div = addDiv(t, { style: 'transition: ' + transitionStyle });
+  var watcher = new EventWatcher(t, div, [ 'transitionrun',
+                                           'transitionstart',
+                                           'transitionend',
+                                           'transitioncancel' ]);
   flushComputedStyle(div);
 
   div.style.marginLeft = '100px';
-  flushComputedStyle(div);
+  var transition = div.getAnimations()[0];
 
-  transition = div.getAnimations()[0];
-
-  return [transition, watcher, handler];
+  return [transition, watcher, div];
 }
 
 // On the next frame (i.e. when events are queued), whether or not the
 // transition is still pending depends on the implementation.
 promise_test(function(t) {
-  var [transition, watcher, handler] = setupTransition(t);
+  var [transition, watcher] =
+    setupTransition(t, 'margin-left 100s 100s');
   return watcher.wait_for('transitionrun').then(function(evt) {
     assert_equals(evt.elapsedTime, 0.0);
   });
 }, 'Idle -> Pending or Before');
 
 promise_test(function(t) {
-  var [transition, watcher, handler] = setupTransition(t);
+  var [transition, watcher] =
+    setupTransition(t, 'margin-left 100s 100s');
   // Force the transition to leave the idle phase
   transition.startTime = document.timeline.currentTime;
   return watcher.wait_for('transitionrun').then(function(evt) {
     assert_equals(evt.elapsedTime, 0.0);
   });
 }, 'Idle -> Before');
 
 promise_test(function(t) {
-  var [transition, watcher, handler] = setupTransition(t);
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s 100s');
+  var handler = new TransitionEventHandler(div);
+
   // Seek to Active phase.
   transition.currentTime = 100 * MS_PER_SEC;
   transition.pause();
   return watcher.wait_for([ 'transitionrun',
                             'transitionstart' ]).then(function(evt) {
     assert_equals(handler.transitionrun, 0.0);
     assert_equals(handler.transitionstart, 0.0);
   });
 }, 'Idle or Pending -> Active');
 
 promise_test(function(t) {
-  var [transition, watcher, handler] = setupTransition(t);
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s 100s');
+  var handler = new TransitionEventHandler(div);
+
   // Seek to After phase.
   transition.finish();
   return watcher.wait_for([ 'transitionrun',
                             'transitionstart',
                             'transitionend' ]).then(function(evt) {
     assert_equals(handler.transitionrun, 0.0);
     assert_equals(handler.transitionstart, 0.0);
     assert_equals(handler.transitionend, 100.0);
   });
 }, 'Idle or Pending -> After');
 
 promise_test(function(t) {
-  var [transition, watcher, handler] = setupTransition(t);
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s 100s');
+
+  return Promise.all([ watcher.wait_for('transitionrun'),
+                       transition.ready ]).then(function() {
+    // Make idle
+    div.style.display = 'none';
+    flushComputedStyle(div);
+    return watcher.wait_for('transitioncancel');
+  }).then(function(evt) {
+    assert_equals(evt.elapsedTime, 0.0);
+  });
+}, 'Before -> Idle (display: none)');
+
+promise_test(function(t) {
+  var [transition, watcher] =
+    setupTransition(t, 'margin-left 100s 100s');
+
+  return Promise.all([ watcher.wait_for('transitionrun'),
+                       transition.ready ]).then(function() {
+    // Make idle
+    transition.timeline = null;
+    return watcher.wait_for('transitioncancel');
+  }).then(function(evt) {
+    assert_equals(evt.elapsedTime, 0.0);
+  });
+}, 'Before -> Idle (Animation.timeline = null)');
+
+promise_test(function(t) {
+  var [transition, watcher] =
+    setupTransition(t, 'margin-left 100s 100s');
 
   return Promise.all([ watcher.wait_for('transitionrun'),
                        transition.ready ]).then(function() {
     transition.currentTime = 100 * MS_PER_SEC;
     return watcher.wait_for('transitionstart');
-  }).then(function() {
-    assert_equals(handler.transitionstart, 0.0);
+  }).then(function(evt) {
+    assert_equals(evt.elapsedTime, 0.0);
   });
 }, 'Before -> Active');
 
 promise_test(function(t) {
-  var [transition, watcher, handler] = setupTransition(t);
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s 100s');
+  var handler = new TransitionEventHandler(div);
+
   return Promise.all([ watcher.wait_for('transitionrun'),
                        transition.ready ]).then(function() {
     // Seek to After phase.
     transition.currentTime = 200 * MS_PER_SEC;
     return watcher.wait_for([ 'transitionstart', 'transitionend' ]);
   }).then(function(evt) {
     assert_equals(handler.transitionstart, 0.0);
     assert_equals(handler.transitionend, 100.0);
   });
 }, 'Before -> After');
 
 promise_test(function(t) {
-  var [transition, watcher, handler] = setupTransition(t);
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s');
+
+  // Seek to Active start position.
+  transition.pause();
+  return watcher.wait_for([ 'transitionrun',
+                            'transitionstart' ]).then(function(evt) {
+    // Make idle
+    div.style.display = 'none';
+    flushComputedStyle(div);
+    return watcher.wait_for('transitioncancel');
+  }).then(function(evt) {
+    assert_equals(evt.elapsedTime, 0.0);
+  });
+}, 'Active -> Idle, no delay (display: none)');
+
+promise_test(function(t) {
+  var [transition, watcher] =
+    setupTransition(t, 'margin-left 100s');
+
+  return watcher.wait_for([ 'transitionrun',
+                            'transitionstart' ]).then(function(evt) {
+    // Make idle
+    transition.currentTime = 0;
+    transition.timeline = null;
+    return watcher.wait_for('transitioncancel');
+  }).then(function(evt) {
+    assert_equals(evt.elapsedTime, 0.0);
+  });
+}, 'Active -> Idle, no delay (Animation.timeline = null)');
+
+promise_test(function(t) {
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s 100s');
+  // Pause so the currentTime is fixed and we can accurately compare the event
+  // time in transition cancel events.
+  transition.pause();
+
+  // Seek to Active phase.
+  transition.currentTime = 100 * MS_PER_SEC;
+  return watcher.wait_for([ 'transitionrun',
+                            'transitionstart' ]).then(function(evt) {
+    // Make idle
+    div.style.display = 'none';
+    flushComputedStyle(div);
+    return watcher.wait_for('transitioncancel');
+  }).then(function(evt) {
+    assert_equals(evt.elapsedTime, 0.0);
+  });
+}, 'Active -> Idle, with positive delay (display: none)');
+
+promise_test(function(t) {
+  var [transition, watcher] =
+    setupTransition(t, 'margin-left 100s 100s');
+
+  // Seek to Active phase.
+  transition.currentTime = 100 * MS_PER_SEC;
+  return watcher.wait_for([ 'transitionrun',
+                            'transitionstart' ]).then(function(evt) {
+    // Make idle
+    transition.currentTime = 100 * MS_PER_SEC;
+    transition.timeline = null;
+    return watcher.wait_for('transitioncancel');
+  }).then(function(evt) {
+    assert_equals(evt.elapsedTime, 0.0);
+  });
+}, 'Active -> Idle, with positive delay (Animation.timeline = null)');
+
+promise_test(function(t) {
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s -50s');
+
+  // Pause so the currentTime is fixed and we can accurately compare the event
+  // time in transition cancel events.
+  transition.pause();
+
+  return watcher.wait_for([ 'transitionrun',
+                            'transitionstart' ]).then(function(evt) {
+    // Make idle
+    div.style.display = 'none';
+    flushComputedStyle(div);
+    return watcher.wait_for('transitioncancel');
+  }).then(function(evt) {
+    assert_equals(evt.elapsedTime, 50.0);
+  });
+}, 'Active -> Idle, with negative delay (display: none)');
+
+promise_test(function(t) {
+  var [transition, watcher] =
+    setupTransition(t, 'margin-left 100s -50s');
+
+  return watcher.wait_for([ 'transitionrun',
+                            'transitionstart' ]).then(function(evt) {
+    // Make idle
+    transition.currentTime = 50 * MS_PER_SEC;
+    transition.timeline = null;
+    return watcher.wait_for('transitioncancel');
+  }).then(function(evt) {
+    assert_equals(evt.elapsedTime, 0.0);
+  });
+}, 'Active -> Idle, with negative delay (Animation.timeline = null)');
+
+promise_test(function(t) {
+  var [transition, watcher] =
+    setupTransition(t, 'margin-left 100s 100s');
   // Seek to Active phase.
   transition.currentTime = 100 * MS_PER_SEC;
   return watcher.wait_for([ 'transitionrun',
                             'transitionstart' ]).then(function(evt) {
     // Seek to Before phase.
     transition.currentTime = 0;
     return watcher.wait_for('transitionend');
   }).then(function(evt) {
     assert_equals(evt.elapsedTime, 0.0);
   });
 }, 'Active -> Before');
 
 promise_test(function(t) {
-  var [transition, watcher, handler] = setupTransition(t);
+  var [transition, watcher] =
+    setupTransition(t, 'margin-left 100s 100s');
   // Seek to Active phase.
   transition.currentTime = 100 * MS_PER_SEC;
   return watcher.wait_for([ 'transitionrun',
                             'transitionstart' ]).then(function(evt) {
     // Seek to After phase.
     transition.currentTime = 200 * MS_PER_SEC;
     return watcher.wait_for('transitionend');
   }).then(function(evt) {
     assert_equals(evt.elapsedTime, 100.0);
   });
 }, 'Active -> After');
 
 promise_test(function(t) {
-  var [transition, watcher, handler] = setupTransition(t);
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s 100s');
+  var handler = new TransitionEventHandler(div);
+
   // Seek to After phase.
   transition.finish();
   return watcher.wait_for([ 'transitionrun',
                             'transitionstart',
                             'transitionend' ]).then(function(evt) {
     // Seek to Before phase.
     transition.currentTime = 0;
     return watcher.wait_for([ 'transitionstart', 'transitionend' ]);
   }).then(function(evt) {
     assert_equals(handler.transitionstart, 100.0);
     assert_equals(handler.transitionend, 0.0);
   });
 }, 'After -> Before');
 
 promise_test(function(t) {
-  var [transition, watcher, handler] = setupTransition(t);
+  var [transition, watcher] =
+    setupTransition(t, 'margin-left 100s 100s');
   // Seek to After phase.
   transition.finish();
   return watcher.wait_for([ 'transitionrun',
                             'transitionstart',
                             'transitionend' ]).then(function(evt) {
     // Seek to Active phase.
     transition.currentTime = 100 * MS_PER_SEC;
     return watcher.wait_for('transitionstart');
   }).then(function(evt) {
     assert_equals(evt.elapsedTime, 100.0);
   });
 }, 'After -> Active');
 
 promise_test(function(t) {
-  var [transition, watcher, handler] =
-    setupTransition(t, 'transition: margin-left 100s -50s');
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s -50s');
+  var handler = new TransitionEventHandler(div);
 
   return watcher.wait_for([ 'transitionrun',
                             'transitionstart' ]).then(function() {
     assert_equals(handler.transitionrun, 50.0);
     assert_equals(handler.transitionstart, 50.0);
     transition.finish();
     return watcher.wait_for('transitionend');
   }).then(function(evt) {
     assert_equals(evt.elapsedTime, 100.0);
   });
 }, 'Calculating the interval start and end time with negative start delay.');
 
 promise_test(function(t) {
-  var [transition, watcher, handler] = setupTransition(t);
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s 100s');
+  var handler = new TransitionEventHandler(div);
 
   return watcher.wait_for('transitionrun').then(function(evt) {
     // We can't set the end delay via generated effect timing.
     // Because CSS-Transition use the AnimationEffectTimingReadOnly.
-    transition.effect = new KeyframeEffect(handler.target,
+    transition.effect = new KeyframeEffect(div,
                                            { marginleft: [ '0px', '100px' ]},
                                            { duration: 100 * MS_PER_SEC,
                                              endDelay: -50 * MS_PER_SEC });
     // Seek to Before and play.
     transition.cancel();
     transition.play();
-    return watcher.wait_for('transitionstart');
+    return watcher.wait_for([ 'transitioncancel',
+                              'transitionrun',
+                              'transitionstart' ]);
   }).then(function() {
     assert_equals(handler.transitionstart, 0.0);
 
     // Seek to After phase.
     transition.finish();
     return watcher.wait_for('transitionend');
   }).then(function(evt) {
     assert_equals(evt.elapsedTime, 50.0);
   });
 }, 'Calculating the interval start and end time with negative end delay.');
 
+promise_test(function(t) {
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s 100s');
+
+  return watcher.wait_for('transitionrun').then(function() {
+    // Make idle
+    div.style.display = 'none';
+    flushComputedStyle(div);
+    return watcher.wait_for('transitioncancel');
+  }).then(function() {
+    transition.cancel();
+    // Then wait a couple of frames and check that no event was dispatched
+    return waitForAnimationFrames(2);
+  });
+}, 'Call Animation.cancel after cancelling transition.');
+
+promise_test(function(t) {
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s 100s');
+
+  return watcher.wait_for('transitionrun').then(function(evt) {
+    // Make idle
+    div.style.display = 'none';
+    flushComputedStyle(div);
+    transition.play();
+    watcher.wait_for([ 'transitioncancel',
+                       'transitionrun',
+                       'transitionstart' ]);
+  });
+}, 'Restart transition after cancelling transition immediately');
+
+promise_test(function(t) {
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s 100s');
+
+  return watcher.wait_for('transitionrun').then(function(evt) {
+    // Make idle
+    div.style.display = 'none';
+    flushComputedStyle(div);
+    transition.play();
+    transition.cancel();
+    return watcher.wait_for('transitioncancel');
+  }).then(function(evt) {
+    // Then wait a couple of frames and check that no event was dispatched
+    return waitForAnimationFrames(2);
+  });
+}, 'Call Animation.cancel after restarting transition immediately');
+
+promise_test(function(t) {
+  var [transition, watcher] =
+    setupTransition(t, 'margin-left 100s');
+
+  return watcher.wait_for([ 'transitionrun',
+                            'transitionstart' ]).then(function(evt) {
+    // Make idle
+    transition.timeline = null;
+    return watcher.wait_for('transitioncancel');
+  }).then(function(evt) {
+    transition.timeline = document.timeline;
+    transition.play();
+
+    return watcher.wait_for(['transitionrun', 'transitionstart']);
+  });
+}, 'Set timeline and play transition after clear the timeline');
+
+promise_test(function(t) {
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s');
+
+  return watcher.wait_for([ 'transitionrun',
+                            'transitionstart' ]).then(function() {
+    transition.cancel();
+    return watcher.wait_for('transitioncancel');
+  }).then(function() {
+    // Make After phase
+    transition.effect = null;
+
+    // Then wait a couple of frames and check that no event was dispatched
+    return waitForAnimationFrames(2);
+  });
+}, 'Set null target effect after cancel the transition');
+
+promise_test(function(t) {
+  var [transition, watcher, div] =
+    setupTransition(t, 'margin-left 100s');
+
+  return watcher.wait_for([ 'transitionrun',
+                            'transitionstart' ]).then(function(evt) {
+    transition.effect = null;
+    return watcher.wait_for('transitionend');
+  }).then(function(evt) {
+    transition.cancel();
+    return watcher.wait_for('transitioncancel');
+  });
+}, 'Cancel the transition after clearing the target effect');
+
 done();
 </script>
 </body>
 </html>
--- a/dom/animation/test/css-transitions/file_setting-effect.html
+++ b/dom/animation/test/css-transitions/file_setting-effect.html
@@ -2,34 +2,39 @@
 <meta charset=utf-8>
 <script src='../testcommon.js'></script>
 <body>
 <script>
 'use strict';
 
 promise_test(function(t) {
   var div = addDiv(t);
+  var watcher = new EventWatcher(t, div, [ 'transitionend',
+                                           'transitioncancel' ]);
   div.style.left = '0px';
 
   div.style.transition = 'left 100s';
   flushComputedStyle(div);
   div.style.left = '100px';
 
   var transition = div.getAnimations()[0];
   return transition.ready.then(function() {
     transition.currentTime = 50 * MS_PER_SEC;
     transition.effect = null;
     assert_equals(transition.transitionProperty, 'left');
     assert_equals(transition.playState, 'finished');
     assert_equals(window.getComputedStyle(div).left, '100px');
+    return watcher.wait_for('transitionend');
   });
 }, 'Test for removing a transition effect');
 
 promise_test(function(t) {
   var div = addDiv(t);
+  var watcher = new EventWatcher(t, div, [ 'transitionend',
+                                           'transitioncancel' ]);
   div.style.left = '0px';
 
   div.style.transition = 'left 100s';
   flushComputedStyle(div);
   div.style.left = '100px';
 
   var transition = div.getAnimations()[0];
   return transition.ready.then(function() {
@@ -41,16 +46,18 @@ promise_test(function(t) {
     assert_equals(transition.playState, 'running');
     assert_equals(window.getComputedStyle(div).left, '100px');
     assert_equals(window.getComputedStyle(div).marginLeft, '50px');
   });
 }, 'Test for replacing the transition effect by a new keyframe effect');
 
 promise_test(function(t) {
   var div = addDiv(t);
+  var watcher = new EventWatcher(t, div, [ 'transitionend',
+                                           'transitioncancel' ]);
   div.style.left = '0px';
   div.style.width = '0px';
 
   div.style.transition = 'left 100s';
   flushComputedStyle(div);
   div.style.left = '100px';
 
   var transition = div.getAnimations()[0];
@@ -60,16 +67,18 @@ promise_test(function(t) {
                                            { marginLeft: [ '0px' , '100px'] },
                                            20 * MS_PER_SEC);
     assert_equals(transition.playState, 'finished');
   });
 }, 'Test for setting a new keyframe effect with a shorter duration');
 
 promise_test(function(t) {
   var div = addDiv(t);
+  var watcher = new EventWatcher(t, div, [ 'transitionend',
+                                           'transitioncancel' ]);
   div.style.left = '0px';
   div.style.width = '0px';
 
   div.style.transition = 'left 100s';
   flushComputedStyle(div);
   div.style.left = '100px';
 
   var transition = div.getAnimations()[0];
rename from dom/animation/test/css-transitions/test_csstransition-events.html
rename to dom/animation/test/css-transitions/test_event-dispatch.html
--- a/dom/animation/test/css-transitions/test_csstransition-events.html
+++ b/dom/animation/test/css-transitions/test_event-dispatch.html
@@ -4,11 +4,11 @@
 <script src="/resources/testharnessreport.js"></script>
 <div id="log"></div>
 <script>
 'use strict';
 setup({explicit_done: true});
 SpecialPowers.pushPrefEnv(
   { "set": [["dom.animations-api.core.enabled", true]]},
   function() {
-    window.open("file_csstransition-events.html");
+    window.open("file_event-dispatch.html");
   });
 </script>
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -23,21 +23,21 @@ support-files =
   css-animations/file_pseudoElement-get-animations.html
   css-transitions/file_animation-cancel.html
   css-transitions/file_animation-computed-timing.html
   css-transitions/file_animation-currenttime.html
   css-transitions/file_animation-finished.html
   css-transitions/file_animation-pausing.html
   css-transitions/file_animation-ready.html
   css-transitions/file_animation-starttime.html
-  css-transitions/file_csstransition-events.html
   css-transitions/file_csstransition-transitionproperty.html
   css-transitions/file_document-get-animations.html
   css-transitions/file_effect-target.html
   css-transitions/file_element-get-animations.html
+  css-transitions/file_event-dispatch.html
   css-transitions/file_keyframeeffect-getkeyframes.html
   css-transitions/file_pseudoElement-get-animations.html
   css-transitions/file_setting-effect.html
   document-timeline/file_document-timeline.html
   mozilla/file_cubic_bezier_limits.html
   mozilla/file_deferred_start.html
   mozilla/file_disabled_properties.html
   mozilla/file_disable_animations_api_core.html
@@ -78,21 +78,21 @@ support-files =
 [css-animations/test_pseudoElement-get-animations.html]
 [css-transitions/test_animation-cancel.html]
 [css-transitions/test_animation-computed-timing.html]
 [css-transitions/test_animation-currenttime.html]
 [css-transitions/test_animation-finished.html]
 [css-transitions/test_animation-pausing.html]
 [css-transitions/test_animation-ready.html]
 [css-transitions/test_animation-starttime.html]
-[css-transitions/test_csstransition-events.html]
 [css-transitions/test_csstransition-transitionproperty.html]
 [css-transitions/test_document-get-animations.html]
 [css-transitions/test_effect-target.html]
 [css-transitions/test_element-get-animations.html]
+[css-transitions/test_event-dispatch.html]
 [css-transitions/test_keyframeeffect-getkeyframes.html]
 [css-transitions/test_pseudoElement-get-animations.html]
 [css-transitions/test_setting-effect.html]
 [document-timeline/test_document-timeline.html]
 [document-timeline/test_request_animation_frame.html]
 [mozilla/test_cubic_bezier_limits.html]
 [mozilla/test_deferred_start.html]
 [mozilla/test_disable_animations_api_core.html]