Backed out changeset 4d85a02e9c28 (bug 1159743) under suspicion of breaking animation tests CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Thu, 30 Apr 2015 15:25:58 -0700
changeset 241963 3ce2f7f110af4f7139fe9edc4d11efb391a07e81
parent 241962 43e99677905e6431b55d6fd1da11c19439e26efd
child 241964 fd384372c6518ce234ac5524fa63e46f7a64dc4a
push id15375
push userryanvm@gmail.com
push dateFri, 01 May 2015 16:59:43 +0000
treeherderb2g-inbound@927a1934960e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1159743
milestone40.0a1
backs out4d85a02e9c286a64c47d21e8f1f12d7fbbeb4c5e
Backed out changeset 4d85a02e9c28 (bug 1159743) under suspicion of breaking animation tests CLOSED TREE
dom/animation/test/css-animations/file_animation-cancel.html
dom/animation/test/css-animations/file_animation-currenttime.html
dom/animation/test/css-animations/file_animation-finish.html
dom/animation/test/css-animations/file_animation-finished.html
dom/animation/test/css-animations/file_animation-pausing.html
dom/animation/test/css-animations/file_animation-playstate.html
dom/animation/test/css-animations/file_animation-ready.html
dom/animation/test/css-animations/file_animation-starttime.html
dom/animation/test/css-animations/file_animations-dynamic-changes.html
dom/animation/test/css-animations/file_effect-name.html
dom/animation/test/css-animations/file_effect-target.html
dom/animation/test/css-animations/file_element-get-animations.html
dom/animation/test/css-animations/test_animation-cancel.html
dom/animation/test/css-animations/test_animation-currenttime.html
dom/animation/test/css-animations/test_animation-finish.html
dom/animation/test/css-animations/test_animation-finished.html
dom/animation/test/css-animations/test_animation-pausing.html
dom/animation/test/css-animations/test_animation-playstate.html
dom/animation/test/css-animations/test_animation-ready.html
dom/animation/test/css-animations/test_animation-starttime.html
dom/animation/test/css-animations/test_animations-dynamic-changes.html
dom/animation/test/css-animations/test_effect-name.html
dom/animation/test/css-animations/test_effect-target.html
dom/animation/test/css-animations/test_element-get-animations.html
dom/animation/test/css-transitions/file_animation-cancel.html
dom/animation/test/css-transitions/file_animation-currenttime.html
dom/animation/test/css-transitions/file_animation-finished.html
dom/animation/test/css-transitions/file_animation-pausing.html
dom/animation/test/css-transitions/file_animation-ready.html
dom/animation/test/css-transitions/file_animation-starttime.html
dom/animation/test/css-transitions/file_effect-name.html
dom/animation/test/css-transitions/file_effect-target.html
dom/animation/test/css-transitions/file_element-get-animations.html
dom/animation/test/css-transitions/test_animation-cancel.html
dom/animation/test/css-transitions/test_animation-currenttime.html
dom/animation/test/css-transitions/test_animation-finished.html
dom/animation/test/css-transitions/test_animation-pausing.html
dom/animation/test/css-transitions/test_animation-ready.html
dom/animation/test/css-transitions/test_animation-starttime.html
dom/animation/test/css-transitions/test_effect-name.html
dom/animation/test/css-transitions/test_effect-target.html
dom/animation/test/css-transitions/test_element-get-animations.html
dom/animation/test/document-timeline/file_document-timeline.html
dom/animation/test/document-timeline/test_document-timeline.html
dom/animation/test/mochitest.ini
dom/animation/test/mozilla/file_deferred_start.html
dom/animation/test/mozilla/test_deferred_start.html
dom/animation/test/testcommon.js
dom/tests/mochitest/general/test_interfaces.html
dom/xslt/tests/mochitest/test_bug1135764.html
layout/style/test/file_animations_pausing.html
layout/style/test/mochitest.ini
layout/style/test/test_animations_pausing.html
testing/profiles/prefs_general.js
testing/web-platform/meta/web-animations/animation-timeline/animation-timeline.html.ini
testing/web-platform/meta/web-animations/animation-timeline/idlharness.html.ini
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_animation-cancel.html
+++ /dev/null
@@ -1,164 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-@keyframes translateAnim {
-  to { transform: translate(100px) }
-}
-@keyframes marginLeftAnim {
-  to { margin-left: 100px }
-}
-@keyframes marginLeftAnim100To200 {
-  from { margin-left: 100px }
-  to { margin-left: 200px }
-}
-</style>
-<body>
-<script>
-'use strict';
-
-async_test(function(t) {
-  var div = addDiv(t, { style: 'animation: translateAnim 100s' });
-
-  var animation = div.getAnimations()[0];
-  animation.ready.then(t.step_func(function() {
-    assert_not_equals(getComputedStyle(div).transform, 'none',
-                      'transform style is animated before cancelling');
-    animation.cancel();
-    assert_equals(getComputedStyle(div).transform, 'none',
-                  'transform style is no longer animated after cancelling');
-    t.done();
-  }));
-}, 'Animated style is cleared after cancelling a running CSS animation');
-
-async_test(function(t) {
-  var div = addDiv(t, { style: 'animation: translateAnim 100s forwards' });
-
-  var animation = div.getAnimations()[0];
-  animation.finish();
-
-  animation.ready.then(t.step_func(function() {
-    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');
-    t.done();
-  }));
-}, 'Animated style is cleared after cancelling a filling CSS animation');
-
-async_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');
-  }));
-
-  animation.ready.then(t.step_func(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);
-  })).then(t.step_func(function() {
-    t.done();
-  }));
-}, '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');
-
-async_test(function(t) {
-  var div =
-    addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
-
-  var animation = div.getAnimations()[0];
-  animation.ready.then(t.step_func(function() {
-    animation.cancel();
-    assert_equals(getComputedStyle(div).marginLeft, '0px',
-                  'margin-left style is not animated after cancelling');
-    animation.play();
-    assert_equals(getComputedStyle(div).marginLeft, '100px',
-                  'margin-left style is animated after re-starting animation');
-    return animation.ready;
-  })).then(t.step_func(function() {
-    assert_equals(animation.playState, 'running',
-                  'Animation succeeds in running after being re-started');
-    t.done();
-  }));
-}, 'After cancelling an animation, it can still be re-used');
-
-test(function(t) {
-  var div =
-    addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
-
-  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');
-
-test(function(t) {
-  var div =
-    addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
-
-  var animation = div.getAnimations()[0];
-  animation.cancel();
-  assert_equals(getComputedStyle(div).marginLeft, '0px',
-                'margin-left style is not animated after cancelling');
-
-  // Make some changes to animation-play-state and check that the
-  // animation doesn't become live again. This is because it should be
-  // possible to cancel an animation from script such that all future
-  // changes to style are ignored.
-
-  // Redundant change
-  div.style.animationPlayState = 'running';
-  assert_equals(animation.playState, 'idle',
-                'Animation is still idle after a redundant change to'
-                + ' animation-play-state');
-
-  // Pause
-  div.style.animationPlayState = 'paused';
-  assert_equals(animation.playState, 'idle',
-                'Animation is still idle after setting'
-                + ' animation-play-state: paused');
-
-  // Play
-  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');
-
-done();
-</script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_animation-currenttime.html
+++ /dev/null
@@ -1,548 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset=utf-8>
-    <title>Tests for the effect of setting a CSS animation's
-           Animation.currentTime</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: add equivalent tests without an animation-delay, but first we need to
-// change the timing of animationstart dispatch. (Right now the animationstart
-// event will fire before the ready Promise is resolved if there is no
-// animation-delay.)
-// See https://bugzilla.mozilla.org/show_bug.cgi?id=1134163
-
-// 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'];
-const ANIM_DELAY_MS = 1000000; // 1000s
-const ANIM_DUR_MS = 1000000; // 1000s
-const ANIM_PROPERTY_VAL = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
-
-/**
- * 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(timeline) {
-  return ANIM_DELAY_MS / 2;
-}
-function currentTimeForActivePhase(timeline) {
-  return ANIM_DELAY_MS + ANIM_DUR_MS / 2;
-}
-function currentTimeForAfterPhase(timeline) {
-  return ANIM_DELAY_MS + ANIM_DUR_MS + ANIM_DELAY_MS / 2;
-}
-function currentTimeForStartOfActiveInterval(timeline) {
-  return ANIM_DELAY_MS;
-}
-function currentTimeForFiftyPercentThroughActiveInterval(timeline) {
-  return ANIM_DELAY_MS + ANIM_DUR_MS * 0.5;
-}
-function currentTimeForEndOfActiveInterval(timeline) {
-  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 UNANIMATED_POSITION = 10;
-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:
-//
-//   https://w3c.github.io/web-animations/#animation-effect-phases-and-states
-//
-// Note the distinction between the "animation start time" which occurs before
-// the start delay and the start of the active interval which occurs after it.
-
-// 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');
-
-  assert_equals(animation.effect.target.style.animationPlayState, 'running',
-    'Animation.effect.target.style.animationPlayState 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, UNANIMATED_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');
-
-  assert_equals(animation.effect.target.style.animationPlayState, 'running',
-    'Animation.effect.target.style.animationPlayState 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');
-
-  assert_equals(animation.effect.target.style.animationPlayState, "running",
-    'Animation.effect.target.style.animationPlayState should be ' +
-    '"finished" at the end of the active interval');
-
-  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 ' +
-    'by the animation at the end of the active duration when the ' +
-    'animation-fill-mode is none');
-}
-
-
-test(function(t)
-{
-  var div = addDiv(t, {'class': 'animated-div'});
-
-  div.style.animation = ANIM_PROPERTY_VAL;
-
-  var animation = div.getAnimations()[0];
-
-  // Animations shouldn't start until the next paint tick, so:
-  assert_equals(animation.currentTime, 0,
-    'Animation.currentTime should be zero when an animation ' +
-    'is initially created');
-
-  assert_equals(animation.playState, "pending",
-    'Animation.playState should be "pending" when an animation ' +
-    'is initially created');
-
-  assert_equals(animation.effect.target.style.animationPlayState, 'running',
-    'Animation.effect.target.style.animationPlayState should be ' +
-    '"running" when an animation is initially created');
-
-  // XXX Ideally we would have a test to check the ready Promise is initially
-  // unresolved, but currently there is no Web API to do that. Waiting for the
-  // ready Promise with a timeout doesn't work because the resolved callback
-  // will be called (async) regardless of whether the Promise was resolved in
-  // the past or is resolved in the future.
-
-  // So that animation is running instead of paused when we set currentTime:
-  animation.startTime = animation.timeline.currentTime;
-
-  assert_approx_equals(animation.currentTime, 0, 0.0001, // rounding error
-    'Check setting of currentTime actually works');
-
-  checkStateOnSettingCurrentTimeToZero(animation);
-}, '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, CSS_ANIM_EVENTS);
-
-  div.style.animation = ANIM_PROPERTY_VAL;
-
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(function() {
-    checkStateOnReadyPromiseResolved(animation);
-
-    animation.currentTime =
-      currentTimeForStartOfActiveInterval(animation.timeline);
-    return eventWatcher.wait_for('animationstart');
-  })).then(t.step_func(function() {
-    checkStateAtActiveIntervalStartTime(animation);
-
-    animation.currentTime =
-      currentTimeForFiftyPercentThroughActiveInterval(animation.timeline);
-    checkStateAtFiftyPctOfActiveInterval(animation);
-
-    animation.currentTime =
-      currentTimeForEndOfActiveInterval(animation.timeline);
-    return eventWatcher.wait_for('animationend');
-  })).then(t.step_func(function() {
-    checkStateAtActiveIntervalEndTime(animation);
-  })).catch(t.step_func(function(reason) {
-    assert_unreached(reason);
-  })).then(function() {
-    t.done();
-  });
-}, 'Skipping forward through animation');
-
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-
-  div.style.animation = ANIM_PROPERTY_VAL;
-
-  var animation = div.getAnimations()[0];
-
-  // So that animation is running instead of paused when we set currentTime:
-  animation.startTime = animation.timeline.currentTime;
-
-  animation.currentTime = currentTimeForEndOfActiveInterval(animation.timeline);
-
-  var previousTimelineTime = animation.timeline.currentTime;
-
-  // Skipping over the active interval will dispatch an 'animationstart' then
-  // an 'animationend' event. We need to wait for these events before we start
-  // testing going backwards since EventWatcher will fail the test if it gets
-  // an event that we haven't told it about.
-  eventWatcher.wait_for(['animationstart',
-                         'animationend']).then(t.step_func(function() {
-    assert_true(document.timeline.currentTime - previousTimelineTime <
-                  ANIM_DUR_MS,
-                'Sanity check that seeking worked rather than the events ' +
-                'firing after normal playback through the very long ' +
-                'animation duration');
-
-    // Now we can start the tests for skipping backwards, but first we check
-    // that after the events we're still in the same end time state:
-    checkStateAtActiveIntervalEndTime(animation);
-
-    animation.currentTime =
-      currentTimeForFiftyPercentThroughActiveInterval(animation.timeline);
-
-    // 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.
-    //
-    // Calling checkStateAtFiftyPctOfActiveInterval will check computed style,
-    // causing computed style to be updated and the 'animationstart' event to
-    // be dispatched synchronously. We need to call wait_for first
-    // otherwise eventWatcher will assert that the event was unexpected.
-    var promise = eventWatcher.wait_for('animationstart');
-    checkStateAtFiftyPctOfActiveInterval(animation);
-    return promise;
-  })).then(t.step_func(function() {
-    animation.currentTime =
-      currentTimeForStartOfActiveInterval(animation.timeline);
-    checkStateAtActiveIntervalStartTime(animation);
-
-    animation.currentTime = 0;
-    // 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(t.step_func(function() {
-    checkStateOnReadyPromiseResolved(animation);
-  })).catch(t.step_func(function(reason) {
-    assert_unreached(reason);
-  })).then(function() {
-    t.done();
-  });
-
-  // This must come after we've set up the Promise chain, since requesting
-  // computed style will force events to be dispatched.
-  // XXX For some reason this fails occasionally (either the animation.playState
-  // check or the marginLeft check).
-  //checkStateAtActiveIntervalEndTime(animation);
-}, 'Skipping backwards through animation');
-
-
-// Next we have multiple tests to check that redundant currentTime 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.
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-  div.style.animation = ANIM_PROPERTY_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.currentTime = currentTimeForActivePhase(animation.timeline);
-  animation.currentTime = currentTimeForBeforePhase(animation.timeline);
-
-  waitForAnimationFrames(2).then(function() {
-    t.done();
-  });
-}, 'Redundant change, before -> active, then back');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-  div.style.animation = ANIM_PROPERTY_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.currentTime = currentTimeForAfterPhase(animation.timeline);
-  animation.currentTime = currentTimeForBeforePhase(animation.timeline);
-
-  waitForAnimationFrames(2).then(function() {
-    t.done();
-  });
-}, 'Redundant change, before -> after, then back');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-  div.style.animation = ANIM_PROPERTY_VAL;
-  var animation = div.getAnimations()[0];
-
-  eventWatcher.wait_for('animationstart').then(function() {
-    animation.currentTime = currentTimeForBeforePhase(animation.timeline);
-    animation.currentTime = currentTimeForActivePhase(animation.timeline);
-
-    waitForAnimationFrames(2).then(function() {
-      t.done();
-    });
-  });
-  // get us into the initial state:
-  animation.currentTime = currentTimeForActivePhase(animation.timeline);
-}, 'Redundant change, active -> before, then back');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-  div.style.animation = ANIM_PROPERTY_VAL;
-  var animation = div.getAnimations()[0];
-
-  eventWatcher.wait_for('animationstart').then(function() {
-    animation.currentTime = currentTimeForAfterPhase(animation.timeline);
-    animation.currentTime = currentTimeForActivePhase(animation.timeline);
-
-    waitForAnimationFrames(2).then(function() {
-      t.done();
-    });
-  });
-  // get us into the initial state:
-  animation.currentTime = currentTimeForActivePhase(animation.timeline);
-}, 'Redundant change, active -> after, then back');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-  div.style.animation = ANIM_PROPERTY_VAL;
-  var animation = div.getAnimations()[0];
-
-  eventWatcher.wait_for(['animationstart',
-                         'animationend']).then(function() {
-    animation.currentTime = currentTimeForBeforePhase(animation.timeline);
-    animation.currentTime = currentTimeForAfterPhase(animation.timeline);
-
-    waitForAnimationFrames(2).then(function() {
-      t.done();
-    });
-  });
-  // get us into the initial state:
-  animation.currentTime = currentTimeForAfterPhase(animation.timeline);
-}, 'Redundant change, after -> before, then back');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-  div.style.animation = ANIM_PROPERTY_VAL;
-  var animation = div.getAnimations()[0];
-
-  eventWatcher.wait_for(['animationstart',
-                         'animationend']).then(function() {
-    animation.currentTime = currentTimeForActivePhase(animation.timeline);
-    animation.currentTime = currentTimeForAfterPhase(animation.timeline);
-
-    waitForAnimationFrames(2).then(function() {
-      t.done();
-    });
-  });
-  // get us into the initial state:
-  animation.currentTime = currentTimeForAfterPhase(animation.timeline);
-}, 'Redundant change, after -> active, then back');
-
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  div.style.animation = ANIM_PROPERTY_VAL;
-
-  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'});
-  div.style.animation = 'anim 100s';
-
-  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');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  div.style.animation = ANIM_PROPERTY_VAL;
-
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(function() {
-    // just before animation ends:
-    animation.currentTime = ANIM_DELAY_MS + ANIM_DUR_MS - 1;
-
-    return waitForAnimationFrames(2);
-  }).then(t.step_func(function() {
-    assert_equals(animation.currentTime, ANIM_DELAY_MS + ANIM_DUR_MS,
-      'Animation.currentTime should not continue to increase after the ' +
-      'animation has finished');
-    t.done();
-  }));
-}, 'Animation.currentTime clamping');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  div.style.animation = ANIM_PROPERTY_VAL;
-
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(function() {
-    // play backwards:
-    animation.playbackRate = -1;
-
-    // just before animation ends (at the "start"):
-    animation.currentTime = 1;
-
-    return waitForAnimationFrames(2);
-  }).then(t.step_func(function() {
-    assert_equals(animation.currentTime, 0,
-      'Animation.currentTime should not continue to decrease after an ' +
-      'animation running in reverse has finished and currentTime is zero');
-    t.done();
-  }));
-}, 'Animation.currentTime clamping for reversed animation');
-
-test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  div.style.animation = 'anim 100s';
-
-  var animation = div.getAnimations()[0];
-  animation.cancel();
-  assert_equals(animation.currentTime, null,
-                'The currentTime of a cancelled animation should be null');
-}, 'Animation.currentTime after cancelling');
-
-done();
-    </script>
-  </body>
-</html>
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_animation-finish.html
+++ /dev/null
@@ -1,160 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-
-.animated-div {
-  margin-left: 10px;
-}
-
-@keyframes anim {
-  from { margin-left: 100px; }
-  to { margin-left: 200px; }
-}
-
-</style>
-<body>
-<script>
-
-'use strict';
-
-const ANIM_PROP_VAL = 'anim 100s';
-const ANIM_DURATION = 100000; // ms
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.playbackRate = 0;
-
-  var threw = false;
-  try {
-    animation.finish();
-  } catch (e) {
-    threw = true;
-    assert_equals(e.name, 'InvalidStateError',
-                  'Exception should be an InvalidStateError exception when ' +
-                  'trying to finish an animation with playbackRate == 0');
-  }
-  assert_true(threw,
-              'Expect InvalidStateError exception trying to finish an ' +
-              'animation with playbackRate == 0');
-}, 'Test exceptions when finishing non-running animation');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  div.style.animationIterationCount = 'infinite';
-  var animation = div.getAnimations()[0];
-
-  var threw = false;
-  try {
-    animation.finish();
-  } catch (e) {
-    threw = true;
-    assert_equals(e.name, 'InvalidStateError',
-                  'Exception should be an InvalidStateError exception when ' +
-                  'trying to finish an infinite animation');
-  }
-  assert_true(threw,
-              'Expect InvalidStateError exception trying to finish an ' +
-              'infinite animation');
-}, 'Test exceptions when finishing infinite animation');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.finish();
-  assert_equals(animation.currentTime, ANIM_DURATION,
-                'After finishing, the currentTime should be set to the end ' +
-                'of the active duration');
-}, 'Test finishing of animation');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.currentTime = ANIM_DURATION + 1000; // 1s past effect end
-
-  animation.finish();
-  assert_equals(animation.currentTime, ANIM_DURATION,
-                'After finishing, the currentTime should be set back to the ' +
-                'end of the active duration');
-}, 'Test finishing of animation with a current time past the effect end');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.currentTime = ANIM_DURATION;
-
-  animation.finished.then(t.step_func(function() {
-    animation.playbackRate = -1;
-    animation.finish();
-    assert_equals(animation.currentTime, 0,
-                  'After finishing a reversed animation the currentTime ' +
-                  'should be set to zero');
-    t.done();
-  }));
-}, 'Test finishing of reversed animation');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.currentTime = ANIM_DURATION;
-
-  animation.finished.then(t.step_func(function() {
-    animation.playbackRate = -1;
-
-    animation.currentTime = -1000;
-
-    animation.finish();
-    assert_equals(animation.currentTime, 0,
-                  'After finishing a reversed animation the currentTime ' +
-                  'should be set back to zero');
-    t.done();
-  }));
-}, 'Test finishing of reversed animation with with a current time less ' +
-   'than zero');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.pause();
-
-  animation.ready.then(t.step_func(function() {
-    animation.finish();
-    assert_equals(animation.playState, 'paused',
-                  'The play state of a paused animation should remain ' +
-                  '"paused" even after finish() is called');
-    t.done();
-  }));
-}, 'Test paused state after finishing of animation');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(function() {
-    animation.finish();
-    var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
-    assert_equals(marginLeft, 10,
-                  'The computed style should be reset when finish() is ' +
-                  'called');
-    t.done();
-  }));
-}, 'Test resetting of computed style');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_animation-finished.html
+++ /dev/null
@@ -1,351 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-@keyframes abc {
-  to { transform: translate(10px) }
-}
-@keyframes def {}
-</style>
-<body>
-<script>
-'use strict';
-
-const ANIM_PROP_VAL = 'abc 100s';
-const ANIM_DURATION = 100000; // ms
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  var previousFinishedPromise = animation.finished;
-
-  animation.ready.then(t.step_func(function() {
-    assert_equals(animation.finished, previousFinishedPromise,
-                  'Finished promise is the same object when playing starts');
-    animation.pause();
-    assert_equals(animation.finished, previousFinishedPromise,
-                  'Finished promise does not change when pausing');
-    animation.play();
-    assert_equals(animation.finished, previousFinishedPromise,
-                  'Finished promise does not change when play() unpauses');
-
-    animation.currentTime = ANIM_DURATION;
-
-    return animation.finished;
-  })).then(t.step_func(function() {
-    assert_equals(animation.finished, previousFinishedPromise,
-                  'Finished promise is the same object when playing completes');
-    t.done();
-  }));
-}, 'Test pausing then playing does not change the finished promise');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  var previousFinishedPromise = animation.finished;
-
-  animation.currentTime = ANIM_DURATION;
-
-  animation.finished.then(t.step_func(function() {
-    assert_equals(animation.finished, previousFinishedPromise,
-                  'Finished promise is the same object when playing completes');
-    animation.play();
-    assert_not_equals(animation.finished, previousFinishedPromise,
-                  'Finished promise changes when replaying animation');
-
-    previousFinishedPromise = animation.finished;
-    animation.play();
-    assert_equals(animation.finished, previousFinishedPromise,
-                  'Finished promise is the same after redundant play() call');
-
-    t.done();
-  }));
-}, 'Test restarting a finished animation');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  var previousFinishedPromise;
-
-  animation.currentTime = ANIM_DURATION;
-
-  animation.finished.then(t.step_func(function() {
-    previousFinishedPromise = animation.finished;
-    animation.playbackRate = -1;
-    assert_not_equals(animation.finished, previousFinishedPromise,
-                      'Finished promise should be replaced when reversing a ' +
-                      'finished promise');
-    animation.currentTime = 0;
-    return animation.finished;
-  })).then(t.step_func(function() {
-    previousFinishedPromise = animation.finished;
-    animation.play();
-    assert_not_equals(animation.finished, previousFinishedPromise,
-                      'Finished promise is replaced after play() call on ' +
-                      'finished, reversed animation');
-    t.done();
-  }));
-}, 'Test restarting a reversed finished animation');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  var previousFinishedPromise = animation.finished;
-
-  animation.currentTime = ANIM_DURATION;
-
-  animation.finished.then(t.step_func(function() {
-    animation.currentTime = ANIM_DURATION + 1000;
-    assert_equals(animation.finished, previousFinishedPromise,
-                  'Finished promise is unchanged jumping past end of ' +
-                  'finished animation');
-
-    t.done();
-  }));
-}, 'Test redundant finishing of animation');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.currentTime = ANIM_DURATION;
-  animation.finished.then(t.step_func(function(resolvedAnimation) {
-    assert_equals(resolvedAnimation, animation,
-                  'Object identity of animation passed to Promise callback'
-                  + ' matches the animation object owning the Promise');
-    t.done();
-  }));
-}, 'The finished promise is fulfilled with its Animation');
-
-async_test(function(t) {
-  var div = addDiv(t);
-
-  // Set up pending animation
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-  var previousFinishedPromise = animation.finished;
-
-  // Set up listeners on finished promise
-  animation.finished.then(t.step_func(function() {
-    assert_unreached('finished promise is fulfilled');
-  })).catch(t.step_func(function(err) {
-    assert_equals(err.name, 'AbortError',
-                  'finished promise is rejected with AbortError');
-    assert_not_equals(animation.finished, previousFinishedPromise,
-                      'Finished promise should change after the original is ' +
-                      'rejected');
-  })).then(t.step_func(function() {
-    t.done();
-  }));
-
-  // Now cancel the animation and flush styles
-  div.style.animation = '';
-  window.getComputedStyle(div).animation;
-
-}, 'finished promise is rejected when an animation is cancelled by resetting ' +
-   'the animation property');
-
-async_test(function(t) {
-  var div = addDiv(t);
-
-  // As before, but this time instead of removing all animations, simply update
-  // the list of animations. At least for Firefox, updating is a different
-  // code path.
-
-  // Set up pending animation
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-  var previousFinishedPromise = animation.finished;
-
-  // Set up listeners on finished promise
-  animation.finished.then(t.step_func(function() {
-    assert_unreached('finished promise was fulfilled');
-  })).catch(t.step_func(function(err) {
-    assert_equals(err.name, 'AbortError',
-                  'finished promise is rejected with AbortError');
-    assert_not_equals(animation.finished, previousFinishedPromise,
-                      'Finished promise should change after the original is ' +
-                      'rejected');
-  })).then(t.step_func(function() {
-    t.done();
-  }));
-
-  // Now update the animation and flush styles
-  div.style.animation = 'def 100s';
-  window.getComputedStyle(div).animation;
-
-}, 'finished promise is rejected when an animation is cancelled by changing ' +
-   'the animation property');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-  var previousFinishedPromise = animation.finished;
-
-  // Set up listeners on finished promise
-  animation.finished.then(t.step_func(function() {
-    assert_unreached('finished promise was fulfilled');
-  })).catch(t.step_func(function(err) {
-    assert_equals(err.name, 'AbortError',
-                  'finished promise is rejected with AbortError');
-    assert_not_equals(animation.finished, previousFinishedPromise,
-                      'Finished promise should change after the original is ' +
-                      'rejected');
-  })).then(t.step_func(function() {
-    t.done();
-  }));
-
-  animation.cancel();
-
-}, 'finished promise is rejected when an animation is cancelled by calling ' +
-   'cancel()');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  var previousFinishedPromise = animation.finished;
-
-  animation.currentTime = ANIM_DURATION;
-
-  animation.finished.then(t.step_func(function() {
-    animation.cancel();
-    assert_not_equals(animation.finished, previousFinishedPromise,
-                      'A new finished promise should be created when'
-                      + ' cancelling a finished player');
-  })).then(t.step_func(function() {
-    t.done();
-  }));
-}, 'cancelling an already-finished player replaces the finished promise');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-  animation.cancel();
-
-  // The spec says we still create a new finished promise and reject the old
-  // one even if we're already idle. That behavior might change, but for now
-  // test that we do that.
-  animation.finished.catch(t.step_func(function(err) {
-    assert_equals(err.name, 'AbortError',
-                  'finished promise is rejected with AbortError');
-    t.done();
-  }));
-
-  // Redundant call to cancel();
-  var previousFinishedPromise = animation.finished;
-  animation.cancel();
-  assert_not_equals(animation.finished, previousFinishedPromise,
-                    'A redundant call to cancel() should still generate a new'
-                    + ' finished promise');
-}, 'cancelling an idle player still replaces the finished promise');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  const HALF_DUR = ANIM_DURATION / 2;
-  const QUARTER_DUR = ANIM_DURATION / 4;
-
-  animation.currentTime = HALF_DUR;
-  div.style.animationDuration = QUARTER_DUR + 'ms';
-  // Animation should now be finished
-
-  // Below we use gotNextFrame to check that shortening of the animation
-  // duration causes the finished promise to resolve, rather than it just
-  // getting resolved on the next animation frame. This relies on the fact
-  // that the promises are resolved as a micro-task before the next frame
-  // happens.
-
-  window.getComputedStyle(div).animationDuration; // flush style
-  var gotNextFrame = false;
-  waitForFrame().then(function() {
-    gotNextFrame = true;
-  });
-
-  animation.finished.then(t.step_func(function() {
-    assert_false(gotNextFrame, 'shortening of the animation duration should ' +
-                               'resolve the finished promise');
-    assert_equals(animation.currentTime, HALF_DUR,
-                  'currentTime should be unchanged when duration shortened');
-    var previousFinishedPromise = animation.finished;
-    div.style.animationDuration = ANIM_DURATION + 'ms'; // now active again
-    window.getComputedStyle(div).animationDuration; // flush style
-    assert_not_equals(animation.finished, previousFinishedPromise,
-                      'Finished promise should change after lengthening the ' +
-                      'duration causes the animation to become active');
-    t.done();
-  }));
-}, 'Test finished promise changes for animation duration changes');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(function() {
-    animation.playbackRate = 0;
-    animation.currentTime = ANIM_DURATION + 1000;
-    return waitForAnimationFrames(2);
-  }).then(t.step_func(function() {
-    t.done();
-  }));
-
-  animation.finished.then(t.step_func(function() {
-    assert_unreached('finished promise should not resolve when playbackRate ' +
-                     'is zero');
-  }));
-}, 'Test finished promise changes when playbackRate == 0');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(function() {
-    animation.playbackRate = -1;
-    return animation.finished;
-  }).then(t.step_func(function() {
-    t.done();
-  }));
-}, 'Test finished promise resolves when playbackRate set to a negative value');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = ANIM_PROP_VAL;
-  var animation = div.getAnimations()[0];
-
-  var previousFinishedPromise = animation.finished;
-
-  animation.currentTime = ANIM_DURATION;
-
-  animation.finished.then(function() {
-    div.style.animationPlayState = 'running';
-    return waitForAnimationFrames(2);
-  }).then(t.step_func(function() {
-    assert_equals(animation.finished, previousFinishedPromise,
-                  'Should not replay when animation-play-state changes to ' +
-                  '"running" on finished animation');
-    assert_equals(animation.currentTime, ANIM_DURATION,
-                  'currentTime should not change when animation-play-state ' +
-                  'changes to "running" on finished animation');
-    t.done();
-  }));
-}, 'Test finished promise changes when animationPlayState set to running');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_animation-pausing.html
+++ /dev/null
@@ -1,202 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-@keyframes anim { 
-  0% { margin-left: 0px }
-  100% { margin-left: 10000px }
-}
-</style>
-<body>
-<script>
-'use strict';
-
-function getMarginLeft(cs) {
-  return parseFloat(cs.marginLeft);
-}
-
-async_test(function(t) {
-  var div = addDiv(t);
-  var cs = window.getComputedStyle(div);
-  div.style.animation = 'anim 1000s';
-
-  var animation = div.getAnimations()[0];
-
-  assert_equals(getMarginLeft(cs), 0,
-                'Initial value of margin-left is zero');
-  var previousAnimVal = getMarginLeft(cs);
-
-  animation.ready.then(waitForFrame).then(t.step_func(function() {
-    assert_true(getMarginLeft(cs) > previousAnimVal,
-                'margin-left is initially increasing');
-    animation.pause();
-    return animation.ready;
-  })).then(t.step_func(function() {
-    previousAnimVal = getMarginLeft(cs);
-    return waitForFrame();
-  })).then(t.step_func(function() {
-    assert_equals(getMarginLeft(cs), previousAnimVal,
-                  'margin-left does not increase after calling pause()');
-    t.done();
-  }));
-}, 'pause() a running animation');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  var cs = window.getComputedStyle(div);
-  div.style.animation = 'anim 1000s paused';
-
-  var animation = div.getAnimations()[0];
-  assert_equals(getMarginLeft(cs), 0,
-                'Initial value of margin-left is zero');
-
-  animation.pause();
-  div.style.animationPlayState = 'running';
-
-  animation.ready.then(waitForFrame).then(t.step_func(function() {
-    assert_equals(cs.animationPlayState, 'running',
-                  'animation-play-state is running');
-    assert_equals(getMarginLeft(cs), 0,
-                  'Paused value of margin-left is zero');
-    t.done();
-  }));
-}, 'pause() overrides animation-play-state');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  var cs = window.getComputedStyle(div);
-  div.style.animation = 'anim 1000s paused';
-
-  var animation = div.getAnimations()[0];
-
-  assert_equals(getMarginLeft(cs), 0,
-                'Initial value of margin-left is zero');
-
-  animation.play();
-
-  animation.ready.then(waitForFrame).then(t.step_func(function() {
-    assert_true(getMarginLeft(cs) > 0,
-                'Playing value of margin-left is greater than zero');
-    t.done();
-  }));
-}, 'play() overrides animation-play-state');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  var cs = window.getComputedStyle(div);
-  div.style.animation = 'anim 1000s paused';
-
-  var animation = div.getAnimations()[0];
-  assert_equals(getMarginLeft(cs), 0,
-                'Initial value of margin-left is zero');
-
-  animation.play();
-
-  var previousAnimVal;
-
-  animation.ready.then(function() {
-    div.style.animationPlayState = 'running';
-    cs.animationPlayState; // Trigger style resolution
-    return waitForFrame();
-  }).then(t.step_func(function() {
-    assert_equals(cs.animationPlayState, 'running',
-                  'animation-play-state is running');
-    div.style.animationPlayState = 'paused';
-    return animation.ready;
-  })).then(t.step_func(function() {
-    assert_equals(cs.animationPlayState, 'paused',
-                  'animation-play-state is paused');
-    previousAnimVal = getMarginLeft(cs);
-    return waitForFrame();
-  })).then(t.step_func(function() {
-    assert_equals(getMarginLeft(cs), previousAnimVal,
-                  'Animated value of margin-left does not change when'
-                  + ' paused by style');
-    t.done();
-  }));
-}, 'play() is overridden by later setting "animation-play-state: paused"');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  var cs = window.getComputedStyle(div);
-  div.style.animation = 'anim 1000s';
-
-  var animation = div.getAnimations()[0];
-  assert_equals(getMarginLeft(cs), 0,
-                'Initial value of margin-left is zero');
-
-  // Set the specified style first. If implementations fail to
-  // apply the style changes first, they will ignore the redundant
-  // call to play() and fail to correctly override the pause style.
-  div.style.animationPlayState = 'paused';
-  animation.play();
-  var previousAnimVal = getMarginLeft(cs);
-
-  animation.ready.then(waitForFrame).then(t.step_func(function() {
-    assert_equals(cs.animationPlayState, 'paused',
-                  'animation-play-state is paused');
-    assert_true(getMarginLeft(cs) > previousAnimVal,
-                'Playing value of margin-left is increasing');
-    t.done();
-  }));
-}, 'play() flushes pending changes to animation-play-state first');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  var cs = window.getComputedStyle(div);
-  div.style.animation = 'anim 1000s paused';
-
-  var animation = div.getAnimations()[0];
-  assert_equals(getMarginLeft(cs), 0,
-                'Initial value of margin-left is zero');
-
-  // Unlike the previous test for play(), since calling pause() is sticky,
-  // we'll apply it even if the underlying style also says we're paused.
-  //
-  // We would like to test that implementations flush styles before running
-  // pause() but actually there's no style we can currently set that will
-  // change the behavior of pause(). That may change in the future
-  // (e.g. if we introduce animation-timeline or animation-playback-rate etc.).
-  //
-  // For now this just serves as a sanity check that we do the same thing
-  // even if we set style before calling the API.
-  div.style.animationPlayState = 'running';
-  animation.pause();
-  var previousAnimVal = getMarginLeft(cs);
-
-  animation.ready.then(waitForFrame).then(t.step_func(function() {
-    assert_equals(cs.animationPlayState, 'running',
-                  'animation-play-state is running');
-    assert_equals(getMarginLeft(cs), previousAnimVal,
-                  'Paused value of margin-left does not change');
-    t.done();
-  }));
-}, 'pause() applies pending changes to animation-play-state first');
-// (Note that we can't actually test for this; see comment above, in test-body.)
-
-async_test(function(t) {
-  var div = addDiv(t, { style: 'animation: anim 1000s' });
-  var animation = div.getAnimations()[0];
-
-  var readyPromiseRun = false;
-
-  animation.ready.then(t.step_func(function() {
-    div.style.animationPlayState = 'paused';
-    assert_equals(animation.playState, 'pending', 'Animation is pause pending');
-
-    // Set current time
-    animation.currentTime = 5000;
-    assert_equals(animation.playState, 'running',
-                  'Animation is running immediately after setting currentTime');
-
-    // The ready promise should now be resolved. If it's not then test will
-    // probably time out before anything else happens that causes it to resolve.
-    return animation.ready;
-  })).then(t.step_func(function() {
-    t.done();
-  }));
-}, 'Setting the current time cancels a pending pause');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_animation-playstate.html
+++ /dev/null
@@ -1,89 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-@keyframes anim { }
-</style>
-<body>
-<script>
-'use strict';
-
-async_test(function(t) {
-  var div = addDiv(t);
-  var cs = window.getComputedStyle(div);
-  div.style.animation = 'anim 1000s';
-
-  var animation = div.getAnimations()[0];
-  assert_equals(animation.playState, 'pending');
-
-  animation.ready.then(t.step_func(function() {
-    assert_equals(animation.playState, 'running');
-    t.done();
-  }));
-}, 'Animation returns correct playState when running');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  var cs = window.getComputedStyle(div);
-  div.style.animation = 'anim 1000s paused';
-
-  var animation = div.getAnimations()[0];
-  assert_equals(animation.playState, 'pending');
-
-  animation.ready.then(t.step_func(function() {
-    assert_equals(animation.playState, 'paused');
-    t.done();
-  }));
-}, 'Animation returns correct playState when paused');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  var cs = window.getComputedStyle(div);
-  div.style.animation = 'anim 1000s';
-
-  var animation = div.getAnimations()[0];
-  animation.pause();
-  assert_equals(animation.playState, 'pending');
-
-  animation.ready.then(t.step_func(function() {
-    assert_equals(animation.playState, 'paused');
-    t.done();
-  }));
-}, 'Animation.playState updates when paused by script');
-
-test(function(t) {
-  var div = addDiv(t);
-  var cs = window.getComputedStyle(div);
-  div.style.animation = 'anim 1000s paused';
-
-  var animation = div.getAnimations()[0];
-  div.style.animationPlayState = 'running';
-  // This test also checks that calling playState flushes style
-  assert_equals(animation.playState, 'pending',
-                'Animation.playState reports pending after updating'
-                + ' animation-play-state (got: ' + animation.playState + ')');
-}, 'Animation.playState updates when resumed by setting style');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim 1000s';
-
-  var animation = div.getAnimations()[0];
-  animation.cancel();
-  assert_equals(animation.playState, 'idle');
-}, 'Animation returns correct playState when cancelled');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim 1000s';
-
-  var animation = div.getAnimations()[0];
-  animation.cancel();
-  animation.currentTime = 50 * 1000;
-  assert_equals(animation.playState, 'paused',
-                'After seeking an idle animation, it is effectively paused');
-}, 'After cancelling an animation, seeking it makes it paused');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_animation-ready.html
+++ /dev/null
@@ -1,251 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-@keyframes abc {
-  to { transform: translate(10px) }
-}
-</style>
-<body>
-<script>
-'use strict';
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'abc 100s';
-  var animation = div.getAnimations()[0];
-
-  var originalReadyPromise = animation.ready;
-  var pauseReadyPromise;
-
-  animation.ready.then(t.step_func(function() {
-    assert_equals(animation.ready, originalReadyPromise,
-                  'Ready promise is the same object when playing completes');
-    animation.pause();
-    assert_not_equals(animation.ready, originalReadyPromise,
-                      'A new ready promise is created when pausing');
-    pauseReadyPromise = animation.ready;
-    // Wait for the promise to fulfill since if we abort the pause the ready
-    // promise object is reused.
-    return animation.ready;
-  })).then(t.step_func(function() {
-    animation.play();
-    assert_not_equals(animation.ready, pauseReadyPromise,
-                      'A new ready promise is created when playing');
-    t.done();
-  }));
-}, 'A new ready promise is created when play()/pause() is called');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'abc 100s paused';
-  var animation = div.getAnimations()[0];
-
-  var originalReadyPromise = animation.ready;
-  animation.ready.then(t.step_func(function() {
-    div.style.animationPlayState = 'running';
-    assert_not_equals(animation.ready, originalReadyPromise,
-                      'After updating animation-play-state a new ready promise'
-                      + ' object is created');
-    t.done();
-  }));
-}, 'A new ready promise is created when setting animation-play-state: running');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'abc 100s';
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(function() {
-    var promiseBeforeCallingPlay = animation.ready;
-    animation.play();
-    assert_equals(animation.ready, promiseBeforeCallingPlay,
-                  'Ready promise has same object identity after redundant call'
-                  + ' to play()');
-    t.done();
-  }));
-}, 'Redundant calls to play() do not generate new ready promise objects');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'abc 100s';
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(function(resolvedAnimation) {
-    assert_equals(resolvedAnimation, animation,
-                  'Object identity of Animation passed to Promise callback'
-                  + ' matches the Animation object owning the Promise');
-    t.done();
-  }));
-}, 'The ready promise is fulfilled with its Animation');
-
-async_test(function(t) {
-  var div = addDiv(t);
-
-  // Set up pending animation
-  div.style.animation = 'abc 100s';
-  var animation = div.getAnimations()[0];
-  assert_equals(animation.playState, 'pending',
-               'Animation is initially pending');
-
-  // Set up listeners on ready promise
-  animation.ready.then(t.step_func(function() {
-    assert_unreached('ready promise is fulfilled');
-  })).catch(t.step_func(function(err) {
-    assert_equals(err.name, 'AbortError',
-                  'ready promise is rejected with AbortError');
-  })).then(t.step_func(function() {
-    t.done();
-  }));
-
-  // Now cancel the animation and flush styles
-  div.style.animation = '';
-  window.getComputedStyle(div).animation;
-
-}, 'ready promise is rejected when an animation is cancelled by resetting'
-   + ' the animation property');
-
-async_test(function(t) {
-  var div = addDiv(t);
-
-  // As before, but this time instead of removing all animations, simply update
-  // the list of animations. At least for Firefox, updating is a different
-  // code path.
-
-  // Set up pending animation
-  div.style.animation = 'abc 100s';
-  var animation = div.getAnimations()[0];
-  assert_equals(animation.playState, 'pending',
-                'Animation is initially pending');
-
-  // Set up listeners on ready promise
-  animation.ready.then(t.step_func(function() {
-    assert_unreached('ready promise was fulfilled');
-  })).catch(t.step_func(function(err) {
-    assert_equals(err.name, 'AbortError',
-                  'ready promise is rejected with AbortError');
-  })).then(t.step_func(function() {
-    t.done();
-  }));
-
-  // Now update the animation and flush styles
-  div.style.animation = 'def 100s';
-  window.getComputedStyle(div).animation;
-
-}, 'ready promise is rejected when an animation is cancelled by updating'
-   + ' the animation property');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'abc 100s';
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(function() {
-    assert_unreached('ready promise was fulfilled');
-  })).catch(t.step_func(function(err) {
-    assert_equals(err.name, 'AbortError',
-                  'ready promise is rejected with AbortError');
-  })).then(t.step_func(function() {
-    t.done();
-  }));
-
-  animation.cancel();
-}, 'ready promise is rejected when a play-pending animation is cancelled by'
-   + ' calling cancel()');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'abc 100s';
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(function() {
-    animation.pause();
-
-    // Set up listeners on pause-pending ready promise
-    animation.ready.then(t.step_func(function() {
-      assert_unreached('ready promise was fulfilled');
-    })).catch(t.step_func(function(err) {
-      assert_equals(err.name, 'AbortError',
-                    'ready promise is rejected with AbortError');
-    })).then(t.step_func(function() {
-      t.done();
-    }));
-
-    animation.cancel();
-  }));
-}, 'ready promise is rejected when a pause-pending animation is cancelled by'
-   + ' calling cancel()');
-
-async_test(function(t) {
-  var div = addDiv(t, { style: 'animation: abc 100s' });
-  var animation = div.getAnimations()[0];
-
-  var originalReadyPromise = animation.ready;
-  animation.ready.then(t.step_func(function() {
-    div.style.animationPlayState = 'paused';
-    assert_not_equals(animation.ready, originalReadyPromise,
-                      'A new Promise object is generated when setting'
-                      + ' animation-play-state: paused');
-    t.done();
-  }));
-}, 'A new ready promise is created when setting animation-play-state: paused');
-
-async_test(function(t) {
-  var div = addDiv(t, { style: 'animation: abc 100s' });
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(function() {
-    div.style.animationPlayState = 'paused';
-    var firstReadyPromise = animation.ready;
-    animation.pause();
-    assert_equals(animation.ready, firstReadyPromise,
-                  'Ready promise objects are identical after redundant pause');
-    t.done();
-  }));
-}, 'Pausing twice re-uses the same Promise');
-
-async_test(function(t) {
-  var div = addDiv(t, { style: 'animation: abc 100s' });
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(function() {
-    div.style.animationPlayState = 'paused';
-
-    // Flush style and verify we're pending at the same time
-    assert_equals(animation.playState, 'pending', 'Animation is pending');
-    var pauseReadyPromise = animation.ready;
-
-    // Now play again immediately
-    div.style.animationPlayState = 'running';
-    assert_equals(animation.playState, 'pending', 'Animation is still pending');
-    assert_equals(animation.ready, pauseReadyPromise,
-                  'The pause Promise is re-used when playing while waiting'
-                  + ' to pause');
-
-    return animation.ready;
-  })).then(t.step_func(function() {
-    assert_equals(animation.playState, 'running',
-                  'Animation is running after aborting a pause');
-    t.done();
-  }));
-}, 'If a pause operation is interrupted, the ready promise is reused');
-
-async_test(function(t) {
-  var div = addDiv(t, { style: 'animation: abc 100s' });
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(function() {
-    div.style.animationPlayState = 'paused';
-    return animation.ready;
-  })).then(t.step_func(function(resolvedAnimation) {
-    assert_equals(resolvedAnimation, animation,
-                  'Promise received when ready Promise for a pause operation'
-                  + ' is completed is the animation on which the pause was'
-                  + ' performed');
-    t.done();
-  }));
-}, 'When a pause is complete the Promise callback gets the correct animation');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_animation-starttime.html
+++ /dev/null
@@ -1,557 +0,0 @@
-<!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: add equivalent tests without an animation-delay, but first we need to
-// change the timing of animationstart dispatch. (Right now the animationstart
-// event will fire before the ready Promise is resolved if there is no
-// animation-delay.)
-// See https://bugzilla.mozilla.org/show_bug.cgi?id=1134163
-
-// 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'];
-const ANIM_DELAY_MS = 1000000; // 1000s
-const ANIM_DUR_MS = 1000000; // 1000s
-const ANIM_PROPERTY_VAL = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
-
-/**
- * These helpers get the value that the startTime 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 startTimeForBeforePhase(timeline) {
-  return timeline.currentTime - ANIM_DELAY_MS / 2;
-}
-function startTimeForActivePhase(timeline) {
-  return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS / 2;
-}
-function startTimeForAfterPhase(timeline) {
-  return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS - ANIM_DELAY_MS / 2;
-}
-function startTimeForStartOfActiveInterval(timeline) {
-  return timeline.currentTime - ANIM_DELAY_MS;
-}
-function startTimeForFiftyPercentThroughActiveInterval(timeline) {
-  return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.5;
-}
-function startTimeForEndOfActiveInterval(timeline) {
-  return timeline.currentTime - 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 UNANIMATED_POSITION = 10;
-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:
-//
-//   https://w3c.github.io/web-animations/#animation-effect-phases-and-states
-//
-// Note the distinction between the "animation start time" which occurs before
-// the start delay and the start of the active interval which occurs after it.
-
-// Called when the ready Promise's callbacks should happen
-function checkStateOnReadyPromiseResolved(animation)
-{
-  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');
-
-  assert_equals(animation.playState, 'running',
-    'Animation.playState should be "running" on the first paint ' +
-    'tick after animation creation');
-
-  assert_equals(animation.effect.target.style.animationPlayState, 'running',
-    'Animation.effect.target.style.animationPlayState 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, UNANIMATED_POSITION,
-                'the computed value of margin-left should be unaffected ' +
-                'by an animation with a delay on ready Promise resolve');
-}
-
-// Called when startTime is set to the time the active interval starts.
-function checkStateAtActiveIntervalStartTime(animation)
-{
-  // We don't test animation.startTime since our caller just set it.
-
-  assert_equals(animation.playState, 'running',
-    'Animation.playState should be "running" at the start of ' +
-    'the active interval');
-
-  assert_equals(animation.effect.target.style.animationPlayState, 'running',
-    'Animation.effect.target.style.animationPlayState 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.startTime 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 startTime is set to the time the active interval ends.
-function checkStateAtActiveIntervalEndTime(animation)
-{
-  // We don't test animation.startTime since our caller just set it.
-
-  assert_equals(animation.playState, 'finished',
-    'Animation.playState should be "finished" at the end of ' +
-    'the active interval');
-
-  assert_equals(animation.effect.target.style.animationPlayState, "running",
-    'Animation.effect.target.style.animationPlayState should be ' +
-    '"finished" at the end of the active interval');
-
-  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 ' +
-    'by the animation at the end of the active duration when the ' +
-    'animation-fill-mode is none');
-}
-
-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');
-
-async_test(function(t)
-{
-  var div = addDiv(t, { 'style': 'animation: anim 100s' });
-  var animation = div.getAnimations()[0];
-  animation.ready.then(t.step_func(function() {
-    assert_true(animation.startTime > 0,
-                'startTime is resolved when running');
-    t.done();
-  }));
-}, 'startTime is resolved when running');
-
-async_test(function(t)
-{
-  var div = addDiv(t, { 'style': 'animation: anim 100s paused' });
-  var animation = div.getAnimations()[0];
-  animation.ready.then(t.step_func(function() {
-    assert_equals(animation.startTime, null,
-                  'startTime is unresolved when paused');
-    t.done();
-  }));
-}, 'startTime is unresolved when paused');
-
-async_test(function(t)
-{
-  var div = addDiv(t, { 'style': 'animation: anim 100s' });
-  var animation = div.getAnimations()[0];
-  animation.ready.then(t.step_func(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');
-    t.done();
-  }));
-}, 'startTime while pause-pending and play-pending');
-
-async_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
-  // FIXME: Once we implement finish(), use that here.
-  animation.currentTime = 100 * 1000;
-  animation.ready.then(t.step_func(function() {
-    // Call play() which puts us back in the running state
-    animation.play();
-    // FIXME: Enable this once we implement finishing behavior (bug 1074630)
-    /*
-    assert_equals(animation.startTime, null, 'startTime is unresolved');
-    */
-    t.done();
-  }));
-}, 'startTime while play-pending from finished state');
-
-async_test(function(t) {
-  var div = addDiv(t, { style: 'animation: anim 1000s' });
-  var animation = div.getAnimations()[0];
-
-  assert_equals(animation.startTime, null, 'The initial startTime is null');
-  var initialTimelineTime = document.timeline.currentTime;
-
-  animation.ready.then(t.step_func(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(t.step_func(function() {
-    assert_equals(animation.startTime, null,
-                  'After actually pausing, the startTime of an animation ' +
-                  'is null');
-    t.done();
-  }));
-}, 'Pausing should make the startTime become null');
-
-test(function(t)
-{
-  var div = addDiv(t, {'class': 'animated-div'});
-  div.style.animation = ANIM_PROPERTY_VAL;
-
-  var animation = div.getAnimations()[0];
-  var currentTime = animation.timeline.currentTime;
-  animation.startTime = currentTime;
-  assert_approx_equals(animation.startTime, currentTime, 0.0001, // rounding error
-    'Check setting of startTime actually works');
-}, 'Sanity test to check round-tripping assigning to a new animation\'s ' +
-   'startTime');
-
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-
-  div.style.animation = ANIM_PROPERTY_VAL;
-
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(function() {
-    checkStateOnReadyPromiseResolved(animation);
-
-    animation.startTime = startTimeForStartOfActiveInterval(animation.timeline);
-    return eventWatcher.wait_for('animationstart');
-  })).then(t.step_func(function() {
-    checkStateAtActiveIntervalStartTime(animation);
-
-    animation.startTime =
-      startTimeForFiftyPercentThroughActiveInterval(animation.timeline);
-    checkStateAtFiftyPctOfActiveInterval(animation);
-
-    animation.startTime = startTimeForEndOfActiveInterval(animation.timeline);
-    return eventWatcher.wait_for('animationend');
-  })).then(t.step_func(function() {
-    checkStateAtActiveIntervalEndTime(animation);
-  })).catch(t.step_func(function(reason) {
-    assert_unreached(reason);
-  })).then(function() {
-    t.done();
-  });
-}, 'Skipping forward through animation');
-
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-
-  div.style.animation = ANIM_PROPERTY_VAL;
-
-  var animation = div.getAnimations()[0];
-
-  animation.startTime = startTimeForEndOfActiveInterval(animation.timeline);
-
-  var previousTimelineTime = animation.timeline.currentTime;
-
-  // Skipping over the active interval will dispatch an 'animationstart' then
-  // an 'animationend' event. We need to wait for these events before we start
-  // testing going backwards since EventWatcher will fail the test if it gets
-  // an event that we haven't told it about.
-  eventWatcher.wait_for(['animationstart',
-                         'animationend']).then(t.step_func(function() {
-    assert_true(document.timeline.currentTime - previousTimelineTime <
-                  ANIM_DUR_MS,
-                'Sanity check that seeking worked rather than the events ' +
-                'firing after normal playback through the very long ' +
-                'animation duration');
-
-    // Now we can start the tests for skipping backwards, but first we check
-    // that after the events we're still in the same end time state:
-    checkStateAtActiveIntervalEndTime(animation);
-
-    animation.startTime =
-      startTimeForFiftyPercentThroughActiveInterval(animation.timeline);
-
-    // 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.
-    //
-    // Calling checkStateAtFiftyPctOfActiveInterval will check computed style,
-    // causing computed style to be updated and the 'animationstart' event to
-    // be dispatched synchronously. We need to call wait_for first
-    // otherwise eventWatcher will assert that the event was unexpected.
-    var promise = eventWatcher.wait_for('animationstart');
-    checkStateAtFiftyPctOfActiveInterval(animation);
-    return promise;
-  })).then(t.step_func(function() {
-    animation.startTime = startTimeForStartOfActiveInterval(animation.timeline);
-    checkStateAtActiveIntervalStartTime(animation);
-
-    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(t.step_func(function() {
-    checkStateOnReadyPromiseResolved(animation);
-  })).catch(t.step_func(function(reason) {
-    assert_unreached(reason);
-  })).then(function() {
-    t.done();
-  });
-
-  // This must come after we've set up the Promise chain, since requesting
-  // computed style will force events to be dispatched.
-  // XXX For some reason this fails occasionally (either the animation.playState
-  // check or the marginLeft check).
-  //checkStateAtActiveIntervalEndTime(animation);
-}, '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.
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-  div.style.animation = ANIM_PROPERTY_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.startTime = startTimeForActivePhase(animation.timeline);
-  animation.startTime = startTimeForBeforePhase(animation.timeline);
-
-  waitForAnimationFrames(2).then(function() {
-    t.done();
-  });
-}, 'Redundant change, before -> active, then back');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-  div.style.animation = ANIM_PROPERTY_VAL;
-  var animation = div.getAnimations()[0];
-
-  animation.startTime = startTimeForAfterPhase(animation.timeline);
-  animation.startTime = startTimeForBeforePhase(animation.timeline);
-
-  waitForAnimationFrames(2).then(function() {
-    t.done();
-  });
-}, 'Redundant change, before -> after, then back');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-  div.style.animation = ANIM_PROPERTY_VAL;
-  var animation = div.getAnimations()[0];
-
-  eventWatcher.wait_for('animationstart').then(function() {
-    animation.startTime = startTimeForBeforePhase(animation.timeline);
-    animation.startTime = startTimeForActivePhase(animation.timeline);
-
-    waitForAnimationFrames(2).then(function() {
-      t.done();
-    });
-  });
-  // get us into the initial state:
-  animation.startTime = startTimeForActivePhase(animation.timeline);
-}, 'Redundant change, active -> before, then back');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-  div.style.animation = ANIM_PROPERTY_VAL;
-  var animation = div.getAnimations()[0];
-
-  eventWatcher.wait_for('animationstart').then(function() {
-    animation.startTime = startTimeForAfterPhase(animation.timeline);
-    animation.startTime = startTimeForActivePhase(animation.timeline);
-
-    waitForAnimationFrames(2).then(function() {
-      t.done();
-    });
-  });
-  // get us into the initial state:
-  animation.startTime = startTimeForActivePhase(animation.timeline);
-}, 'Redundant change, active -> after, then back');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-  div.style.animation = ANIM_PROPERTY_VAL;
-  var animation = div.getAnimations()[0];
-
-  eventWatcher.wait_for(['animationstart',
-                         'animationend']).then(function() {
-    animation.startTime = startTimeForBeforePhase(animation.timeline);
-    animation.startTime = startTimeForAfterPhase(animation.timeline);
-
-    waitForAnimationFrames(2).then(function() {
-      t.done();
-    });
-  });
-  // get us into the initial state:
-  animation.startTime = startTimeForAfterPhase(animation.timeline);
-}, 'Redundant change, after -> before, then back');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
-  div.style.animation = ANIM_PROPERTY_VAL;
-  var animation = div.getAnimations()[0];
-
-  eventWatcher.wait_for(['animationstart',
-                         'animationend']).then(function() {
-    animation.startTime = startTimeForActivePhase(animation.timeline);
-    animation.startTime = startTimeForAfterPhase(animation.timeline);
-
-    waitForAnimationFrames(2).then(function() {
-      t.done();
-    });
-  });
-  // get us into the initial state:
-  animation.startTime = startTimeForAfterPhase(animation.timeline);
-}, 'Redundant change, after -> active, then back');
-
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  div.style.animation = ANIM_PROPERTY_VAL;
-
-  var animation = div.getAnimations()[0];
-
-  var storedCurrentTime;
-
-  animation.ready.then(t.step_func(function() {
-    storedCurrentTime = animation.currentTime;
-    animation.startTime = null;
-    return animation.ready;
-  })).catch(t.step_func(function(reason) {
-    assert_unreached(reason);
-  })).then(t.step_func(function() {
-    assert_equals(animation.currentTime, storedCurrentTime,
-      'Test that hold time is correct');
-    t.done();
-  }));
-}, 'Setting startTime to null');
-
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  div.style.animation = 'anim 100s';
-
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(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(t.step_func(function() {
-    assert_equals(animation.startTime, null,
-      'Animation.startTime is null after paused');
-    assert_equals(animation.playState, 'paused',
-      'Animation.playState is "paused" after pause() call');
-  })).catch(t.step_func(function(reason) {
-    assert_unreached(reason);
-  })).then(function() {
-    t.done();
-  });
-}, 'Animation.startTime after pausing');
-
-async_test(function(t) {
-  var div = addDiv(t, {'class': 'animated-div'});
-  div.style.animation = 'anim 100s';
-
-  var animation = div.getAnimations()[0];
-  animation.ready.then(t.step_func(function() {
-    animation.cancel();
-    assert_equals(animation.startTime, null,
-                  'The startTime of a cancelled animation should be null');
-    t.done();
-  }));
-}, 'Animation.startTime after cancelling');
-
-done();
-    </script>
-  </body>
-</html>
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_animations-dynamic-changes.html
+++ /dev/null
@@ -1,159 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-@keyframes anim1 {
-  to { left: 100px }
-}
-@keyframes anim2 { }
-</style>
-<body>
-<script>
-'use strict';
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim1 100s';
-
-  var originalAnimation = div.getAnimations()[0];
-  var originalStartTime;
-  var originalCurrentTime;
-
-  // Wait a moment so we can confirm the startTime doesn't change (and doesn't
-  // simply reflect the current time).
-  originalAnimation.ready.then(function() {
-    originalStartTime = originalAnimation.startTime;
-    originalCurrentTime = originalAnimation.currentTime;
-
-    // Wait a moment so we can confirm the startTime doesn't change (and
-    // doesn't simply reflect the current time).
-    return waitForFrame();
-  }).then(t.step_func(function() {
-    div.style.animationDuration = '200s';
-    var animation = div.getAnimations()[0];
-    assert_equals(animation, originalAnimation,
-                  'The same Animation is returned after updating'
-                  + ' animation duration');
-    assert_equals(animation.startTime, originalStartTime,
-                  'Animations returned by getAnimations preserve'
-                  + ' their startTime even when they are updated');
-    // Sanity check
-    assert_not_equals(animation.currentTime, originalCurrentTime,
-                      'Animation.currentTime has updated in next'
-                      + ' requestAnimationFrame callback');
-    t.done();
-  }));
-}, 'Animations preserve their startTime when changed');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim1 100s, anim1 100s';
-
-  // Store original state
-  var animations = div.getAnimations();
-  var animation1 = animations[0];
-  var animation2 = animations[1];
-
-  // Update first in list
-  div.style.animationDuration = '200s, 100s';
-  animations = div.getAnimations();
-  assert_equals(animations[0], animation1,
-                'First Animation is in same position after update');
-  assert_equals(animations[1], animation2,
-                'Second Animation is in same position after update');
-}, 'Updated Animations maintain their order in the list');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim1 200s, anim1 100s';
-
-  // Store original state
-  var animations = div.getAnimations();
-  var animation1 = animations[0];
-  var animation2 = animations[1];
-
-  // Wait before continuing so we can compare start times (otherwise the
-  // new Animation objects and existing Animation objects will all have the same
-  // start time).
-  waitForAllAnimations(animations).then(waitForFrame).then(t.step_func(function() {
-    // Swap duration of first and second in list and prepend animation at the
-    // same time
-    div.style.animation = 'anim1 100s, anim1 100s, anim1 200s';
-    animations = div.getAnimations();
-    assert_true(animations[0] !== animation1 && animations[0] !== animation2,
-                'New Animation is prepended to start of list');
-    assert_equals(animations[1], animation1,
-                  'First Animation is in second position after update');
-    assert_equals(animations[2], animation2,
-                  'Second Animation is in third position after update');
-    assert_equals(animations[1].startTime, animations[2].startTime,
-                  'Old Animations have the same start time');
-    // TODO: Check that animations[0].startTime === null
-    return animations[0].ready;
-  })).then(t.step_func(function() {
-    assert_true(animations[0].startTime > animations[1].startTime,
-                'New Animation has later start time');
-    t.done();
-  }));
-}, 'Only the startTimes of existing animations are preserved');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim1 100s, anim1 100s';
-  var secondAnimation = div.getAnimations()[1];
-
-  // Wait before continuing so we can compare start times
-  secondAnimation.ready.then(waitForFrame).then(t.step_func(function() {
-    // Trim list of animations
-    div.style.animationName = 'anim1';
-    var animations = div.getAnimations();
-    assert_equals(animations.length, 1, 'List of Animations was trimmed');
-    assert_equals(animations[0], secondAnimation,
-                  'Remaining Animation is the second one in the list');
-    assert_equals(typeof(animations[0].startTime), 'number',
-                  'Remaining Animation has resolved startTime');
-    assert_true(animations[0].startTime < animations[0].timeline.currentTime,
-                'Remaining Animation preserves startTime');
-    t.done();
-  }));
-}, 'Animations are removed from the start of the list while preserving'
-   + ' the state of existing Animations');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim1 100s';
-  var firstAddedAnimation = div.getAnimations()[0],
-      secondAddedAnimation,
-      animations;
-
-  // Wait and add second Animation
-  firstAddedAnimation.ready.then(waitForFrame).then(t.step_func(function() {
-    div.style.animation = 'anim1 100s, anim1 100s';
-    secondAddedAnimation = div.getAnimations()[0];
-
-    // Wait again and add another Animation
-    return secondAddedAnimation.ready.then(waitForFrame);
-  })).then(t.step_func(function() {
-    div.style.animation = 'anim1 100s, anim2 100s, anim1 100s';
-    animations = div.getAnimations();
-    assert_not_equals(firstAddedAnimation, secondAddedAnimation,
-                      'New Animations are added to start of the list');
-    assert_equals(animations[0], secondAddedAnimation,
-                  'Second Animation remains in same position after'
-                  + ' interleaving');
-    assert_equals(animations[2], firstAddedAnimation,
-                  'First Animation remains in same position after'
-                  + ' interleaving');
-    return animations[1].ready;
-  })).then(t.step_func(function() {
-    assert_true(animations[1].startTime > animations[0].startTime,
-                'Interleaved animation starts later than existing animations');
-    assert_true(animations[0].startTime > animations[2].startTime,
-                'Original animations retain their start time');
-    t.done();
-  }));
-}, 'Animation state is preserved when interleaving animations in list');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_effect-name.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-@keyframes xyz {
-  to { left: 100px }
-}
-</style>
-<body>
-<script>
-'use strict';
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'xyz 100s';
-  assert_equals(div.getAnimations()[0].effect.name, 'xyz',
-                'Animation effect name matches keyframes rule name');
-}, 'Effect name makes keyframe rule');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'x\\yz 100s';
-  assert_equals(div.getAnimations()[0].effect.name, 'xyz',
-                'Escaped animation effect name matches keyframes rule name');
-}, 'Escaped animation name');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'x\\79 z 100s';
-  assert_equals(div.getAnimations()[0].effect.name, 'xyz',
-                'Hex-escaped animation name matches keyframes rule'
-                + ' name');
-}, 'Animation name with hex-escape');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_effect-target.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-@keyframes anim { }
-</style>
-<body>
-<script>
-'use strict';
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim 100s';
-  var animation = div.getAnimations()[0];
-  assert_equals(animation.effect.target, div,
-    'Animation.target is the animatable div');
-}, 'Returned CSS animations have the correct Animation.target');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_element-get-animations.html
+++ /dev/null
@@ -1,272 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-@keyframes anim1 {
-  to { left: 100px }
-}
-@keyframes anim2 {
-  to { top: 100px }
-}
-@keyframes multiPropAnim {
-  to { background: green, opacity: 0.5, left: 100px, top: 100px }
-}
-@keyframes empty { }
-</style>
-<body>
-<script>
-'use strict';
-
-test(function(t) {
-  var div = addDiv(t);
-  assert_equals(div.getAnimations().length, 0,
-    'getAnimations returns an empty sequence for an element'
-    + ' with no animations');
-}, 'getAnimations for non-animated content');
-
-async_test(function(t) {
-  var div = addDiv(t);
-
-  // Add an animation
-  div.style.animation = 'anim1 100s';
-  var animations = div.getAnimations();
-  assert_equals(animations.length, 1,
-    'getAnimations returns an Animation running CSS Animations');
-  animations[0].ready.then(t.step_func(function() {
-    var startTime = animations[0].startTime;
-    assert_true(startTime > 0 && startTime <= document.timeline.currentTime,
-      'CSS animation has a sensible start time');
-
-    // Wait a moment then add a second animation.
-    //
-    // We wait for the next frame so that we can test that the start times of
-    // the animations differ.
-    return waitForFrame();
-  })).then(t.step_func(function() {
-    div.style.animation = 'anim1 100s, anim2 100s';
-    animations = div.getAnimations();
-    assert_equals(animations.length, 2,
-      'getAnimations returns one Animation for each value of'
-      + ' animation-name');
-    // Wait until both Animations are ready
-    // (We don't make any assumptions about the order of the Animations since
-    //  that is the purpose of the following test.)
-    return waitForAllAnimations(animations);
-  })).then(t.step_func(function() {
-    assert_true(animations[0].startTime < animations[1].startTime,
-      'Additional Animations for CSS animations start after the original'
-      + ' animation and appear later in the list');
-    t.done();
-  }));
-}, 'getAnimations for CSS Animations');
-
-test(function(t) {
-  var div = addDiv(t);
-
-  // Add an animation that targets multiple properties
-  div.style.animation = 'multiPropAnim 100s';
-  assert_equals(div.getAnimations().length, 1,
-    'getAnimations returns only one Animation for a CSS Animation'
-    + ' that targets multiple properties');
-}, 'getAnimations for multi-property animations');
-
-async_test(function(t) {
-  var div = addDiv(t);
-
-  // Add an animation
-  div.style.backgroundColor = 'red';
-  div.style.animation = 'anim1 100s';
-  window.getComputedStyle(div).backgroundColor;
-
-  // Wait until a frame after the animation starts, then add a transition
-  var animations = div.getAnimations();
-  animations[0].ready.then(waitForFrame).then(t.step_func(function() {
-    div.style.transition = 'all 100s';
-    div.style.backgroundColor = 'green';
-
-    animations = div.getAnimations();
-    assert_equals(animations.length, 2,
-      'getAnimations returns Animations for both animations and'
-      + ' transitions that run simultaneously');
-    return waitForAllAnimations(animations);
-  })).then(t.step_func(function() {
-    assert_true(animations[0].startTime > animations[1].startTime,
-      'Animations for transitions appear before animations even if they'
-      + ' start later');
-    t.done();
-  }));
-}, 'getAnimations for both CSS Animations and Transitions at once');
-
-async_test(function(t) {
-  var div = addDiv(t);
-
-  // Set up event listener
-  div.addEventListener('animationend', t.step_func(function() {
-    assert_equals(div.getAnimations().length, 0,
-      'getAnimations does not return Animations for finished '
-      + ' (and non-forwards-filling) CSS Animations');
-    t.done();
-  }));
-
-  // Add a very short animation
-  div.style.animation = 'anim1 0.01s';
-}, 'getAnimations for CSS Animations that have finished');
-
-async_test(function(t) {
-  var div = addDiv(t);
-
-  // Set up event listener
-  div.addEventListener('animationend', t.step_func(function() {
-    assert_equals(div.getAnimations().length, 1,
-      'getAnimations returns Animations for CSS Animations that have'
-      + ' finished but are filling forwards');
-    t.done();
-  }));
-
-  // Add a very short animation
-  div.style.animation = 'anim1 0.01s forwards';
-}, 'getAnimations for CSS Animations that have finished but are'
-   + ' forwards filling');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'none 100s';
-
-  var animations = div.getAnimations();
-  assert_equals(animations.length, 0,
-    'getAnimations returns an empty sequence for an element'
-    + ' with animation-name: none');
-
-  div.style.animation = 'none 100s, anim1 100s';
-  animations = div.getAnimations();
-  assert_equals(animations.length, 1,
-    'getAnimations returns Animations only for those CSS Animations whose'
-    + ' animation-name is not none');
-}, 'getAnimations for CSS Animations with animation-name: none');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'missing 100s';
-  var animations = div.getAnimations();
-  assert_equals(animations.length, 0,
-    'getAnimations returns an empty sequence for an element'
-    + ' with animation-name: missing');
-
-  div.style.animation = 'anim1 100s, missing 100s';
-  animations = div.getAnimations();
-  assert_equals(animations.length, 1,
-    'getAnimations returns Animations only for those CSS Animations whose'
-    + ' animation-name is found');
-}, 'getAnimations for CSS Animations with animation-name: missing');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim1 100s, notyet 100s';
-  var animations = div.getAnimations();
-  assert_equals(animations.length, 1,
-    'getAnimations initally only returns Animations for CSS Animations whose'
-    + ' animation-name is found');
-
-  animations[0].ready.then(waitForFrame).then(t.step_func(function() {
-    var keyframes = '@keyframes notyet { to { left: 100px; } }';
-    document.styleSheets[0].insertRule(keyframes, 0);
-    animations = div.getAnimations();
-    assert_equals(animations.length, 2,
-      'getAnimations includes Animation when @keyframes rule is added'
-      + ' later');
-    return waitForAllAnimations(animations);
-  })).then(t.step_func(function() {
-    assert_true(animations[0].startTime < animations[1].startTime,
-      'Newly added animation has a later start time');
-    document.styleSheets[0].deleteRule(0);
-    t.done();
-  }));
-}, 'getAnimations for CSS Animations where the @keyframes rule is added'
-   + ' later');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim1 100s, anim1 100s';
-  assert_equals(div.getAnimations().length, 2,
-    'getAnimations returns one Animation for each CSS animation-name'
-    + ' even if the names are duplicated');
-}, 'getAnimations for CSS Animations with duplicated animation-name');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'empty 100s';
-  assert_equals(div.getAnimations().length, 1,
-    'getAnimations returns Animations for CSS animations with an'
-    + ' empty keyframes rule');
-}, 'getAnimations for CSS Animations with empty keyframes rule');
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim1 100s 100s';
-  var animations = div.getAnimations();
-  assert_equals(animations.length, 1,
-    'getAnimations returns animations for CSS animations whose'
-    + ' delay makes them start later');
-  animations[0].ready.then(waitForFrame).then(t.step_func(function() {
-    assert_true(animations[0].startTime <= document.timeline.currentTime,
-      'For CSS Animations in delay phase, the start time of the Animation is'
-      + ' not in the future');
-    t.done();
-  }));
-}, 'getAnimations for CSS animations in delay phase');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim1 0s 100s';
-  assert_equals(div.getAnimations().length, 1,
-    'getAnimations returns animations for CSS animations whose'
-    + ' duration is zero');
-  div.remove();
-}, 'getAnimations for zero-duration CSS Animations');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim1 100s';
-  var originalAnimation = div.getAnimations()[0];
-
-  // Update pause state (an Animation change)
-  div.style.animationPlayState = 'paused';
-  var pendingAnimation = div.getAnimations()[0];
-  assert_equals(pendingAnimation.playState, 'pending',
-                'animation\'s play state is updated');
-  assert_equals(originalAnimation, pendingAnimation,
-                'getAnimations returns the same objects even when their'
-                + ' play state changes');
-
-  // Update duration (an Animation change)
-  div.style.animationDuration = '200s';
-  var extendedAnimation = div.getAnimations()[0];
-  // FIXME: Check extendedAnimation.effect.timing.duration has changed once the
-  // API is available
-  assert_equals(originalAnimation, extendedAnimation,
-                'getAnimations returns the same objects even when their'
-                + ' duration changes');
-}, 'getAnimations returns objects with the same identity');
-
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim1 100s';
-
-  assert_equals(div.getAnimations().length, 1,
-    'getAnimations returns an animation before cancelling');
-
-  var animation = div.getAnimations()[0];
-
-  animation.cancel();
-  assert_equals(div.getAnimations().length, 0,
-    'getAnimations does not return cancelled animations');
-
-  animation.play();
-  assert_equals(div.getAnimations().length, 1,
-    'getAnimations returns cancelled animations that have been re-started');
-
-}, 'getAnimations for CSS Animations that are cancelled');
-
-done();
-</script>
-</body>
--- a/dom/animation/test/css-animations/test_animation-cancel.html
+++ b/dom/animation/test/css-animations/test_animation-cancel.html
@@ -1,15 +1,164 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
 <div id="log"></div>
+<style>
+@keyframes translateAnim {
+  to { transform: translate(100px) }
+}
+@keyframes marginLeftAnim {
+  to { margin-left: 100px }
+}
+@keyframes marginLeftAnim100To200 {
+  from { margin-left: 100px }
+  to { margin-left: 200px }
+}
+</style>
 <script>
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animation-cancel.html");
-  });
+
+async_test(function(t) {
+  var div = addDiv(t, { style: 'animation: translateAnim 100s' });
+
+  var animation = div.getAnimations()[0];
+  animation.ready.then(t.step_func(function() {
+    assert_not_equals(getComputedStyle(div).transform, 'none',
+                      'transform style is animated before cancelling');
+    animation.cancel();
+    assert_equals(getComputedStyle(div).transform, 'none',
+                  'transform style is no longer animated after cancelling');
+    t.done();
+  }));
+}, 'Animated style is cleared after cancelling a running CSS animation');
+
+async_test(function(t) {
+  var div = addDiv(t, { style: 'animation: translateAnim 100s forwards' });
+
+  var animation = div.getAnimations()[0];
+  animation.finish();
+
+  animation.ready.then(t.step_func(function() {
+    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');
+    t.done();
+  }));
+}, 'Animated style is cleared after cancelling a filling CSS animation');
+
+async_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');
+  }));
+
+  animation.ready.then(t.step_func(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);
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+}, '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');
+
+async_test(function(t) {
+  var div =
+    addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
+
+  var animation = div.getAnimations()[0];
+  animation.ready.then(t.step_func(function() {
+    animation.cancel();
+    assert_equals(getComputedStyle(div).marginLeft, '0px',
+                  'margin-left style is not animated after cancelling');
+    animation.play();
+    assert_equals(getComputedStyle(div).marginLeft, '100px',
+                  'margin-left style is animated after re-starting animation');
+    return animation.ready;
+  })).then(t.step_func(function() {
+    assert_equals(animation.playState, 'running',
+                  'Animation succeeds in running after being re-started');
+    t.done();
+  }));
+}, 'After cancelling an animation, it can still be re-used');
+
+test(function(t) {
+  var div =
+    addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
+
+  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');
+
+test(function(t) {
+  var div =
+    addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
+
+  var animation = div.getAnimations()[0];
+  animation.cancel();
+  assert_equals(getComputedStyle(div).marginLeft, '0px',
+                'margin-left style is not animated after cancelling');
+
+  // Make some changes to animation-play-state and check that the
+  // animation doesn't become live again. This is because it should be
+  // possible to cancel an animation from script such that all future
+  // changes to style are ignored.
+
+  // Redundant change
+  div.style.animationPlayState = 'running';
+  assert_equals(animation.playState, 'idle',
+                'Animation is still idle after a redundant change to'
+                + ' animation-play-state');
+
+  // Pause
+  div.style.animationPlayState = 'paused';
+  assert_equals(animation.playState, 'idle',
+                'Animation is still idle after setting'
+                + ' animation-play-state: paused');
+
+  // Play
+  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');
+
 </script>
 </html>
--- a/dom/animation/test/css-animations/test_animation-currenttime.html
+++ b/dom/animation/test/css-animations/test_animation-currenttime.html
@@ -1,15 +1,550 @@
 <!doctype html>
-<meta charset=utf-8>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id="log"></div>
-<script>
+<html>
+  <head>
+    <meta charset=utf-8>
+    <title>Tests for the effect of setting a CSS animation's
+           Animation.currentTime</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="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="../testcommon.js"></script>
+  </head>
+  <body>
+    <div id="log"></div>
+    <script type="text/javascript">
+
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animation-currenttime.html");
+
+// TODO: add equivalent tests without an animation-delay, but first we need to
+// change the timing of animationstart dispatch. (Right now the animationstart
+// event will fire before the ready Promise is resolved if there is no
+// animation-delay.)
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=1134163
+
+// 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'];
+const ANIM_DELAY_MS = 1000000; // 1000s
+const ANIM_DUR_MS = 1000000; // 1000s
+const ANIM_PROPERTY_VAL = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
+
+/**
+ * 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(timeline) {
+  return ANIM_DELAY_MS / 2;
+}
+function currentTimeForActivePhase(timeline) {
+  return ANIM_DELAY_MS + ANIM_DUR_MS / 2;
+}
+function currentTimeForAfterPhase(timeline) {
+  return ANIM_DELAY_MS + ANIM_DUR_MS + ANIM_DELAY_MS / 2;
+}
+function currentTimeForStartOfActiveInterval(timeline) {
+  return ANIM_DELAY_MS;
+}
+function currentTimeForFiftyPercentThroughActiveInterval(timeline) {
+  return ANIM_DELAY_MS + ANIM_DUR_MS * 0.5;
+}
+function currentTimeForEndOfActiveInterval(timeline) {
+  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 UNANIMATED_POSITION = 10;
+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:
+//
+//   https://w3c.github.io/web-animations/#animation-effect-phases-and-states
+//
+// Note the distinction between the "animation start time" which occurs before
+// the start delay and the start of the active interval which occurs after it.
+
+// 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');
+
+  assert_equals(animation.effect.target.style.animationPlayState, 'running',
+    'Animation.effect.target.style.animationPlayState 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, UNANIMATED_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');
+
+  assert_equals(animation.effect.target.style.animationPlayState, 'running',
+    'Animation.effect.target.style.animationPlayState 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');
+
+  assert_equals(animation.effect.target.style.animationPlayState, "running",
+    'Animation.effect.target.style.animationPlayState should be ' +
+    '"finished" at the end of the active interval');
+
+  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 ' +
+    'by the animation at the end of the active duration when the ' +
+    'animation-fill-mode is none');
+}
+
+
+test(function(t)
+{
+  var div = addDiv(t, {'class': 'animated-div'});
+
+  div.style.animation = ANIM_PROPERTY_VAL;
+
+  var animation = div.getAnimations()[0];
+
+  // Animations shouldn't start until the next paint tick, so:
+  assert_equals(animation.currentTime, 0,
+    'Animation.currentTime should be zero when an animation ' +
+    'is initially created');
+
+  assert_equals(animation.playState, "pending",
+    'Animation.playState should be "pending" when an animation ' +
+    'is initially created');
+
+  assert_equals(animation.effect.target.style.animationPlayState, 'running',
+    'Animation.effect.target.style.animationPlayState should be ' +
+    '"running" when an animation is initially created');
+
+  // XXX Ideally we would have a test to check the ready Promise is initially
+  // unresolved, but currently there is no Web API to do that. Waiting for the
+  // ready Promise with a timeout doesn't work because the resolved callback
+  // will be called (async) regardless of whether the Promise was resolved in
+  // the past or is resolved in the future.
+
+  // So that animation is running instead of paused when we set currentTime:
+  animation.startTime = animation.timeline.currentTime;
+
+  assert_approx_equals(animation.currentTime, 0, 0.0001, // rounding error
+    'Check setting of currentTime actually works');
+
+  checkStateOnSettingCurrentTimeToZero(animation);
+}, '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, CSS_ANIM_EVENTS);
+
+  div.style.animation = ANIM_PROPERTY_VAL;
+
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(t.step_func(function() {
+    checkStateOnReadyPromiseResolved(animation);
+
+    animation.currentTime =
+      currentTimeForStartOfActiveInterval(animation.timeline);
+    return eventWatcher.wait_for('animationstart');
+  })).then(t.step_func(function() {
+    checkStateAtActiveIntervalStartTime(animation);
+
+    animation.currentTime =
+      currentTimeForFiftyPercentThroughActiveInterval(animation.timeline);
+    checkStateAtFiftyPctOfActiveInterval(animation);
+
+    animation.currentTime =
+      currentTimeForEndOfActiveInterval(animation.timeline);
+    return eventWatcher.wait_for('animationend');
+  })).then(t.step_func(function() {
+    checkStateAtActiveIntervalEndTime(animation);
+  })).catch(t.step_func(function(reason) {
+    assert_unreached(reason);
+  })).then(function() {
+    t.done();
   });
-</script>
+}, 'Skipping forward through animation');
+
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+
+  div.style.animation = ANIM_PROPERTY_VAL;
+
+  var animation = div.getAnimations()[0];
+
+  // So that animation is running instead of paused when we set currentTime:
+  animation.startTime = animation.timeline.currentTime;
+
+  animation.currentTime = currentTimeForEndOfActiveInterval(animation.timeline);
+
+  var previousTimelineTime = animation.timeline.currentTime;
+
+  // Skipping over the active interval will dispatch an 'animationstart' then
+  // an 'animationend' event. We need to wait for these events before we start
+  // testing going backwards since EventWatcher will fail the test if it gets
+  // an event that we haven't told it about.
+  eventWatcher.wait_for(['animationstart',
+                         'animationend']).then(t.step_func(function() {
+    assert_true(document.timeline.currentTime - previousTimelineTime <
+                  ANIM_DUR_MS,
+                'Sanity check that seeking worked rather than the events ' +
+                'firing after normal playback through the very long ' +
+                'animation duration');
+
+    // Now we can start the tests for skipping backwards, but first we check
+    // that after the events we're still in the same end time state:
+    checkStateAtActiveIntervalEndTime(animation);
+
+    animation.currentTime =
+      currentTimeForFiftyPercentThroughActiveInterval(animation.timeline);
+
+    // 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.
+    //
+    // Calling checkStateAtFiftyPctOfActiveInterval will check computed style,
+    // causing computed style to be updated and the 'animationstart' event to
+    // be dispatched synchronously. We need to call wait_for first
+    // otherwise eventWatcher will assert that the event was unexpected.
+    var promise = eventWatcher.wait_for('animationstart');
+    checkStateAtFiftyPctOfActiveInterval(animation);
+    return promise;
+  })).then(t.step_func(function() {
+    animation.currentTime =
+      currentTimeForStartOfActiveInterval(animation.timeline);
+    checkStateAtActiveIntervalStartTime(animation);
+
+    animation.currentTime = 0;
+    // 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(t.step_func(function() {
+    checkStateOnReadyPromiseResolved(animation);
+  })).catch(t.step_func(function(reason) {
+    assert_unreached(reason);
+  })).then(function() {
+    t.done();
+  });
+
+  // This must come after we've set up the Promise chain, since requesting
+  // computed style will force events to be dispatched.
+  // XXX For some reason this fails occasionally (either the animation.playState
+  // check or the marginLeft check).
+  //checkStateAtActiveIntervalEndTime(animation);
+}, 'Skipping backwards through animation');
+
+
+// Next we have multiple tests to check that redundant currentTime 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.
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+  div.style.animation = ANIM_PROPERTY_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.currentTime = currentTimeForActivePhase(animation.timeline);
+  animation.currentTime = currentTimeForBeforePhase(animation.timeline);
+
+  waitForAnimationFrames(2).then(function() {
+    t.done();
+  });
+}, 'Redundant change, before -> active, then back');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+  div.style.animation = ANIM_PROPERTY_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.currentTime = currentTimeForAfterPhase(animation.timeline);
+  animation.currentTime = currentTimeForBeforePhase(animation.timeline);
+
+  waitForAnimationFrames(2).then(function() {
+    t.done();
+  });
+}, 'Redundant change, before -> after, then back');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+  div.style.animation = ANIM_PROPERTY_VAL;
+  var animation = div.getAnimations()[0];
+
+  eventWatcher.wait_for('animationstart').then(function() {
+    animation.currentTime = currentTimeForBeforePhase(animation.timeline);
+    animation.currentTime = currentTimeForActivePhase(animation.timeline);
+
+    waitForAnimationFrames(2).then(function() {
+      t.done();
+    });
+  });
+  // get us into the initial state:
+  animation.currentTime = currentTimeForActivePhase(animation.timeline);
+}, 'Redundant change, active -> before, then back');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+  div.style.animation = ANIM_PROPERTY_VAL;
+  var animation = div.getAnimations()[0];
+
+  eventWatcher.wait_for('animationstart').then(function() {
+    animation.currentTime = currentTimeForAfterPhase(animation.timeline);
+    animation.currentTime = currentTimeForActivePhase(animation.timeline);
+
+    waitForAnimationFrames(2).then(function() {
+      t.done();
+    });
+  });
+  // get us into the initial state:
+  animation.currentTime = currentTimeForActivePhase(animation.timeline);
+}, 'Redundant change, active -> after, then back');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+  div.style.animation = ANIM_PROPERTY_VAL;
+  var animation = div.getAnimations()[0];
+
+  eventWatcher.wait_for(['animationstart',
+                         'animationend']).then(function() {
+    animation.currentTime = currentTimeForBeforePhase(animation.timeline);
+    animation.currentTime = currentTimeForAfterPhase(animation.timeline);
+
+    waitForAnimationFrames(2).then(function() {
+      t.done();
+    });
+  });
+  // get us into the initial state:
+  animation.currentTime = currentTimeForAfterPhase(animation.timeline);
+}, 'Redundant change, after -> before, then back');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+  div.style.animation = ANIM_PROPERTY_VAL;
+  var animation = div.getAnimations()[0];
+
+  eventWatcher.wait_for(['animationstart',
+                         'animationend']).then(function() {
+    animation.currentTime = currentTimeForActivePhase(animation.timeline);
+    animation.currentTime = currentTimeForAfterPhase(animation.timeline);
+
+    waitForAnimationFrames(2).then(function() {
+      t.done();
+    });
+  });
+  // get us into the initial state:
+  animation.currentTime = currentTimeForAfterPhase(animation.timeline);
+}, 'Redundant change, after -> active, then back');
+
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  div.style.animation = ANIM_PROPERTY_VAL;
+
+  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'});
+  div.style.animation = 'anim 100s';
+
+  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');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  div.style.animation = ANIM_PROPERTY_VAL;
+
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(function() {
+    // just before animation ends:
+    animation.currentTime = ANIM_DELAY_MS + ANIM_DUR_MS - 1;
+
+    return waitForAnimationFrames(2);
+  }).then(t.step_func(function() {
+    assert_equals(animation.currentTime, ANIM_DELAY_MS + ANIM_DUR_MS,
+      'Animation.currentTime should not continue to increase after the ' +
+      'animation has finished');
+    t.done();
+  }));
+}, 'Animation.currentTime clamping');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  div.style.animation = ANIM_PROPERTY_VAL;
+
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(function() {
+    // play backwards:
+    animation.playbackRate = -1;
+
+    // just before animation ends (at the "start"):
+    animation.currentTime = 1;
+
+    return waitForAnimationFrames(2);
+  }).then(t.step_func(function() {
+    assert_equals(animation.currentTime, 0,
+      'Animation.currentTime should not continue to decrease after an ' +
+      'animation running in reverse has finished and currentTime is zero');
+    t.done();
+  }));
+}, 'Animation.currentTime clamping for reversed animation');
+
+test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  div.style.animation = 'anim 100s';
+
+  var animation = div.getAnimations()[0];
+  animation.cancel();
+  assert_equals(animation.currentTime, null,
+                'The currentTime of a cancelled animation should be null');
+}, 'Animation.currentTime after cancelling');
+
+    </script>
+  </body>
 </html>
--- a/dom/animation/test/css-animations/test_animation-finish.html
+++ b/dom/animation/test/css-animations/test_animation-finish.html
@@ -1,15 +1,160 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
 <div id="log"></div>
+<style>
+
+.animated-div {
+  margin-left: 10px;
+}
+
+@keyframes anim {
+  from { margin-left: 100px; }
+  to { margin-left: 200px; }
+}
+
+</style>
 <script>
+
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animation-finish.html");
-  });
+
+const ANIM_PROP_VAL = 'anim 100s';
+const ANIM_DURATION = 100000; // ms
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.playbackRate = 0;
+
+  var threw = false;
+  try {
+    animation.finish();
+  } catch (e) {
+    threw = true;
+    assert_equals(e.name, 'InvalidStateError',
+                  'Exception should be an InvalidStateError exception when ' +
+                  'trying to finish an animation with playbackRate == 0');
+  }
+  assert_true(threw,
+              'Expect InvalidStateError exception trying to finish an ' +
+              'animation with playbackRate == 0');
+}, 'Test exceptions when finishing non-running animation');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  div.style.animationIterationCount = 'infinite';
+  var animation = div.getAnimations()[0];
+
+  var threw = false;
+  try {
+    animation.finish();
+  } catch (e) {
+    threw = true;
+    assert_equals(e.name, 'InvalidStateError',
+                  'Exception should be an InvalidStateError exception when ' +
+                  'trying to finish an infinite animation');
+  }
+  assert_true(threw,
+              'Expect InvalidStateError exception trying to finish an ' +
+              'infinite animation');
+}, 'Test exceptions when finishing infinite animation');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.finish();
+  assert_equals(animation.currentTime, ANIM_DURATION,
+                'After finishing, the currentTime should be set to the end ' +
+                'of the active duration');
+}, 'Test finishing of animation');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.currentTime = ANIM_DURATION + 1000; // 1s past effect end
+
+  animation.finish();
+  assert_equals(animation.currentTime, ANIM_DURATION,
+                'After finishing, the currentTime should be set back to the ' +
+                'end of the active duration');
+}, 'Test finishing of animation with a current time past the effect end');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.currentTime = ANIM_DURATION;
+
+  animation.finished.then(t.step_func(function() {
+    animation.playbackRate = -1;
+    animation.finish();
+    assert_equals(animation.currentTime, 0,
+                  'After finishing a reversed animation the currentTime ' +
+                  'should be set to zero');
+    t.done();
+  }));
+}, 'Test finishing of reversed animation');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.currentTime = ANIM_DURATION;
+
+  animation.finished.then(t.step_func(function() {
+    animation.playbackRate = -1;
+
+    animation.currentTime = -1000;
+
+    animation.finish();
+    assert_equals(animation.currentTime, 0,
+                  'After finishing a reversed animation the currentTime ' +
+                  'should be set back to zero');
+    t.done();
+  }));
+}, 'Test finishing of reversed animation with with a current time less ' +
+   'than zero');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.pause();
+
+  animation.ready.then(t.step_func(function() {
+    animation.finish();
+    assert_equals(animation.playState, 'paused',
+                  'The play state of a paused animation should remain ' +
+                  '"paused" even after finish() is called');
+    t.done();
+  }));
+}, 'Test paused state after finishing of animation');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(t.step_func(function() {
+    animation.finish();
+    var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
+    assert_equals(marginLeft, 10,
+                  'The computed style should be reset when finish() is ' +
+                  'called');
+    t.done();
+  }));
+}, 'Test resetting of computed style');
+
 </script>
-</html>
--- a/dom/animation/test/css-animations/test_animation-finished.html
+++ b/dom/animation/test/css-animations/test_animation-finished.html
@@ -1,15 +1,351 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
 <div id="log"></div>
+<style>
+@keyframes abc {
+  to { transform: translate(10px) }
+}
+@keyframes def {}
+</style>
 <script>
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animation-finished.html");
+
+const ANIM_PROP_VAL = 'abc 100s';
+const ANIM_DURATION = 100000; // ms
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  var previousFinishedPromise = animation.finished;
+
+  animation.ready.then(t.step_func(function() {
+    assert_equals(animation.finished, previousFinishedPromise,
+                  'Finished promise is the same object when playing starts');
+    animation.pause();
+    assert_equals(animation.finished, previousFinishedPromise,
+                  'Finished promise does not change when pausing');
+    animation.play();
+    assert_equals(animation.finished, previousFinishedPromise,
+                  'Finished promise does not change when play() unpauses');
+
+    animation.currentTime = ANIM_DURATION;
+
+    return animation.finished;
+  })).then(t.step_func(function() {
+    assert_equals(animation.finished, previousFinishedPromise,
+                  'Finished promise is the same object when playing completes');
+    t.done();
+  }));
+}, 'Test pausing then playing does not change the finished promise');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  var previousFinishedPromise = animation.finished;
+
+  animation.currentTime = ANIM_DURATION;
+
+  animation.finished.then(t.step_func(function() {
+    assert_equals(animation.finished, previousFinishedPromise,
+                  'Finished promise is the same object when playing completes');
+    animation.play();
+    assert_not_equals(animation.finished, previousFinishedPromise,
+                  'Finished promise changes when replaying animation');
+
+    previousFinishedPromise = animation.finished;
+    animation.play();
+    assert_equals(animation.finished, previousFinishedPromise,
+                  'Finished promise is the same after redundant play() call');
+
+    t.done();
+  }));
+}, 'Test restarting a finished animation');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  var previousFinishedPromise;
+
+  animation.currentTime = ANIM_DURATION;
+
+  animation.finished.then(t.step_func(function() {
+    previousFinishedPromise = animation.finished;
+    animation.playbackRate = -1;
+    assert_not_equals(animation.finished, previousFinishedPromise,
+                      'Finished promise should be replaced when reversing a ' +
+                      'finished promise');
+    animation.currentTime = 0;
+    return animation.finished;
+  })).then(t.step_func(function() {
+    previousFinishedPromise = animation.finished;
+    animation.play();
+    assert_not_equals(animation.finished, previousFinishedPromise,
+                      'Finished promise is replaced after play() call on ' +
+                      'finished, reversed animation');
+    t.done();
+  }));
+}, 'Test restarting a reversed finished animation');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  var previousFinishedPromise = animation.finished;
+
+  animation.currentTime = ANIM_DURATION;
+
+  animation.finished.then(t.step_func(function() {
+    animation.currentTime = ANIM_DURATION + 1000;
+    assert_equals(animation.finished, previousFinishedPromise,
+                  'Finished promise is unchanged jumping past end of ' +
+                  'finished animation');
+
+    t.done();
+  }));
+}, 'Test redundant finishing of animation');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.currentTime = ANIM_DURATION;
+  animation.finished.then(t.step_func(function(resolvedAnimation) {
+    assert_equals(resolvedAnimation, animation,
+                  'Object identity of animation passed to Promise callback'
+                  + ' matches the animation object owning the Promise');
+    t.done();
+  }));
+}, 'The finished promise is fulfilled with its Animation');
+
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // Set up pending animation
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+  var previousFinishedPromise = animation.finished;
+
+  // Set up listeners on finished promise
+  animation.finished.then(t.step_func(function() {
+    assert_unreached('finished promise is fulfilled');
+  })).catch(t.step_func(function(err) {
+    assert_equals(err.name, 'AbortError',
+                  'finished promise is rejected with AbortError');
+    assert_not_equals(animation.finished, previousFinishedPromise,
+                      'Finished promise should change after the original is ' +
+                      'rejected');
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+
+  // Now cancel the animation and flush styles
+  div.style.animation = '';
+  window.getComputedStyle(div).animation;
+
+}, 'finished promise is rejected when an animation is cancelled by resetting ' +
+   'the animation property');
+
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // As before, but this time instead of removing all animations, simply update
+  // the list of animations. At least for Firefox, updating is a different
+  // code path.
+
+  // Set up pending animation
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+  var previousFinishedPromise = animation.finished;
+
+  // Set up listeners on finished promise
+  animation.finished.then(t.step_func(function() {
+    assert_unreached('finished promise was fulfilled');
+  })).catch(t.step_func(function(err) {
+    assert_equals(err.name, 'AbortError',
+                  'finished promise is rejected with AbortError');
+    assert_not_equals(animation.finished, previousFinishedPromise,
+                      'Finished promise should change after the original is ' +
+                      'rejected');
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+
+  // Now update the animation and flush styles
+  div.style.animation = 'def 100s';
+  window.getComputedStyle(div).animation;
+
+}, 'finished promise is rejected when an animation is cancelled by changing ' +
+   'the animation property');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+  var previousFinishedPromise = animation.finished;
+
+  // Set up listeners on finished promise
+  animation.finished.then(t.step_func(function() {
+    assert_unreached('finished promise was fulfilled');
+  })).catch(t.step_func(function(err) {
+    assert_equals(err.name, 'AbortError',
+                  'finished promise is rejected with AbortError');
+    assert_not_equals(animation.finished, previousFinishedPromise,
+                      'Finished promise should change after the original is ' +
+                      'rejected');
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+
+  animation.cancel();
+
+}, 'finished promise is rejected when an animation is cancelled by calling ' +
+   'cancel()');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  var previousFinishedPromise = animation.finished;
+
+  animation.currentTime = ANIM_DURATION;
+
+  animation.finished.then(t.step_func(function() {
+    animation.cancel();
+    assert_not_equals(animation.finished, previousFinishedPromise,
+                      'A new finished promise should be created when'
+                      + ' cancelling a finished player');
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+}, 'cancelling an already-finished player replaces the finished promise');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+  animation.cancel();
+
+  // The spec says we still create a new finished promise and reject the old
+  // one even if we're already idle. That behavior might change, but for now
+  // test that we do that.
+  animation.finished.catch(t.step_func(function(err) {
+    assert_equals(err.name, 'AbortError',
+                  'finished promise is rejected with AbortError');
+    t.done();
+  }));
+
+  // Redundant call to cancel();
+  var previousFinishedPromise = animation.finished;
+  animation.cancel();
+  assert_not_equals(animation.finished, previousFinishedPromise,
+                    'A redundant call to cancel() should still generate a new'
+                    + ' finished promise');
+}, 'cancelling an idle player still replaces the finished promise');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  const HALF_DUR = ANIM_DURATION / 2;
+  const QUARTER_DUR = ANIM_DURATION / 4;
+
+  animation.currentTime = HALF_DUR;
+  div.style.animationDuration = QUARTER_DUR + 'ms';
+  // Animation should now be finished
+
+  // Below we use gotNextFrame to check that shortening of the animation
+  // duration causes the finished promise to resolve, rather than it just
+  // getting resolved on the next animation frame. This relies on the fact
+  // that the promises are resolved as a micro-task before the next frame
+  // happens.
+
+  window.getComputedStyle(div).animationDuration; // flush style
+  var gotNextFrame = false;
+  waitForFrame().then(function() {
+    gotNextFrame = true;
   });
+
+  animation.finished.then(t.step_func(function() {
+    assert_false(gotNextFrame, 'shortening of the animation duration should ' +
+                               'resolve the finished promise');
+    assert_equals(animation.currentTime, HALF_DUR,
+                  'currentTime should be unchanged when duration shortened');
+    var previousFinishedPromise = animation.finished;
+    div.style.animationDuration = ANIM_DURATION + 'ms'; // now active again
+    window.getComputedStyle(div).animationDuration; // flush style
+    assert_not_equals(animation.finished, previousFinishedPromise,
+                      'Finished promise should change after lengthening the ' +
+                      'duration causes the animation to become active');
+    t.done();
+  }));
+}, 'Test finished promise changes for animation duration changes');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(function() {
+    animation.playbackRate = 0;
+    animation.currentTime = ANIM_DURATION + 1000;
+    return waitForAnimationFrames(2);
+  }).then(t.step_func(function() {
+    t.done();
+  }));
+
+  animation.finished.then(t.step_func(function() {
+    assert_unreached('finished promise should not resolve when playbackRate ' +
+                     'is zero');
+  }));
+}, 'Test finished promise changes when playbackRate == 0');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(function() {
+    animation.playbackRate = -1;
+    return animation.finished;
+  }).then(t.step_func(function() {
+    t.done();
+  }));
+}, 'Test finished promise resolves when playbackRate set to a negative value');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = ANIM_PROP_VAL;
+  var animation = div.getAnimations()[0];
+
+  var previousFinishedPromise = animation.finished;
+
+  animation.currentTime = ANIM_DURATION;
+
+  animation.finished.then(function() {
+    div.style.animationPlayState = 'running';
+    return waitForAnimationFrames(2);
+  }).then(t.step_func(function() {
+    assert_equals(animation.finished, previousFinishedPromise,
+                  'Should not replay when animation-play-state changes to ' +
+                  '"running" on finished animation');
+    assert_equals(animation.currentTime, ANIM_DURATION,
+                  'currentTime should not change when animation-play-state ' +
+                  'changes to "running" on finished animation');
+    t.done();
+  }));
+}, 'Test finished promise changes when animationPlayState set to running');
+
 </script>
-</html>
--- a/dom/animation/test/css-animations/test_animation-pausing.html
+++ b/dom/animation/test/css-animations/test_animation-pausing.html
@@ -1,15 +1,202 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
 <div id="log"></div>
+<style>
+@keyframes anim { 
+  0% { margin-left: 0px }
+  100% { margin-left: 10000px }
+}
+</style>
 <script>
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animation-pausing.html");
-  });
+
+function getMarginLeft(cs) {
+  return parseFloat(cs.marginLeft);
+}
+
+async_test(function(t) {
+  var div = addDiv(t);
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s';
+
+  var animation = div.getAnimations()[0];
+
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+  var previousAnimVal = getMarginLeft(cs);
+
+  animation.ready.then(waitForFrame).then(t.step_func(function() {
+    assert_true(getMarginLeft(cs) > previousAnimVal,
+                'margin-left is initially increasing');
+    animation.pause();
+    return animation.ready;
+  })).then(t.step_func(function() {
+    previousAnimVal = getMarginLeft(cs);
+    return waitForFrame();
+  })).then(t.step_func(function() {
+    assert_equals(getMarginLeft(cs), previousAnimVal,
+                  'margin-left does not increase after calling pause()');
+    t.done();
+  }));
+}, 'pause() a running animation');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s paused';
+
+  var animation = div.getAnimations()[0];
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+
+  animation.pause();
+  div.style.animationPlayState = 'running';
+
+  animation.ready.then(waitForFrame).then(t.step_func(function() {
+    assert_equals(cs.animationPlayState, 'running',
+                  'animation-play-state is running');
+    assert_equals(getMarginLeft(cs), 0,
+                  'Paused value of margin-left is zero');
+    t.done();
+  }));
+}, 'pause() overrides animation-play-state');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s paused';
+
+  var animation = div.getAnimations()[0];
+
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+
+  animation.play();
+
+  animation.ready.then(waitForFrame).then(t.step_func(function() {
+    assert_true(getMarginLeft(cs) > 0,
+                'Playing value of margin-left is greater than zero');
+    t.done();
+  }));
+}, 'play() overrides animation-play-state');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s paused';
+
+  var animation = div.getAnimations()[0];
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+
+  animation.play();
+
+  var previousAnimVal;
+
+  animation.ready.then(function() {
+    div.style.animationPlayState = 'running';
+    cs.animationPlayState; // Trigger style resolution
+    return waitForFrame();
+  }).then(t.step_func(function() {
+    assert_equals(cs.animationPlayState, 'running',
+                  'animation-play-state is running');
+    div.style.animationPlayState = 'paused';
+    return animation.ready;
+  })).then(t.step_func(function() {
+    assert_equals(cs.animationPlayState, 'paused',
+                  'animation-play-state is paused');
+    previousAnimVal = getMarginLeft(cs);
+    return waitForFrame();
+  })).then(t.step_func(function() {
+    assert_equals(getMarginLeft(cs), previousAnimVal,
+                  'Animated value of margin-left does not change when'
+                  + ' paused by style');
+    t.done();
+  }));
+}, 'play() is overridden by later setting "animation-play-state: paused"');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s';
+
+  var animation = div.getAnimations()[0];
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+
+  // Set the specified style first. If implementations fail to
+  // apply the style changes first, they will ignore the redundant
+  // call to play() and fail to correctly override the pause style.
+  div.style.animationPlayState = 'paused';
+  animation.play();
+  var previousAnimVal = getMarginLeft(cs);
+
+  animation.ready.then(waitForFrame).then(t.step_func(function() {
+    assert_equals(cs.animationPlayState, 'paused',
+                  'animation-play-state is paused');
+    assert_true(getMarginLeft(cs) > previousAnimVal,
+                'Playing value of margin-left is increasing');
+    t.done();
+  }));
+}, 'play() flushes pending changes to animation-play-state first');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s paused';
+
+  var animation = div.getAnimations()[0];
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+
+  // Unlike the previous test for play(), since calling pause() is sticky,
+  // we'll apply it even if the underlying style also says we're paused.
+  //
+  // We would like to test that implementations flush styles before running
+  // pause() but actually there's no style we can currently set that will
+  // change the behavior of pause(). That may change in the future
+  // (e.g. if we introduce animation-timeline or animation-playback-rate etc.).
+  //
+  // For now this just serves as a sanity check that we do the same thing
+  // even if we set style before calling the API.
+  div.style.animationPlayState = 'running';
+  animation.pause();
+  var previousAnimVal = getMarginLeft(cs);
+
+  animation.ready.then(waitForFrame).then(t.step_func(function() {
+    assert_equals(cs.animationPlayState, 'running',
+                  'animation-play-state is running');
+    assert_equals(getMarginLeft(cs), previousAnimVal,
+                  'Paused value of margin-left does not change');
+    t.done();
+  }));
+}, 'pause() applies pending changes to animation-play-state first');
+// (Note that we can't actually test for this; see comment above, in test-body.)
+
+async_test(function(t) {
+  var div = addDiv(t, { style: 'animation: anim 1000s' });
+  var animation = div.getAnimations()[0];
+
+  var readyPromiseRun = false;
+
+  animation.ready.then(t.step_func(function() {
+    div.style.animationPlayState = 'paused';
+    assert_equals(animation.playState, 'pending', 'Animation is pause pending');
+
+    // Set current time
+    animation.currentTime = 5000;
+    assert_equals(animation.playState, 'running',
+                  'Animation is running immediately after setting currentTime');
+
+    // The ready promise should now be resolved. If it's not then test will
+    // probably time out before anything else happens that causes it to resolve.
+    return animation.ready;
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+}, 'Setting the current time cancels a pending pause');
+
 </script>
-</html>
--- a/dom/animation/test/css-animations/test_animation-playstate.html
+++ b/dom/animation/test/css-animations/test_animation-playstate.html
@@ -1,15 +1,89 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
 <div id="log"></div>
+<style>
+@keyframes anim { }
+</style>
 <script>
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animation-playstate.html");
-  });
+
+async_test(function(t) {
+  var div = addDiv(t);
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s';
+
+  var animation = div.getAnimations()[0];
+  assert_equals(animation.playState, 'pending');
+
+  animation.ready.then(t.step_func(function() {
+    assert_equals(animation.playState, 'running');
+    t.done();
+  }));
+}, 'Animation returns correct playState when running');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s paused';
+
+  var animation = div.getAnimations()[0];
+  assert_equals(animation.playState, 'pending');
+
+  animation.ready.then(t.step_func(function() {
+    assert_equals(animation.playState, 'paused');
+    t.done();
+  }));
+}, 'Animation returns correct playState when paused');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s';
+
+  var animation = div.getAnimations()[0];
+  animation.pause();
+  assert_equals(animation.playState, 'pending');
+
+  animation.ready.then(t.step_func(function() {
+    assert_equals(animation.playState, 'paused');
+    t.done();
+  }));
+}, 'Animation.playState updates when paused by script');
+
+test(function(t) {
+  var div = addDiv(t);
+  var cs = window.getComputedStyle(div);
+  div.style.animation = 'anim 1000s paused';
+
+  var animation = div.getAnimations()[0];
+  div.style.animationPlayState = 'running';
+  // This test also checks that calling playState flushes style
+  assert_equals(animation.playState, 'pending',
+                'Animation.playState reports pending after updating'
+                + ' animation-play-state (got: ' + animation.playState + ')');
+}, 'Animation.playState updates when resumed by setting style');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim 1000s';
+
+  var animation = div.getAnimations()[0];
+  animation.cancel();
+  assert_equals(animation.playState, 'idle');
+}, 'Animation returns correct playState when cancelled');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim 1000s';
+
+  var animation = div.getAnimations()[0];
+  animation.cancel();
+  animation.currentTime = 50 * 1000;
+  assert_equals(animation.playState, 'paused',
+                'After seeking an idle animation, it is effectively paused');
+}, 'After cancelling an animation, seeking it makes it paused');
+
 </script>
-</html>
--- a/dom/animation/test/css-animations/test_animation-ready.html
+++ b/dom/animation/test/css-animations/test_animation-ready.html
@@ -1,15 +1,251 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
 <div id="log"></div>
+<style>
+@keyframes abc {
+  to { transform: translate(10px) }
+}
+</style>
 <script>
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animation-ready.html");
-  });
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'abc 100s';
+  var animation = div.getAnimations()[0];
+
+  var originalReadyPromise = animation.ready;
+  var pauseReadyPromise;
+
+  animation.ready.then(t.step_func(function() {
+    assert_equals(animation.ready, originalReadyPromise,
+                  'Ready promise is the same object when playing completes');
+    animation.pause();
+    assert_not_equals(animation.ready, originalReadyPromise,
+                      'A new ready promise is created when pausing');
+    pauseReadyPromise = animation.ready;
+    // Wait for the promise to fulfill since if we abort the pause the ready
+    // promise object is reused.
+    return animation.ready;
+  })).then(t.step_func(function() {
+    animation.play();
+    assert_not_equals(animation.ready, pauseReadyPromise,
+                      'A new ready promise is created when playing');
+    t.done();
+  }));
+}, 'A new ready promise is created when play()/pause() is called');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'abc 100s paused';
+  var animation = div.getAnimations()[0];
+
+  var originalReadyPromise = animation.ready;
+  animation.ready.then(t.step_func(function() {
+    div.style.animationPlayState = 'running';
+    assert_not_equals(animation.ready, originalReadyPromise,
+                      'After updating animation-play-state a new ready promise'
+                      + ' object is created');
+    t.done();
+  }));
+}, 'A new ready promise is created when setting animation-play-state: running');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'abc 100s';
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(t.step_func(function() {
+    var promiseBeforeCallingPlay = animation.ready;
+    animation.play();
+    assert_equals(animation.ready, promiseBeforeCallingPlay,
+                  'Ready promise has same object identity after redundant call'
+                  + ' to play()');
+    t.done();
+  }));
+}, 'Redundant calls to play() do not generate new ready promise objects');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'abc 100s';
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(t.step_func(function(resolvedAnimation) {
+    assert_equals(resolvedAnimation, animation,
+                  'Object identity of Animation passed to Promise callback'
+                  + ' matches the Animation object owning the Promise');
+    t.done();
+  }));
+}, 'The ready promise is fulfilled with its Animation');
+
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // Set up pending animation
+  div.style.animation = 'abc 100s';
+  var animation = div.getAnimations()[0];
+  assert_equals(animation.playState, 'pending',
+               'Animation is initially pending');
+
+  // Set up listeners on ready promise
+  animation.ready.then(t.step_func(function() {
+    assert_unreached('ready promise is fulfilled');
+  })).catch(t.step_func(function(err) {
+    assert_equals(err.name, 'AbortError',
+                  'ready promise is rejected with AbortError');
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+
+  // Now cancel the animation and flush styles
+  div.style.animation = '';
+  window.getComputedStyle(div).animation;
+
+}, 'ready promise is rejected when an animation is cancelled by resetting'
+   + ' the animation property');
+
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // As before, but this time instead of removing all animations, simply update
+  // the list of animations. At least for Firefox, updating is a different
+  // code path.
+
+  // Set up pending animation
+  div.style.animation = 'abc 100s';
+  var animation = div.getAnimations()[0];
+  assert_equals(animation.playState, 'pending',
+                'Animation is initially pending');
+
+  // Set up listeners on ready promise
+  animation.ready.then(t.step_func(function() {
+    assert_unreached('ready promise was fulfilled');
+  })).catch(t.step_func(function(err) {
+    assert_equals(err.name, 'AbortError',
+                  'ready promise is rejected with AbortError');
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+
+  // Now update the animation and flush styles
+  div.style.animation = 'def 100s';
+  window.getComputedStyle(div).animation;
+
+}, 'ready promise is rejected when an animation is cancelled by updating'
+   + ' the animation property');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'abc 100s';
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(t.step_func(function() {
+    assert_unreached('ready promise was fulfilled');
+  })).catch(t.step_func(function(err) {
+    assert_equals(err.name, 'AbortError',
+                  'ready promise is rejected with AbortError');
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+
+  animation.cancel();
+}, 'ready promise is rejected when a play-pending animation is cancelled by'
+   + ' calling cancel()');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'abc 100s';
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(t.step_func(function() {
+    animation.pause();
+
+    // Set up listeners on pause-pending ready promise
+    animation.ready.then(t.step_func(function() {
+      assert_unreached('ready promise was fulfilled');
+    })).catch(t.step_func(function(err) {
+      assert_equals(err.name, 'AbortError',
+                    'ready promise is rejected with AbortError');
+    })).then(t.step_func(function() {
+      t.done();
+    }));
+
+    animation.cancel();
+  }));
+}, 'ready promise is rejected when a pause-pending animation is cancelled by'
+   + ' calling cancel()');
+
+async_test(function(t) {
+  var div = addDiv(t, { style: 'animation: abc 100s' });
+  var animation = div.getAnimations()[0];
+
+  var originalReadyPromise = animation.ready;
+  animation.ready.then(t.step_func(function() {
+    div.style.animationPlayState = 'paused';
+    assert_not_equals(animation.ready, originalReadyPromise,
+                      'A new Promise object is generated when setting'
+                      + ' animation-play-state: paused');
+    t.done();
+  }));
+}, 'A new ready promise is created when setting animation-play-state: paused');
+
+async_test(function(t) {
+  var div = addDiv(t, { style: 'animation: abc 100s' });
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(t.step_func(function() {
+    div.style.animationPlayState = 'paused';
+    var firstReadyPromise = animation.ready;
+    animation.pause();
+    assert_equals(animation.ready, firstReadyPromise,
+                  'Ready promise objects are identical after redundant pause');
+    t.done();
+  }));
+}, 'Pausing twice re-uses the same Promise');
+
+async_test(function(t) {
+  var div = addDiv(t, { style: 'animation: abc 100s' });
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(t.step_func(function() {
+    div.style.animationPlayState = 'paused';
+
+    // Flush style and verify we're pending at the same time
+    assert_equals(animation.playState, 'pending', 'Animation is pending');
+    var pauseReadyPromise = animation.ready;
+
+    // Now play again immediately
+    div.style.animationPlayState = 'running';
+    assert_equals(animation.playState, 'pending', 'Animation is still pending');
+    assert_equals(animation.ready, pauseReadyPromise,
+                  'The pause Promise is re-used when playing while waiting'
+                  + ' to pause');
+
+    return animation.ready;
+  })).then(t.step_func(function() {
+    assert_equals(animation.playState, 'running',
+                  'Animation is running after aborting a pause');
+    t.done();
+  }));
+}, 'If a pause operation is interrupted, the ready promise is reused');
+
+async_test(function(t) {
+  var div = addDiv(t, { style: 'animation: abc 100s' });
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(t.step_func(function() {
+    div.style.animationPlayState = 'paused';
+    return animation.ready;
+  })).then(t.step_func(function(resolvedAnimation) {
+    assert_equals(resolvedAnimation, animation,
+                  'Promise received when ready Promise for a pause operation'
+                  + ' is completed is the animation on which the pause was'
+                  + ' performed');
+    t.done();
+  }));
+}, 'When a pause is complete the Promise callback gets the correct animation');
+
 </script>
-</html>
--- a/dom/animation/test/css-animations/test_animation-starttime.html
+++ b/dom/animation/test/css-animations/test_animation-starttime.html
@@ -1,15 +1,559 @@
 <!doctype html>
-<meta charset=utf-8>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id="log"></div>
-<script>
+<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="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="../testcommon.js"></script>
+  </head>
+  <body>
+    <div id="log"></div>
+    <script type="text/javascript">
+
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animation-starttime.html");
+
+// TODO: add equivalent tests without an animation-delay, but first we need to
+// change the timing of animationstart dispatch. (Right now the animationstart
+// event will fire before the ready Promise is resolved if there is no
+// animation-delay.)
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=1134163
+
+// 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'];
+const ANIM_DELAY_MS = 1000000; // 1000s
+const ANIM_DUR_MS = 1000000; // 1000s
+const ANIM_PROPERTY_VAL = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
+
+/**
+ * These helpers get the value that the startTime 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 startTimeForBeforePhase(timeline) {
+  return timeline.currentTime - ANIM_DELAY_MS / 2;
+}
+function startTimeForActivePhase(timeline) {
+  return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS / 2;
+}
+function startTimeForAfterPhase(timeline) {
+  return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS - ANIM_DELAY_MS / 2;
+}
+function startTimeForStartOfActiveInterval(timeline) {
+  return timeline.currentTime - ANIM_DELAY_MS;
+}
+function startTimeForFiftyPercentThroughActiveInterval(timeline) {
+  return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.5;
+}
+function startTimeForEndOfActiveInterval(timeline) {
+  return timeline.currentTime - 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 UNANIMATED_POSITION = 10;
+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:
+//
+//   https://w3c.github.io/web-animations/#animation-effect-phases-and-states
+//
+// Note the distinction between the "animation start time" which occurs before
+// the start delay and the start of the active interval which occurs after it.
+
+// Called when the ready Promise's callbacks should happen
+function checkStateOnReadyPromiseResolved(animation)
+{
+  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');
+
+  assert_equals(animation.playState, 'running',
+    'Animation.playState should be "running" on the first paint ' +
+    'tick after animation creation');
+
+  assert_equals(animation.effect.target.style.animationPlayState, 'running',
+    'Animation.effect.target.style.animationPlayState 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, UNANIMATED_POSITION,
+                'the computed value of margin-left should be unaffected ' +
+                'by an animation with a delay on ready Promise resolve');
+}
+
+// Called when startTime is set to the time the active interval starts.
+function checkStateAtActiveIntervalStartTime(animation)
+{
+  // We don't test animation.startTime since our caller just set it.
+
+  assert_equals(animation.playState, 'running',
+    'Animation.playState should be "running" at the start of ' +
+    'the active interval');
+
+  assert_equals(animation.effect.target.style.animationPlayState, 'running',
+    'Animation.effect.target.style.animationPlayState 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.startTime 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 startTime is set to the time the active interval ends.
+function checkStateAtActiveIntervalEndTime(animation)
+{
+  // We don't test animation.startTime since our caller just set it.
+
+  assert_equals(animation.playState, 'finished',
+    'Animation.playState should be "finished" at the end of ' +
+    'the active interval');
+
+  assert_equals(animation.effect.target.style.animationPlayState, "running",
+    'Animation.effect.target.style.animationPlayState should be ' +
+    '"finished" at the end of the active interval');
+
+  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 ' +
+    'by the animation at the end of the active duration when the ' +
+    'animation-fill-mode is none');
+}
+
+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');
+
+async_test(function(t)
+{
+  var div = addDiv(t, { 'style': 'animation: anim 100s' });
+  var animation = div.getAnimations()[0];
+  animation.ready.then(t.step_func(function() {
+    assert_true(animation.startTime > 0,
+                'startTime is resolved when running');
+    t.done();
+  }));
+}, 'startTime is resolved when running');
+
+async_test(function(t)
+{
+  var div = addDiv(t, { 'style': 'animation: anim 100s paused' });
+  var animation = div.getAnimations()[0];
+  animation.ready.then(t.step_func(function() {
+    assert_equals(animation.startTime, null,
+                  'startTime is unresolved when paused');
+    t.done();
+  }));
+}, 'startTime is unresolved when paused');
+
+async_test(function(t)
+{
+  var div = addDiv(t, { 'style': 'animation: anim 100s' });
+  var animation = div.getAnimations()[0];
+  animation.ready.then(t.step_func(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');
+    t.done();
+  }));
+}, 'startTime while pause-pending and play-pending');
+
+async_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
+  // FIXME: Once we implement finish(), use that here.
+  animation.currentTime = 100 * 1000;
+  animation.ready.then(t.step_func(function() {
+    // Call play() which puts us back in the running state
+    animation.play();
+    // FIXME: Enable this once we implement finishing behavior (bug 1074630)
+    /*
+    assert_equals(animation.startTime, null, 'startTime is unresolved');
+    */
+    t.done();
+  }));
+}, 'startTime while play-pending from finished state');
+
+async_test(function(t) {
+  var div = addDiv(t, { style: 'animation: anim 1000s' });
+  var animation = div.getAnimations()[0];
+
+  assert_equals(animation.startTime, null, 'The initial startTime is null');
+  var initialTimelineTime = document.timeline.currentTime;
+
+  animation.ready.then(t.step_func(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(t.step_func(function() {
+    assert_equals(animation.startTime, null,
+                  'After actually pausing, the startTime of an animation ' +
+                  'is null');
+    t.done();
+  }));
+}, 'Pausing should make the startTime become null');
+
+test(function(t)
+{
+  var div = addDiv(t, {'class': 'animated-div'});
+  div.style.animation = ANIM_PROPERTY_VAL;
+
+  var animation = div.getAnimations()[0];
+  var currentTime = animation.timeline.currentTime;
+  animation.startTime = currentTime;
+  assert_approx_equals(animation.startTime, currentTime, 0.0001, // rounding error
+    'Check setting of startTime actually works');
+}, 'Sanity test to check round-tripping assigning to a new animation\'s ' +
+   'startTime');
+
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+
+  div.style.animation = ANIM_PROPERTY_VAL;
+
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(t.step_func(function() {
+    checkStateOnReadyPromiseResolved(animation);
+
+    animation.startTime = startTimeForStartOfActiveInterval(animation.timeline);
+    return eventWatcher.wait_for('animationstart');
+  })).then(t.step_func(function() {
+    checkStateAtActiveIntervalStartTime(animation);
+
+    animation.startTime =
+      startTimeForFiftyPercentThroughActiveInterval(animation.timeline);
+    checkStateAtFiftyPctOfActiveInterval(animation);
+
+    animation.startTime = startTimeForEndOfActiveInterval(animation.timeline);
+    return eventWatcher.wait_for('animationend');
+  })).then(t.step_func(function() {
+    checkStateAtActiveIntervalEndTime(animation);
+  })).catch(t.step_func(function(reason) {
+    assert_unreached(reason);
+  })).then(function() {
+    t.done();
   });
-</script>
+}, 'Skipping forward through animation');
+
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+
+  div.style.animation = ANIM_PROPERTY_VAL;
+
+  var animation = div.getAnimations()[0];
+
+  animation.startTime = startTimeForEndOfActiveInterval(animation.timeline);
+
+  var previousTimelineTime = animation.timeline.currentTime;
+
+  // Skipping over the active interval will dispatch an 'animationstart' then
+  // an 'animationend' event. We need to wait for these events before we start
+  // testing going backwards since EventWatcher will fail the test if it gets
+  // an event that we haven't told it about.
+  eventWatcher.wait_for(['animationstart',
+                         'animationend']).then(t.step_func(function() {
+    assert_true(document.timeline.currentTime - previousTimelineTime <
+                  ANIM_DUR_MS,
+                'Sanity check that seeking worked rather than the events ' +
+                'firing after normal playback through the very long ' +
+                'animation duration');
+
+    // Now we can start the tests for skipping backwards, but first we check
+    // that after the events we're still in the same end time state:
+    checkStateAtActiveIntervalEndTime(animation);
+
+    animation.startTime =
+      startTimeForFiftyPercentThroughActiveInterval(animation.timeline);
+
+    // 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.
+    //
+    // Calling checkStateAtFiftyPctOfActiveInterval will check computed style,
+    // causing computed style to be updated and the 'animationstart' event to
+    // be dispatched synchronously. We need to call wait_for first
+    // otherwise eventWatcher will assert that the event was unexpected.
+    var promise = eventWatcher.wait_for('animationstart');
+    checkStateAtFiftyPctOfActiveInterval(animation);
+    return promise;
+  })).then(t.step_func(function() {
+    animation.startTime = startTimeForStartOfActiveInterval(animation.timeline);
+    checkStateAtActiveIntervalStartTime(animation);
+
+    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(t.step_func(function() {
+    checkStateOnReadyPromiseResolved(animation);
+  })).catch(t.step_func(function(reason) {
+    assert_unreached(reason);
+  })).then(function() {
+    t.done();
+  });
+
+  // This must come after we've set up the Promise chain, since requesting
+  // computed style will force events to be dispatched.
+  // XXX For some reason this fails occasionally (either the animation.playState
+  // check or the marginLeft check).
+  //checkStateAtActiveIntervalEndTime(animation);
+}, '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.
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+  div.style.animation = ANIM_PROPERTY_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.startTime = startTimeForActivePhase(animation.timeline);
+  animation.startTime = startTimeForBeforePhase(animation.timeline);
+
+  waitForAnimationFrames(2).then(function() {
+    t.done();
+  });
+}, 'Redundant change, before -> active, then back');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+  div.style.animation = ANIM_PROPERTY_VAL;
+  var animation = div.getAnimations()[0];
+
+  animation.startTime = startTimeForAfterPhase(animation.timeline);
+  animation.startTime = startTimeForBeforePhase(animation.timeline);
+
+  waitForAnimationFrames(2).then(function() {
+    t.done();
+  });
+}, 'Redundant change, before -> after, then back');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+  div.style.animation = ANIM_PROPERTY_VAL;
+  var animation = div.getAnimations()[0];
+
+  eventWatcher.wait_for('animationstart').then(function() {
+    animation.startTime = startTimeForBeforePhase(animation.timeline);
+    animation.startTime = startTimeForActivePhase(animation.timeline);
+
+    waitForAnimationFrames(2).then(function() {
+      t.done();
+    });
+  });
+  // get us into the initial state:
+  animation.startTime = startTimeForActivePhase(animation.timeline);
+}, 'Redundant change, active -> before, then back');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+  div.style.animation = ANIM_PROPERTY_VAL;
+  var animation = div.getAnimations()[0];
+
+  eventWatcher.wait_for('animationstart').then(function() {
+    animation.startTime = startTimeForAfterPhase(animation.timeline);
+    animation.startTime = startTimeForActivePhase(animation.timeline);
+
+    waitForAnimationFrames(2).then(function() {
+      t.done();
+    });
+  });
+  // get us into the initial state:
+  animation.startTime = startTimeForActivePhase(animation.timeline);
+}, 'Redundant change, active -> after, then back');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+  div.style.animation = ANIM_PROPERTY_VAL;
+  var animation = div.getAnimations()[0];
+
+  eventWatcher.wait_for(['animationstart',
+                         'animationend']).then(function() {
+    animation.startTime = startTimeForBeforePhase(animation.timeline);
+    animation.startTime = startTimeForAfterPhase(animation.timeline);
+
+    waitForAnimationFrames(2).then(function() {
+      t.done();
+    });
+  });
+  // get us into the initial state:
+  animation.startTime = startTimeForAfterPhase(animation.timeline);
+}, 'Redundant change, after -> before, then back');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
+  div.style.animation = ANIM_PROPERTY_VAL;
+  var animation = div.getAnimations()[0];
+
+  eventWatcher.wait_for(['animationstart',
+                         'animationend']).then(function() {
+    animation.startTime = startTimeForActivePhase(animation.timeline);
+    animation.startTime = startTimeForAfterPhase(animation.timeline);
+
+    waitForAnimationFrames(2).then(function() {
+      t.done();
+    });
+  });
+  // get us into the initial state:
+  animation.startTime = startTimeForAfterPhase(animation.timeline);
+}, 'Redundant change, after -> active, then back');
+
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  div.style.animation = ANIM_PROPERTY_VAL;
+
+  var animation = div.getAnimations()[0];
+
+  var storedCurrentTime;
+
+  animation.ready.then(t.step_func(function() {
+    storedCurrentTime = animation.currentTime;
+    animation.startTime = null;
+    return animation.ready;
+  })).catch(t.step_func(function(reason) {
+    assert_unreached(reason);
+  })).then(t.step_func(function() {
+    assert_equals(animation.currentTime, storedCurrentTime,
+      'Test that hold time is correct');
+    t.done();
+  }));
+}, 'Setting startTime to null');
+
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  div.style.animation = 'anim 100s';
+
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(t.step_func(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(t.step_func(function() {
+    assert_equals(animation.startTime, null,
+      'Animation.startTime is null after paused');
+    assert_equals(animation.playState, 'paused',
+      'Animation.playState is "paused" after pause() call');
+  })).catch(t.step_func(function(reason) {
+    assert_unreached(reason);
+  })).then(function() {
+    t.done();
+  });
+}, 'Animation.startTime after pausing');
+
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  div.style.animation = 'anim 100s';
+
+  var animation = div.getAnimations()[0];
+  animation.ready.then(t.step_func(function() {
+    animation.cancel();
+    assert_equals(animation.startTime, null,
+                  'The startTime of a cancelled animation should be null');
+    t.done();
+  }));
+}, 'Animation.startTime after cancelling');
+
+    </script>
+  </body>
 </html>
--- a/dom/animation/test/css-animations/test_animations-dynamic-changes.html
+++ b/dom/animation/test/css-animations/test_animations-dynamic-changes.html
@@ -1,15 +1,159 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
 <div id="log"></div>
+<style>
+@keyframes anim1 {
+  to { left: 100px }
+}
+@keyframes anim2 { }
+</style>
 <script>
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animations-dynamic-changes.html");
-  });
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim1 100s';
+
+  var originalAnimation = div.getAnimations()[0];
+  var originalStartTime;
+  var originalCurrentTime;
+
+  // Wait a moment so we can confirm the startTime doesn't change (and doesn't
+  // simply reflect the current time).
+  originalAnimation.ready.then(function() {
+    originalStartTime = originalAnimation.startTime;
+    originalCurrentTime = originalAnimation.currentTime;
+
+    // Wait a moment so we can confirm the startTime doesn't change (and
+    // doesn't simply reflect the current time).
+    return waitForFrame();
+  }).then(t.step_func(function() {
+    div.style.animationDuration = '200s';
+    var animation = div.getAnimations()[0];
+    assert_equals(animation, originalAnimation,
+                  'The same Animation is returned after updating'
+                  + ' animation duration');
+    assert_equals(animation.startTime, originalStartTime,
+                  'Animations returned by getAnimations preserve'
+                  + ' their startTime even when they are updated');
+    // Sanity check
+    assert_not_equals(animation.currentTime, originalCurrentTime,
+                      'Animation.currentTime has updated in next'
+                      + ' requestAnimationFrame callback');
+    t.done();
+  }));
+}, 'Animations preserve their startTime when changed');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim1 100s, anim1 100s';
+
+  // Store original state
+  var animations = div.getAnimations();
+  var animation1 = animations[0];
+  var animation2 = animations[1];
+
+  // Update first in list
+  div.style.animationDuration = '200s, 100s';
+  animations = div.getAnimations();
+  assert_equals(animations[0], animation1,
+                'First Animation is in same position after update');
+  assert_equals(animations[1], animation2,
+                'Second Animation is in same position after update');
+}, 'Updated Animations maintain their order in the list');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim1 200s, anim1 100s';
+
+  // Store original state
+  var animations = div.getAnimations();
+  var animation1 = animations[0];
+  var animation2 = animations[1];
+
+  // Wait before continuing so we can compare start times (otherwise the
+  // new Animation objects and existing Animation objects will all have the same
+  // start time).
+  waitForAllAnimations(animations).then(waitForFrame).then(t.step_func(function() {
+    // Swap duration of first and second in list and prepend animation at the
+    // same time
+    div.style.animation = 'anim1 100s, anim1 100s, anim1 200s';
+    animations = div.getAnimations();
+    assert_true(animations[0] !== animation1 && animations[0] !== animation2,
+                'New Animation is prepended to start of list');
+    assert_equals(animations[1], animation1,
+                  'First Animation is in second position after update');
+    assert_equals(animations[2], animation2,
+                  'Second Animation is in third position after update');
+    assert_equals(animations[1].startTime, animations[2].startTime,
+                  'Old Animations have the same start time');
+    // TODO: Check that animations[0].startTime === null
+    return animations[0].ready;
+  })).then(t.step_func(function() {
+    assert_true(animations[0].startTime > animations[1].startTime,
+                'New Animation has later start time');
+    t.done();
+  }));
+}, 'Only the startTimes of existing animations are preserved');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim1 100s, anim1 100s';
+  var secondAnimation = div.getAnimations()[1];
+
+  // Wait before continuing so we can compare start times
+  secondAnimation.ready.then(waitForFrame).then(t.step_func(function() {
+    // Trim list of animations
+    div.style.animationName = 'anim1';
+    var animations = div.getAnimations();
+    assert_equals(animations.length, 1, 'List of Animations was trimmed');
+    assert_equals(animations[0], secondAnimation,
+                  'Remaining Animation is the second one in the list');
+    assert_equals(typeof(animations[0].startTime), 'number',
+                  'Remaining Animation has resolved startTime');
+    assert_true(animations[0].startTime < animations[0].timeline.currentTime,
+                'Remaining Animation preserves startTime');
+    t.done();
+  }));
+}, 'Animations are removed from the start of the list while preserving'
+   + ' the state of existing Animations');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim1 100s';
+  var firstAddedAnimation = div.getAnimations()[0],
+      secondAddedAnimation,
+      animations;
+
+  // Wait and add second Animation
+  firstAddedAnimation.ready.then(waitForFrame).then(t.step_func(function() {
+    div.style.animation = 'anim1 100s, anim1 100s';
+    secondAddedAnimation = div.getAnimations()[0];
+
+    // Wait again and add another Animation
+    return secondAddedAnimation.ready.then(waitForFrame);
+  })).then(t.step_func(function() {
+    div.style.animation = 'anim1 100s, anim2 100s, anim1 100s';
+    animations = div.getAnimations();
+    assert_not_equals(firstAddedAnimation, secondAddedAnimation,
+                      'New Animations are added to start of the list');
+    assert_equals(animations[0], secondAddedAnimation,
+                  'Second Animation remains in same position after'
+                  + ' interleaving');
+    assert_equals(animations[2], firstAddedAnimation,
+                  'First Animation remains in same position after'
+                  + ' interleaving');
+    return animations[1].ready;
+  })).then(t.step_func(function() {
+    assert_true(animations[1].startTime > animations[0].startTime,
+                'Interleaved animation starts later than existing animations');
+    assert_true(animations[0].startTime > animations[2].startTime,
+                'Original animations retain their start time');
+    t.done();
+  }));
+}, 'Animation state is preserved when interleaving animations in list');
+
 </script>
-</html>
--- a/dom/animation/test/css-animations/test_effect-name.html
+++ b/dom/animation/test/css-animations/test_effect-name.html
@@ -1,15 +1,37 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
 <div id="log"></div>
+<style>
+@keyframes xyz {
+  to { left: 100px }
+}
+</style>
 <script>
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_effect-name.html");
-  });
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'xyz 100s';
+  assert_equals(div.getAnimations()[0].effect.name, 'xyz',
+                'Animation effect name matches keyframes rule name');
+}, 'Effect name makes keyframe rule');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'x\\yz 100s';
+  assert_equals(div.getAnimations()[0].effect.name, 'xyz',
+                'Escaped animation effect name matches keyframes rule name');
+}, 'Escaped animation name');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'x\\79 z 100s';
+  assert_equals(div.getAnimations()[0].effect.name, 'xyz',
+                'Hex-escaped animation name matches keyframes rule'
+                + ' name');
+}, 'Animation name with hex-escape');
+
 </script>
-</html>
--- a/dom/animation/test/css-animations/test_effect-target.html
+++ b/dom/animation/test/css-animations/test_effect-target.html
@@ -1,15 +1,21 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
 <div id="log"></div>
+<style>
+@keyframes anim { }
+</style>
 <script>
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_effect-target.html");
-  });
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim 100s';
+  var animation = div.getAnimations()[0];
+  assert_equals(animation.effect.target, div,
+    'Animation.target is the animatable div');
+}, 'Returned CSS animations have the correct Animation.target');
+
 </script>
-</html>
--- a/dom/animation/test/css-animations/test_element-get-animations.html
+++ b/dom/animation/test/css-animations/test_element-get-animations.html
@@ -1,15 +1,272 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
 <div id="log"></div>
+<style>
+@keyframes anim1 {
+  to { left: 100px }
+}
+@keyframes anim2 {
+  to { top: 100px }
+}
+@keyframes multiPropAnim {
+  to { background: green, opacity: 0.5, left: 100px, top: 100px }
+}
+@keyframes empty { }
+</style>
 <script>
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_element-get-animations.html");
-  });
+
+test(function(t) {
+  var div = addDiv(t);
+  assert_equals(div.getAnimations().length, 0,
+    'getAnimations returns an empty sequence for an element'
+    + ' with no animations');
+}, 'getAnimations for non-animated content');
+
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // Add an animation
+  div.style.animation = 'anim1 100s';
+  var animations = div.getAnimations();
+  assert_equals(animations.length, 1,
+    'getAnimations returns an Animation running CSS Animations');
+  animations[0].ready.then(t.step_func(function() {
+    var startTime = animations[0].startTime;
+    assert_true(startTime > 0 && startTime <= document.timeline.currentTime,
+      'CSS animation has a sensible start time');
+
+    // Wait a moment then add a second animation.
+    //
+    // We wait for the next frame so that we can test that the start times of
+    // the animations differ.
+    return waitForFrame();
+  })).then(t.step_func(function() {
+    div.style.animation = 'anim1 100s, anim2 100s';
+    animations = div.getAnimations();
+    assert_equals(animations.length, 2,
+      'getAnimations returns one Animation for each value of'
+      + ' animation-name');
+    // Wait until both Animations are ready
+    // (We don't make any assumptions about the order of the Animations since
+    //  that is the purpose of the following test.)
+    return waitForAllAnimations(animations);
+  })).then(t.step_func(function() {
+    assert_true(animations[0].startTime < animations[1].startTime,
+      'Additional Animations for CSS animations start after the original'
+      + ' animation and appear later in the list');
+    t.done();
+  }));
+}, 'getAnimations for CSS Animations');
+
+test(function(t) {
+  var div = addDiv(t);
+
+  // Add an animation that targets multiple properties
+  div.style.animation = 'multiPropAnim 100s';
+  assert_equals(div.getAnimations().length, 1,
+    'getAnimations returns only one Animation for a CSS Animation'
+    + ' that targets multiple properties');
+}, 'getAnimations for multi-property animations');
+
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // Add an animation
+  div.style.backgroundColor = 'red';
+  div.style.animation = 'anim1 100s';
+  window.getComputedStyle(div).backgroundColor;
+
+  // Wait until a frame after the animation starts, then add a transition
+  var animations = div.getAnimations();
+  animations[0].ready.then(waitForFrame).then(t.step_func(function() {
+    div.style.transition = 'all 100s';
+    div.style.backgroundColor = 'green';
+
+    animations = div.getAnimations();
+    assert_equals(animations.length, 2,
+      'getAnimations returns Animations for both animations and'
+      + ' transitions that run simultaneously');
+    return waitForAllAnimations(animations);
+  })).then(t.step_func(function() {
+    assert_true(animations[0].startTime > animations[1].startTime,
+      'Animations for transitions appear before animations even if they'
+      + ' start later');
+    t.done();
+  }));
+}, 'getAnimations for both CSS Animations and Transitions at once');
+
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // Set up event listener
+  div.addEventListener('animationend', t.step_func(function() {
+    assert_equals(div.getAnimations().length, 0,
+      'getAnimations does not return Animations for finished '
+      + ' (and non-forwards-filling) CSS Animations');
+    t.done();
+  }));
+
+  // Add a very short animation
+  div.style.animation = 'anim1 0.01s';
+}, 'getAnimations for CSS Animations that have finished');
+
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // Set up event listener
+  div.addEventListener('animationend', t.step_func(function() {
+    assert_equals(div.getAnimations().length, 1,
+      'getAnimations returns Animations for CSS Animations that have'
+      + ' finished but are filling forwards');
+    t.done();
+  }));
+
+  // Add a very short animation
+  div.style.animation = 'anim1 0.01s forwards';
+}, 'getAnimations for CSS Animations that have finished but are'
+   + ' forwards filling');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'none 100s';
+
+  var animations = div.getAnimations();
+  assert_equals(animations.length, 0,
+    'getAnimations returns an empty sequence for an element'
+    + ' with animation-name: none');
+
+  div.style.animation = 'none 100s, anim1 100s';
+  animations = div.getAnimations();
+  assert_equals(animations.length, 1,
+    'getAnimations returns Animations only for those CSS Animations whose'
+    + ' animation-name is not none');
+}, 'getAnimations for CSS Animations with animation-name: none');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'missing 100s';
+  var animations = div.getAnimations();
+  assert_equals(animations.length, 0,
+    'getAnimations returns an empty sequence for an element'
+    + ' with animation-name: missing');
+
+  div.style.animation = 'anim1 100s, missing 100s';
+  animations = div.getAnimations();
+  assert_equals(animations.length, 1,
+    'getAnimations returns Animations only for those CSS Animations whose'
+    + ' animation-name is found');
+}, 'getAnimations for CSS Animations with animation-name: missing');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim1 100s, notyet 100s';
+  var animations = div.getAnimations();
+  assert_equals(animations.length, 1,
+    'getAnimations initally only returns Animations for CSS Animations whose'
+    + ' animation-name is found');
+
+  animations[0].ready.then(waitForFrame).then(t.step_func(function() {
+    var keyframes = '@keyframes notyet { to { left: 100px; } }';
+    document.styleSheets[0].insertRule(keyframes, 0);
+    animations = div.getAnimations();
+    assert_equals(animations.length, 2,
+      'getAnimations includes Animation when @keyframes rule is added'
+      + ' later');
+    return waitForAllAnimations(animations);
+  })).then(t.step_func(function() {
+    assert_true(animations[0].startTime < animations[1].startTime,
+      'Newly added animation has a later start time');
+    document.styleSheets[0].deleteRule(0);
+    t.done();
+  }));
+}, 'getAnimations for CSS Animations where the @keyframes rule is added'
+   + ' later');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim1 100s, anim1 100s';
+  assert_equals(div.getAnimations().length, 2,
+    'getAnimations returns one Animation for each CSS animation-name'
+    + ' even if the names are duplicated');
+}, 'getAnimations for CSS Animations with duplicated animation-name');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'empty 100s';
+  assert_equals(div.getAnimations().length, 1,
+    'getAnimations returns Animations for CSS animations with an'
+    + ' empty keyframes rule');
+}, 'getAnimations for CSS Animations with empty keyframes rule');
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim1 100s 100s';
+  var animations = div.getAnimations();
+  assert_equals(animations.length, 1,
+    'getAnimations returns animations for CSS animations whose'
+    + ' delay makes them start later');
+  animations[0].ready.then(waitForFrame).then(t.step_func(function() {
+    assert_true(animations[0].startTime <= document.timeline.currentTime,
+      'For CSS Animations in delay phase, the start time of the Animation is'
+      + ' not in the future');
+    t.done();
+  }));
+}, 'getAnimations for CSS animations in delay phase');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim1 0s 100s';
+  assert_equals(div.getAnimations().length, 1,
+    'getAnimations returns animations for CSS animations whose'
+    + ' duration is zero');
+  div.remove();
+}, 'getAnimations for zero-duration CSS Animations');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim1 100s';
+  var originalAnimation = div.getAnimations()[0];
+
+  // Update pause state (an Animation change)
+  div.style.animationPlayState = 'paused';
+  var pendingAnimation = div.getAnimations()[0];
+  assert_equals(pendingAnimation.playState, 'pending',
+                'animation\'s play state is updated');
+  assert_equals(originalAnimation, pendingAnimation,
+                'getAnimations returns the same objects even when their'
+                + ' play state changes');
+
+  // Update duration (an Animation change)
+  div.style.animationDuration = '200s';
+  var extendedAnimation = div.getAnimations()[0];
+  // FIXME: Check extendedAnimation.effect.timing.duration has changed once the
+  // API is available
+  assert_equals(originalAnimation, extendedAnimation,
+                'getAnimations returns the same objects even when their'
+                + ' duration changes');
+}, 'getAnimations returns objects with the same identity');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim1 100s';
+
+  assert_equals(div.getAnimations().length, 1,
+    'getAnimations returns an animation before cancelling');
+
+  var animation = div.getAnimations()[0];
+
+  animation.cancel();
+  assert_equals(div.getAnimations().length, 0,
+    'getAnimations does not return cancelled animations');
+
+  animation.play();
+  assert_equals(div.getAnimations().length, 1,
+    'getAnimations returns cancelled animations that have been re-started');
+
+}, 'getAnimations for CSS Animations that are cancelled');
+
 </script>
-</html>
deleted file mode 100644
--- a/dom/animation/test/css-transitions/file_animation-cancel.html
+++ /dev/null
@@ -1,128 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<body>
-<script>
-'use strict';
-
-async_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.ready.then(waitForFrame).then(t.step_func(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');
-    t.done();
-  }));
-}, 'Animated style is cleared after cancelling a running CSS transition');
-
-async_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', t.step_func(function() {
-    assert_unreached('Got unexpected end event on cancelled transition');
-  }));
-
-  var animation = div.getAnimations()[0];
-  animation.ready.then(t.step_func(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);
-  })).then(t.step_func(function() {
-    t.done();
-  }));
-}, 'Cancelled CSS transitions do not dispatch events');
-
-async_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.ready.then(t.step_func(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(t.step_func(function() {
-    assert_equals(animation.playState, 'running',
-                  'Transition succeeds in running after being re-started');
-    t.done();
-  }));
-}, 'After cancelling a transition, it can still be re-used');
-
-async_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.ready.then(t.step_func(function() {
-    animation.finish();
-    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(t.step_func(function() {
-    assert_equals(animation.playState, 'running',
-                  'Transition succeeds in running after being re-started');
-    t.done();
-  }));
-}, '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
-  div.style.transitionDuration = '200s';
-  flushComputedStyle(div);
-  assert_equals(getComputedStyle(div).marginLeft, '1000px',
-                'margin-left style is still not animated after updating'
-                + ' transition-duration');
-  assert_equals(animation.playState, 'idle',
-                'Transition is still idle after updating transition-duration');
-}, 'After cancelling a transition, updating transition properties doesn\'t make'
-   + ' it live again');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-transitions/file_animation-currenttime.html
+++ /dev/null
@@ -1,313 +0,0 @@
-<!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: add equivalent tests without an animation-delay, but first we need to
-// change the timing of animationstart dispatch. (Right now the animationstart
-// event will fire before the ready Promise is resolved if there is no
-// animation-delay.)
-// See https://bugzilla.mozilla.org/show_bug.cgi?id=1134163
-
-// 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>
deleted file mode 100644
--- a/dom/animation/test/css-transitions/file_animation-finished.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-
-.animated-div {
-  margin-left: 100px;
-  transition: margin-left 1000s linear 1000s;
-}
-
-</style>
-<body>
-<script>
-
-'use strict';
-
-const ANIM_DELAY_MS = 1000000; // 1000s
-const ANIM_DUR_MS = 1000000; // 1000s
-
-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.finish();
-
-  animation.finished.then(t.step_func(function() {
-    animation.play();
-    assert_equals(animation.currentTime, 0,
-                  'Replaying a finished transition should reset its ' +
-                  'currentTime');
-    t.done();
-  }));
-}, 'Test restarting a finished 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(function() {
-    animation.playbackRate = -1;
-    return animation.finished;
-  }).then(t.step_func(function() {
-    animation.play();
-    // FIXME: once animation.effect.computedTiming.endTime is available (bug
-    // 1108055) we should use that here.
-    assert_equals(animation.currentTime, ANIM_DELAY_MS + ANIM_DUR_MS,
-                  'Replaying a finished reversed transition should reset ' +
-                  'its currentTime to the end of the effect');
-    t.done();
-  }));
-}, 'Test restarting a reversed finished transition');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-transitions/file_animation-pausing.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<body>
-<script>
-'use strict';
-
-function getMarginLeft(cs) {
-  return parseFloat(cs.marginLeft);
-}
-
-async_test(function(t) {
-  var div = addDiv(t);
-  var cs = window.getComputedStyle(div);
-
-  div.style.marginLeft = '0px';
-  cs.marginLeft; // Flush style to set up transition start point
-  div.style.transition = 'margin-left 100s';
-  div.style.marginLeft = '10000px';
-  cs.marginLeft;
-
-  var animation = div.getAnimations()[0];
-  assert_equals(getMarginLeft(cs), 0,
-                'Initial value of margin-left is zero');
-  var previousAnimVal = getMarginLeft(cs);
-
-  animation.ready.then(waitForFrame).then(t.step_func(function() {
-    assert_true(getMarginLeft(cs) > previousAnimVal,
-                'margin-left is initially increasing');
-    animation.pause();
-    return animation.ready;
-  })).then(t.step_func(function() {
-    previousAnimVal = getMarginLeft(cs);
-    return waitForFrame();
-  })).then(t.step_func(function() {
-    assert_equals(getMarginLeft(cs), previousAnimVal,
-                  'margin-left does not increase after calling pause()');
-    previousAnimVal = getMarginLeft(cs);
-    animation.play();
-    return animation.ready.then(waitForFrame);
-  })).then(t.step_func(function() {
-    assert_true(getMarginLeft(cs) > previousAnimVal,
-                'margin-left increases after calling play()');
-    t.done();
-  }));
-}, 'pause() and play() a transition');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-transitions/file_animation-ready.html
+++ /dev/null
@@ -1,96 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<body>
-<script>
-'use strict';
-
-async_test(function(t) {
-  var div = addDiv(t);
-  div.style.transform = 'translate(0px)';
-  window.getComputedStyle(div).transform;
-  div.style.transition = 'transform 100s';
-  div.style.transform = 'translate(10px)';
-  window.getComputedStyle(div).transform;
-
-  var animation = div.getAnimations()[0];
-  var originalReadyPromise = animation.ready;
-
-  animation.ready.then(t.step_func(function() {
-    assert_equals(animation.ready, originalReadyPromise,
-                  'Ready promise is the same object when playing completes');
-    animation.pause();
-    assert_not_equals(animation.ready, originalReadyPromise,
-                      'Ready promise object identity differs when pausing');
-    t.done();
-  }));
-}, 'A new ready promise is created each time play() is called'
-   + ' the animation property');
-
-async_test(function(t) {
-  var div = addDiv(t);
-
-  // Set up pending transition
-  div.style.transform = 'translate(0px)';
-  window.getComputedStyle(div).transform;
-  div.style.transition = 'transform 100s';
-  div.style.transform = 'translate(10px)';
-  window.getComputedStyle(div).transform;
-
-  var animation = div.getAnimations()[0];
-  assert_equals(animation.playState, 'pending', 'Animation is initially pending');
-
-  // Set up listeners on ready promise
-  animation.ready.then(t.step_func(function() {
-    assert_unreached('ready promise was fulfilled');
-  })).catch(t.step_func(function(err) {
-    assert_equals(err.name, 'AbortError',
-                  'ready promise is rejected with AbortError');
-    assert_equals(animation.playState, 'idle',
-                  'Animation is idle after transition was cancelled');
-  })).then(t.step_func(function() {
-    t.done();
-  }));
-
-  // Now remove transform from transition-property and flush styles
-  div.style.transitionProperty = 'none';
-  window.getComputedStyle(div).transitionProperty;
-
-}, 'ready promise is rejected when a transition is cancelled by updating'
-   + ' transition-property');
-
-async_test(function(t) {
-  var div = addDiv(t);
-
-  // Set up pending transition
-  div.style.marginLeft = '0px';
-  window.getComputedStyle(div).marginLeft;
-  div.style.transition = 'margin-left 100s';
-  div.style.marginLeft = '100px';
-  window.getComputedStyle(div).marginLeft;
-
-  var animation = div.getAnimations()[0];
-  assert_equals(animation.playState, 'pending', 'Animation is initially pending');
-
-  // Set up listeners on ready promise
-  animation.ready.then(t.step_func(function() {
-    assert_unreached('ready promise was fulfilled');
-  })).catch(t.step_func(function(err) {
-    assert_equals(err.name, 'AbortError',
-                  'ready promise is rejected with AbortError');
-    assert_equals(animation.playState, 'idle',
-                  'Animation is idle after transition was cancelled');
-  })).then(t.step_func(function() {
-    t.done();
-  }));
-
-  // Now update the transition to animate to something not-interpolable
-  div.style.marginLeft = 'auto';
-  window.getComputedStyle(div).marginLeft;
-
-}, 'ready promise is rejected when a transition is cancelled by changing'
-   + ' the transition property to something not interpolable');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-transitions/file_animation-starttime.html
+++ /dev/null
@@ -1,290 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset=utf-8>
-    <title>Tests for the effect of setting a CSS transition's
-           Animation.startTime</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: add equivalent tests without an animation-delay, but first we need to
-// change the timing of animationstart dispatch. (Right now the animationstart
-// event will fire before the ready Promise is resolved if there is no
-// animation-delay.)
-// See https://bugzilla.mozilla.org/show_bug.cgi?id=1134163
-
-// 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 startTime 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 startTimeForBeforePhase(timeline) {
-  return timeline.currentTime - ANIM_DELAY_MS / 2;
-}
-function startTimeForActivePhase(timeline) {
-  return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS / 2;
-}
-function startTimeForAfterPhase(timeline) {
-  return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS - ANIM_DELAY_MS / 2;
-}
-function startTimeForStartOfActiveInterval(timeline) {
-  return timeline.currentTime - ANIM_DELAY_MS;
-}
-function startTimeForFiftyPercentThroughActiveInterval(timeline) {
-  return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.5;
-}
-function startTimeForEndOfActiveInterval(timeline) {
-  return timeline.currentTime - 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:
-//
-//   https://w3c.github.io/web-animations/#animation-effect-phases-and-states
-//
-// Note the distinction between the "animation start time" which occurs before
-// the start delay and the start of the active interval which occurs after it.
-
-// Called when the ready Promise's callbacks should happen
-function checkStateOnReadyPromiseResolved(animation)
-{
-  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');
-
-  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 startTime is set to the time the active interval starts.
-function checkStateAtActiveIntervalStartTime(animation)
-{
-  // We don't test animation.startTime 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.startTime 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 startTime is set to the time the active interval ends.
-function checkStateAtActiveIntervalEndTime(animation)
-{
-  // We don't test animation.startTime 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.startTime, null, 'startTime is unresolved');
-}, 'startTime of a newly created transition is unresolved');
-
-
-test(function(t)
-{
-  var div = addDiv(t, {'class': 'animated-div'});
-  flushComputedStyle(div);
-  div.style.marginLeft = '200px'; // initiate transition
-
-  var animation = div.getAnimations()[0];
-  var currentTime = animation.timeline.currentTime;
-  animation.startTime = currentTime;
-  assert_approx_equals(animation.startTime, currentTime, 0.0001, // rounding error
-    'Check setting of startTime actually works');
-}, 'Sanity test to check round-tripping assigning to new animation\'s ' +
-   'startTime');
-
-
-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.startTime = startTimeForStartOfActiveInterval(animation.timeline);
-    checkStateAtActiveIntervalStartTime(animation);
-
-    animation.startTime =
-      startTimeForFiftyPercentThroughActiveInterval(animation.timeline);
-    checkStateAtFiftyPctOfActiveInterval(animation);
-
-    animation.startTime = startTimeForEndOfActiveInterval(animation.timeline);
-    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 animation');
-
-
-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 90% through point.
-
-  animation.startTime =
-    startTimeForFiftyPercentThroughActiveInterval(animation.timeline);
-  checkStateAtFiftyPctOfActiveInterval(animation);
-
-  animation.startTime = startTimeForStartOfActiveInterval(animation.timeline);
-
-  // Despite going backwards from being in the active interval to being before
-  // it, we now expect an 'animationend' event because the animation 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 waitForEvent 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];
-
-  var storedCurrentTime;
-
-  animation.ready.then(t.step_func(function() {
-    storedCurrentTime = animation.currentTime;
-    animation.startTime = null;
-    return animation.ready;
-  })).catch(t.step_func(function(reason) {
-    assert_unreached(reason);
-  })).then(t.step_func(function() {
-    assert_equals(animation.currentTime, storedCurrentTime,
-      'Test that hold time is correct');
-    t.done();
-  }));
-}, 'Setting startTime 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];
-
-  animation.ready.then(t.step_func(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(t.step_func(function() {
-    assert_equals(animation.startTime, null,
-      'Animation.startTime is null after paused');
-    assert_equals(animation.playState, 'paused',
-      'Animation.playState is "paused" after pause() call');
-  })).catch(t.step_func(function(reason) {
-    assert_unreached(reason);
-  })).then(function() {
-    t.done();
-  });
-}, 'Animation.startTime after paused');
-
-done();
-    </script>
-  </body>
-</html>
deleted file mode 100644
--- a/dom/animation/test/css-transitions/file_effect-name.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<body>
-<script>
-'use strict';
-
-test(function(t) {
-  var div = addDiv(t);
-
-  // Add a transition
-  div.style.left = '0px';
-  window.getComputedStyle(div).transitionProperty;
-  div.style.transition = 'all 100s';
-  div.style.left = '100px';
-
-  assert_equals(div.getAnimations()[0].effect.name, 'left',
-                'The name for the transitions corresponds to the property ' +
-                'being transitioned');
-}, 'Effect name for transitions');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-transitions/file_effect-target.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<body>
-<script>
-'use strict';
-
-test(function(t) {
-  var div = addDiv(t);
-
-  div.style.left = '0px';
-  window.getComputedStyle(div).transitionProperty;
-  div.style.transition = 'left 100s';
-  div.style.left = '100px';
-
-  var animation = div.getAnimations()[0];
-  assert_equals(animation.effect.target, div,
-    'Animation.target is the animatable div');
-}, 'Returned CSS transitions have the correct Animation.target');
-
-done();
-</script>
-</body>
deleted file mode 100644
--- a/dom/animation/test/css-transitions/file_element-get-animations.html
+++ /dev/null
@@ -1,94 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<body>
-<script>
-'use strict';
-
-async_test(function(t) {
-  var div = addDiv(t);
-
-  // Add a couple of transitions
-  div.style.left = '0px';
-  div.style.top = '0px';
-  window.getComputedStyle(div).transitionProperty;
-
-  div.style.transition = 'all 100s';
-  div.style.left = '100px';
-  div.style.top = '100px';
-
-  var animations = div.getAnimations();
-  assert_equals(animations.length, 2,
-    'getAnimations() returns one Animation per transitioning property');
-  waitForAllAnimations(animations).then(t.step_func(function() {
-    var startTime = animations[0].startTime;
-    assert_true(startTime > 0 && startTime <= document.timeline.currentTime,
-                'CSS transitions have sensible start times');
-    assert_equals(animations[0].startTime, animations[1].startTime,
-      'CSS transitions started together have the same start time');
-    // Wait a moment then add a third transition
-    return waitForFrame();
-  })).then(t.step_func(function() {
-    div.style.backgroundColor = 'green';
-    animations = div.getAnimations();
-    assert_equals(animations.length, 3,
-      'getAnimations returns Animations for all running CSS Transitions');
-    return waitForAllAnimations(animations);
-  })).then(t.step_func(function() {
-    assert_true(animations[1].startTime < animations[2].startTime,
-      'Animation for additional CSS transition starts after the original'
-      + ' transitions and appears later in the list');
-    t.done();
-  }));
-}, 'getAnimations for CSS Transitions');
-
-async_test(function(t) {
-  var div = addDiv(t);
-
-  // Set up event listener
-  div.addEventListener('transitionend', t.step_func(function() {
-    assert_equals(div.getAnimations().length, 0,
-      'getAnimations does not return finished CSS Transitions');
-    t.done();
-  }));
-
-  // Add a very short transition
-  div.style.left = '0px';
-  window.getComputedStyle(div).left;
-
-  div.style.transition = 'all 0.01s';
-  div.style.left = '100px';
-  window.getComputedStyle(div).left;
-}, 'getAnimations for CSS Transitions that have finished');
-
-test(function(t) {
-  var div = addDiv(t);
-
-  // Try to transition non-animatable property animation-duration
-  div.style.animationDuration = '10s';
-  window.getComputedStyle(div).animationDuration;
-
-  div.style.transition = 'all 100s';
-  div.style.animationDuration = '100s';
-
-  assert_equals(div.getAnimations().length, 0,
-    'getAnimations returns an empty sequence for a transition'
-    + ' of a non-animatable property');
-}, 'getAnimations for transition on non-animatable property');
-
-test(function(t) {
-  var div = addDiv(t);
-
-  div.style.setProperty('-vendor-unsupported', '0px', '');
-  window.getComputedStyle(div).transitionProperty;
-  div.style.transition = 'all 100s';
-  div.style.setProperty('-vendor-unsupported', '100px', '');
-
-  assert_equals(div.getAnimations().length, 0,
-    'getAnimations returns an empty sequence for a transition'
-    + ' of an unsupported property');
-}, 'getAnimations for transition on unsupported property');
-
-done();
-</script>
-</body>
--- a/dom/animation/test/css-transitions/test_animation-cancel.html
+++ b/dom/animation/test/css-transitions/test_animation-cancel.html
@@ -1,14 +1,129 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.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_animation-cancel.html");
-  });
+
+async_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.ready.then(waitForFrame).then(t.step_func(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');
+    t.done();
+  }));
+}, 'Animated style is cleared after cancelling a running CSS transition');
+
+async_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', t.step_func(function() {
+    assert_unreached('Got unexpected end event on cancelled transition');
+  }));
+
+  var animation = div.getAnimations()[0];
+  animation.ready.then(t.step_func(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);
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+}, 'Cancelled CSS transitions do not dispatch events');
+
+async_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.ready.then(t.step_func(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(t.step_func(function() {
+    assert_equals(animation.playState, 'running',
+                  'Transition succeeds in running after being re-started');
+    t.done();
+  }));
+}, 'After cancelling a transition, it can still be re-used');
+
+async_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.ready.then(t.step_func(function() {
+    animation.finish();
+    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(t.step_func(function() {
+    assert_equals(animation.playState, 'running',
+                  'Transition succeeds in running after being re-started');
+    t.done();
+  }));
+}, '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
+  div.style.transitionDuration = '200s';
+  flushComputedStyle(div);
+  assert_equals(getComputedStyle(div).marginLeft, '1000px',
+                'margin-left style is still not animated after updating'
+                + ' transition-duration');
+  assert_equals(animation.playState, 'idle',
+                'Transition is still idle after updating transition-duration');
+}, 'After cancelling a transition, updating transition properties doesn\'t make'
+   + ' it live again');
+
 </script>
+</html>
--- a/dom/animation/test/css-transitions/test_animation-currenttime.html
+++ b/dom/animation/test/css-transitions/test_animation-currenttime.html
@@ -1,14 +1,315 @@
 <!doctype html>
-<meta charset=utf-8>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id="log"></div>
-<script>
+<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="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="../testcommon.js"></script>
+  </head>
+  <body>
+    <div id="log"></div>
+    <script type="text/javascript">
+
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animation-currenttime.html");
+
+// TODO: add equivalent tests without an animation-delay, but first we need to
+// change the timing of animationstart dispatch. (Right now the animationstart
+// event will fire before the ready Promise is resolved if there is no
+// animation-delay.)
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=1134163
+
+// 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();
   });
-</script>
+}, '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');
+
+    </script>
+  </body>
+</html>
--- a/dom/animation/test/css-transitions/test_animation-finished.html
+++ b/dom/animation/test/css-transitions/test_animation-finished.html
@@ -1,14 +1,61 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
 <div id="log"></div>
+<style>
+
+.animated-div {
+  margin-left: 100px;
+  transition: margin-left 1000s linear 1000s;
+}
+
+</style>
 <script>
+
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animation-finished.html");
-  });
+
+const ANIM_DELAY_MS = 1000000; // 1000s
+const ANIM_DUR_MS = 1000000; // 1000s
+
+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.finish();
+
+  animation.finished.then(t.step_func(function() {
+    animation.play();
+    assert_equals(animation.currentTime, 0,
+                  'Replaying a finished transition should reset its ' +
+                  'currentTime');
+    t.done();
+  }));
+}, 'Test restarting a finished 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(function() {
+    animation.playbackRate = -1;
+    return animation.finished;
+  }).then(t.step_func(function() {
+    animation.play();
+    // FIXME: once animation.effect.computedTiming.endTime is available (bug
+    // 1108055) we should use that here.
+    assert_equals(animation.currentTime, ANIM_DELAY_MS + ANIM_DUR_MS,
+                  'Replaying a finished reversed transition should reset ' +
+                  'its currentTime to the end of the effect');
+    t.done();
+  }));
+}, 'Test restarting a reversed finished transition');
+
 </script>
--- a/dom/animation/test/css-transitions/test_animation-pausing.html
+++ b/dom/animation/test/css-transitions/test_animation-pausing.html
@@ -1,14 +1,50 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.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_animation-pausing.html");
-  });
+
+function getMarginLeft(cs) {
+  return parseFloat(cs.marginLeft);
+}
+
+async_test(function(t) {
+  var div = addDiv(t);
+  var cs = window.getComputedStyle(div);
+
+  div.style.marginLeft = '0px';
+  cs.marginLeft; // Flush style to set up transition start point
+  div.style.transition = 'margin-left 100s';
+  div.style.marginLeft = '10000px';
+  cs.marginLeft;
+
+  var animation = div.getAnimations()[0];
+  assert_equals(getMarginLeft(cs), 0,
+                'Initial value of margin-left is zero');
+  var previousAnimVal = getMarginLeft(cs);
+
+  animation.ready.then(waitForFrame).then(t.step_func(function() {
+    assert_true(getMarginLeft(cs) > previousAnimVal,
+                'margin-left is initially increasing');
+    animation.pause();
+    return animation.ready;
+  })).then(t.step_func(function() {
+    previousAnimVal = getMarginLeft(cs);
+    return waitForFrame();
+  })).then(t.step_func(function() {
+    assert_equals(getMarginLeft(cs), previousAnimVal,
+                  'margin-left does not increase after calling pause()');
+    previousAnimVal = getMarginLeft(cs);
+    animation.play();
+    return animation.ready.then(waitForFrame);
+  })).then(t.step_func(function() {
+    assert_true(getMarginLeft(cs) > previousAnimVal,
+                'margin-left increases after calling play()');
+    t.done();
+  }));
+}, 'pause() and play() a transition');
+
 </script>
--- a/dom/animation/test/css-transitions/test_animation-ready.html
+++ b/dom/animation/test/css-transitions/test_animation-ready.html
@@ -1,14 +1,96 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.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_animation-ready.html");
-  });
+
+async_test(function(t) {
+  var div = addDiv(t);
+  div.style.transform = 'translate(0px)';
+  window.getComputedStyle(div).transform;
+  div.style.transition = 'transform 100s';
+  div.style.transform = 'translate(10px)';
+  window.getComputedStyle(div).transform;
+
+  var animation = div.getAnimations()[0];
+  var originalReadyPromise = animation.ready;
+
+  animation.ready.then(t.step_func(function() {
+    assert_equals(animation.ready, originalReadyPromise,
+                  'Ready promise is the same object when playing completes');
+    animation.pause();
+    assert_not_equals(animation.ready, originalReadyPromise,
+                      'Ready promise object identity differs when pausing');
+    t.done();
+  }));
+}, 'A new ready promise is created each time play() is called'
+   + ' the animation property');
+
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // Set up pending transition
+  div.style.transform = 'translate(0px)';
+  window.getComputedStyle(div).transform;
+  div.style.transition = 'transform 100s';
+  div.style.transform = 'translate(10px)';
+  window.getComputedStyle(div).transform;
+
+  var animation = div.getAnimations()[0];
+  assert_equals(animation.playState, 'pending', 'Animation is initially pending');
+
+  // Set up listeners on ready promise
+  animation.ready.then(t.step_func(function() {
+    assert_unreached('ready promise was fulfilled');
+  })).catch(t.step_func(function(err) {
+    assert_equals(err.name, 'AbortError',
+                  'ready promise is rejected with AbortError');
+    assert_equals(animation.playState, 'idle',
+                  'Animation is idle after transition was cancelled');
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+
+  // Now remove transform from transition-property and flush styles
+  div.style.transitionProperty = 'none';
+  window.getComputedStyle(div).transitionProperty;
+
+}, 'ready promise is rejected when a transition is cancelled by updating'
+   + ' transition-property');
+
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // Set up pending transition
+  div.style.marginLeft = '0px';
+  window.getComputedStyle(div).marginLeft;
+  div.style.transition = 'margin-left 100s';
+  div.style.marginLeft = '100px';
+  window.getComputedStyle(div).marginLeft;
+
+  var animation = div.getAnimations()[0];
+  assert_equals(animation.playState, 'pending', 'Animation is initially pending');
+
+  // Set up listeners on ready promise
+  animation.ready.then(t.step_func(function() {
+    assert_unreached('ready promise was fulfilled');
+  })).catch(t.step_func(function(err) {
+    assert_equals(err.name, 'AbortError',
+                  'ready promise is rejected with AbortError');
+    assert_equals(animation.playState, 'idle',
+                  'Animation is idle after transition was cancelled');
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+
+  // Now update the transition to animate to something not-interpolable
+  div.style.marginLeft = 'auto';
+  window.getComputedStyle(div).marginLeft;
+
+}, 'ready promise is rejected when a transition is cancelled by changing'
+   + ' the transition property to something not interpolable');
+
 </script>
--- a/dom/animation/test/css-transitions/test_animation-starttime.html
+++ b/dom/animation/test/css-transitions/test_animation-starttime.html
@@ -1,14 +1,292 @@
 <!doctype html>
-<meta charset=utf-8>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id="log"></div>
-<script>
+<html>
+  <head>
+    <meta charset=utf-8>
+    <title>Tests for the effect of setting a CSS transition's
+           Animation.startTime</title>
+    <style>
+
+.animated-div {
+  margin-left: 100px;
+  transition: margin-left 1000s linear 1000s;
+}
+
+    </style>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="../testcommon.js"></script>
+  </head>
+  <body>
+    <div id="log"></div>
+    <script type="text/javascript">
+
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animation-starttime.html");
+
+// TODO: add equivalent tests without an animation-delay, but first we need to
+// change the timing of animationstart dispatch. (Right now the animationstart
+// event will fire before the ready Promise is resolved if there is no
+// animation-delay.)
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=1134163
+
+// 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 startTime 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 startTimeForBeforePhase(timeline) {
+  return timeline.currentTime - ANIM_DELAY_MS / 2;
+}
+function startTimeForActivePhase(timeline) {
+  return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS / 2;
+}
+function startTimeForAfterPhase(timeline) {
+  return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS - ANIM_DELAY_MS / 2;
+}
+function startTimeForStartOfActiveInterval(timeline) {
+  return timeline.currentTime - ANIM_DELAY_MS;
+}
+function startTimeForFiftyPercentThroughActiveInterval(timeline) {
+  return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.5;
+}
+function startTimeForEndOfActiveInterval(timeline) {
+  return timeline.currentTime - 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:
+//
+//   https://w3c.github.io/web-animations/#animation-effect-phases-and-states
+//
+// Note the distinction between the "animation start time" which occurs before
+// the start delay and the start of the active interval which occurs after it.
+
+// Called when the ready Promise's callbacks should happen
+function checkStateOnReadyPromiseResolved(animation)
+{
+  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');
+
+  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 startTime is set to the time the active interval starts.
+function checkStateAtActiveIntervalStartTime(animation)
+{
+  // We don't test animation.startTime 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.startTime 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 startTime is set to the time the active interval ends.
+function checkStateAtActiveIntervalEndTime(animation)
+{
+  // We don't test animation.startTime 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.startTime, null, 'startTime is unresolved');
+}, 'startTime of a newly created transition is unresolved');
+
+
+test(function(t)
+{
+  var div = addDiv(t, {'class': 'animated-div'});
+  flushComputedStyle(div);
+  div.style.marginLeft = '200px'; // initiate transition
+
+  var animation = div.getAnimations()[0];
+  var currentTime = animation.timeline.currentTime;
+  animation.startTime = currentTime;
+  assert_approx_equals(animation.startTime, currentTime, 0.0001, // rounding error
+    'Check setting of startTime actually works');
+}, 'Sanity test to check round-tripping assigning to new animation\'s ' +
+   'startTime');
+
+
+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.startTime = startTimeForStartOfActiveInterval(animation.timeline);
+    checkStateAtActiveIntervalStartTime(animation);
+
+    animation.startTime =
+      startTimeForFiftyPercentThroughActiveInterval(animation.timeline);
+    checkStateAtFiftyPctOfActiveInterval(animation);
+
+    animation.startTime = startTimeForEndOfActiveInterval(animation.timeline);
+    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();
   });
-</script>
+}, 'Skipping forward through animation');
+
+
+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 90% through point.
+
+  animation.startTime =
+    startTimeForFiftyPercentThroughActiveInterval(animation.timeline);
+  checkStateAtFiftyPctOfActiveInterval(animation);
+
+  animation.startTime = startTimeForStartOfActiveInterval(animation.timeline);
+
+  // Despite going backwards from being in the active interval to being before
+  // it, we now expect an 'animationend' event because the animation 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 waitForEvent 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];
+
+  var storedCurrentTime;
+
+  animation.ready.then(t.step_func(function() {
+    storedCurrentTime = animation.currentTime;
+    animation.startTime = null;
+    return animation.ready;
+  })).catch(t.step_func(function(reason) {
+    assert_unreached(reason);
+  })).then(t.step_func(function() {
+    assert_equals(animation.currentTime, storedCurrentTime,
+      'Test that hold time is correct');
+    t.done();
+  }));
+}, 'Setting startTime 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];
+
+  animation.ready.then(t.step_func(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(t.step_func(function() {
+    assert_equals(animation.startTime, null,
+      'Animation.startTime is null after paused');
+    assert_equals(animation.playState, 'paused',
+      'Animation.playState is "paused" after pause() call');
+  })).catch(t.step_func(function(reason) {
+    assert_unreached(reason);
+  })).then(function() {
+    t.done();
+  });
+}, 'Animation.startTime after paused');
+
+    </script>
+  </body>
+</html>
--- a/dom/animation/test/css-transitions/test_effect-name.html
+++ b/dom/animation/test/css-transitions/test_effect-name.html
@@ -1,14 +1,24 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.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_effect-name.html");
-  });
+
+test(function(t) {
+  var div = addDiv(t);
+
+  // Add a transition
+  div.style.left = '0px';
+  window.getComputedStyle(div).transitionProperty;
+  div.style.transition = 'all 100s';
+  div.style.left = '100px';
+
+  assert_equals(div.getAnimations()[0].effect.name, 'left',
+                'The name for the transitions corresponds to the property ' +
+                'being transitioned');
+}, 'Effect name for transitions');
+
 </script>
--- a/dom/animation/test/css-transitions/test_effect-target.html
+++ b/dom/animation/test/css-transitions/test_effect-target.html
@@ -1,14 +1,23 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.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_effect-target.html");
-  });
+
+test(function(t) {
+  var div = addDiv(t);
+
+  div.style.left = '0px';
+  window.getComputedStyle(div).transitionProperty;
+  div.style.transition = 'left 100s';
+  div.style.left = '100px';
+
+  var animation = div.getAnimations()[0];
+  assert_equals(animation.effect.target, div,
+    'Animation.target is the animatable div');
+}, 'Returned CSS transitions have the correct Animation.target');
+
 </script>
--- a/dom/animation/test/css-transitions/test_element-get-animations.html
+++ b/dom/animation/test/css-transitions/test_element-get-animations.html
@@ -1,14 +1,94 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.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_element-get-animations.html");
-  });
+
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // Add a couple of transitions
+  div.style.left = '0px';
+  div.style.top = '0px';
+  window.getComputedStyle(div).transitionProperty;
+
+  div.style.transition = 'all 100s';
+  div.style.left = '100px';
+  div.style.top = '100px';
+
+  var animations = div.getAnimations();
+  assert_equals(animations.length, 2,
+    'getAnimations() returns one Animation per transitioning property');
+  waitForAllAnimations(animations).then(t.step_func(function() {
+    var startTime = animations[0].startTime;
+    assert_true(startTime > 0 && startTime <= document.timeline.currentTime,
+                'CSS transitions have sensible start times');
+    assert_equals(animations[0].startTime, animations[1].startTime,
+      'CSS transitions started together have the same start time');
+    // Wait a moment then add a third transition
+    return waitForFrame();
+  })).then(t.step_func(function() {
+    div.style.backgroundColor = 'green';
+    animations = div.getAnimations();
+    assert_equals(animations.length, 3,
+      'getAnimations returns Animations for all running CSS Transitions');
+    return waitForAllAnimations(animations);
+  })).then(t.step_func(function() {
+    assert_true(animations[1].startTime < animations[2].startTime,
+      'Animation for additional CSS transition starts after the original'
+      + ' transitions and appears later in the list');
+    t.done();
+  }));
+}, 'getAnimations for CSS Transitions');
+
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // Set up event listener
+  div.addEventListener('transitionend', t.step_func(function() {
+    assert_equals(div.getAnimations().length, 0,
+      'getAnimations does not return finished CSS Transitions');
+    t.done();
+  }));
+
+  // Add a very short transition
+  div.style.left = '0px';
+  window.getComputedStyle(div).left;
+
+  div.style.transition = 'all 0.01s';
+  div.style.left = '100px';
+  window.getComputedStyle(div).left;
+}, 'getAnimations for CSS Transitions that have finished');
+
+test(function(t) {
+  var div = addDiv(t);
+
+  // Try to transition non-animatable property animation-duration
+  div.style.animationDuration = '10s';
+  window.getComputedStyle(div).animationDuration;
+
+  div.style.transition = 'all 100s';
+  div.style.animationDuration = '100s';
+
+  assert_equals(div.getAnimations().length, 0,
+    'getAnimations returns an empty sequence for a transition'
+    + ' of a non-animatable property');
+}, 'getAnimations for transition on non-animatable property');
+
+test(function(t) {
+  var div = addDiv(t);
+
+  div.style.setProperty('-vendor-unsupported', '0px', '');
+  window.getComputedStyle(div).transitionProperty;
+  div.style.transition = 'all 100s';
+  div.style.setProperty('-vendor-unsupported', '100px', '');
+
+  assert_equals(div.getAnimations().length, 0,
+    'getAnimations returns an empty sequence for a transition'
+    + ' of an unsupported property');
+}, 'getAnimations for transition on unsupported property');
+
 </script>
deleted file mode 100644
--- a/dom/animation/test/document-timeline/file_document-timeline.html
+++ /dev/null
@@ -1,135 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>Web Animations API: DocumentTimeline tests</title>
-<script src="../testcommon.js"></script>
-<iframe src="data:text/html;charset=utf-8," width="10" height="10" id="iframe"></iframe>
-<iframe src="data:text/html;charset=utf-8,%3Chtml%20style%3D%22display%3Anone%22%3E%3C%2Fhtml%3E" width="10" height="10" id="hidden-iframe"></iframe>
-<script>
-'use strict';
-
-test(function() {
-  assert_equals(document.timeline, document.timeline,
-    'document.timeline returns the same object every time');
-  var iframe = document.getElementById('iframe');
-  assert_not_equals(document.timeline, iframe.contentDocument.timeline,
-    'document.timeline returns a different object for each document');
-  assert_not_equals(iframe.contentDocument.timeline, null,
-    'document.timeline on an iframe is not null');
-},
-'document.timeline identity tests',
-{
-  help:   'http://dev.w3.org/fxtf/web-animations/#the-document-timeline',
-  assert: [ 'Each document has a timeline called the document timeline' ],
-  author: 'Brian Birtles'
-});
-
-async_test(function(t) {
-  assert_true(document.timeline.currentTime > 0,
-    'document.timeline.currentTime is positive');
-  // document.timeline.currentTime should be set even before document
-  // load fires. We expect this code to be run before document load and hence
-  // the above assertion is sufficient.
-  // If the following assertion fails, this test needs to be redesigned.
-  assert_true(document.readyState !== 'complete',
-    'Test is running prior to document load');
-
-  // Test that the document timeline's current time is measured from
-  // navigationStart.
-  //
-  // We can't just compare document.timeline.currentTime to
-  // window.performance.now() because currentTime is only updated on a sample
-  // so we use requestAnimationFrame instead.
-  window.requestAnimationFrame(t.step_func(function(rafTime) {
-    assert_equals(document.timeline.currentTime, rafTime,
-                  'document.timeline.currentTime matches' +
-                  ' requestAnimationFrame time');
-    t.done();
-  }));
-},
-'document.timeline.currentTime value tests',
-{
-  help: [
-    'http://dev.w3.org/fxtf/web-animations/#the-global-clock',
-    'http://dev.w3.org/fxtf/web-animations/#the-document-timeline'
-  ],
-  assert: [
-    'The global clock is a source of monotonically increasing time values',
-    'The time values of the document timeline are calculated as a fixed' +
-    ' offset from the global clock',
-    'the zero time corresponds to the navigationStart moment',
-    'the time value of each document timeline must be equal to the time ' +
-    'passed to animation frame request callbacks for that browsing context'
-  ],
-  author: 'Brian Birtles'
-});
-
-async_test(function(t) {
-  var valueAtStart = document.timeline.currentTime;
-  var timeAtStart = window.performance.now();
-  while (window.performance.now() - timeAtStart < 100) {
-    // Wait 100ms
-  }
-  assert_equals(document.timeline.currentTime, valueAtStart,
-    'document.timeline.currentTime does not change within a script block');
-  window.requestAnimationFrame(t.step_func(function() {
-    assert_true(document.timeline.currentTime > valueAtStart,
-      'document.timeline.currentTime increases between script blocks');
-    t.done();
-  }));
-},
-'document.timeline.currentTime liveness tests',
-{
-  help: 'http://dev.w3.org/fxtf/web-animations/#script-execution-and-live-updates-to-the-model',
-  assert: [ 'The value returned by the currentTime attribute of a' +
-            ' document timeline will not change within a script block' ],
-  author: 'Brian Birtles'
-});
-
-test(function() {
-  var hiddenIFrame = document.getElementById('hidden-iframe');
-  assert_equals(typeof hiddenIFrame.contentDocument.timeline.currentTime,
-    'number',
-    'currentTime of an initially hidden subframe\'s timeline is a number');
-  assert_true(hiddenIFrame.contentDocument.timeline.currentTime >= 0,
-    'currentTime of an initially hidden subframe\'s timeline is >= 0');
-}, 'document.timeline.currentTime hidden subframe test');
-
-async_test(function(t) {
-  var hiddenIFrame = document.getElementById('hidden-iframe');
-
-  // Don't run the test until after the iframe has completed loading or else the
-  // contentDocument may change.
-  var testToRunOnLoad = t.step_func(function() {
-    // Remove display:none
-    hiddenIFrame.style.display = 'block';
-    window.getComputedStyle(hiddenIFrame).display;
-
-    window.requestAnimationFrame(t.step_func(function() {
-      assert_true(hiddenIFrame.contentDocument.timeline.currentTime > 0,
-        'document.timeline.currentTime is positive after removing'
-        + ' display:none');
-      var previousValue = hiddenIFrame.contentDocument.timeline.currentTime;
-
-      // Re-introduce display:none
-      hiddenIFrame.style.display = 'none';
-      window.getComputedStyle(hiddenIFrame).display;
-
-      window.requestAnimationFrame(t.step_func(function() {
-        assert_true(
-          hiddenIFrame.contentDocument.timeline.currentTime >= previousValue,
-          'document.timeline.currentTime does not go backwards after'
-          + ' re-setting display:none');
-        t.done();
-      }));
-    }));
-  });
-
-  if (hiddenIFrame.contentDocument.readyState === 'complete') {
-    testToRunOnLoad();
-  } else {
-    hiddenIFrame.addEventListener("load", testToRunOnLoad);
-  }
-}, 'document.timeline.currentTime hidden subframe dynamic test');
-
-done();
-</script>
--- a/dom/animation/test/document-timeline/test_document-timeline.html
+++ b/dom/animation/test/document-timeline/test_document-timeline.html
@@ -1,14 +1,136 @@
 <!doctype html>
 <meta charset=utf-8>
+<title>Web Animations API: DocumentTimeline tests</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <div id="log"></div>
+<iframe src="data:text/html;charset=utf-8," width="10" height="10" id="iframe"></iframe>
+<iframe src="data:text/html;charset=utf-8,%3Chtml%20style%3D%22display%3Anone%22%3E%3C%2Fhtml%3E" width="10" height="10" id="hidden-iframe"></iframe>
 <script>
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_document-timeline.html");
+
+test(function() {
+  assert_equals(document.timeline, document.timeline,
+    'document.timeline returns the same object every time');
+  var iframe = document.getElementById('iframe');
+  assert_not_equals(document.timeline, iframe.contentDocument.timeline,
+    'document.timeline returns a different object for each document');
+  assert_not_equals(iframe.contentDocument.timeline, null,
+    'document.timeline on an iframe is not null');
+},
+'document.timeline identity tests',
+{
+  help:   'http://dev.w3.org/fxtf/web-animations/#the-document-timeline',
+  assert: [ 'Each document has a timeline called the document timeline' ],
+  author: 'Brian Birtles'
+});
+
+async_test(function(t) {
+  assert_true(document.timeline.currentTime > 0,
+    'document.timeline.currentTime is positive');
+  // document.timeline.currentTime should be set even before document
+  // load fires. We expect this code to be run before document load and hence
+  // the above assertion is sufficient.
+  // If the following assertion fails, this test needs to be redesigned.
+  assert_true(document.readyState !== 'complete',
+    'Test is running prior to document load');
+
+  // Test that the document timeline's current time is measured from
+  // navigationStart.
+  //
+  // We can't just compare document.timeline.currentTime to
+  // window.performance.now() because currentTime is only updated on a sample
+  // so we use requestAnimationFrame instead.
+  window.requestAnimationFrame(t.step_func(function(rafTime) {
+    assert_equals(document.timeline.currentTime, rafTime,
+                  'document.timeline.currentTime matches' +
+                  ' requestAnimationFrame time');
+    t.done();
+  }));
+},
+'document.timeline.currentTime value tests',
+{
+  help: [
+    'http://dev.w3.org/fxtf/web-animations/#the-global-clock',
+    'http://dev.w3.org/fxtf/web-animations/#the-document-timeline'
+  ],
+  assert: [
+    'The global clock is a source of monotonically increasing time values',
+    'The time values of the document timeline are calculated as a fixed' +
+    ' offset from the global clock',
+    'the zero time corresponds to the navigationStart moment',
+    'the time value of each document timeline must be equal to the time ' +
+    'passed to animation frame request callbacks for that browsing context'
+  ],
+  author: 'Brian Birtles'
+});
+
+async_test(function(t) {
+  var valueAtStart = document.timeline.currentTime;
+  var timeAtStart = window.performance.now();
+  while (window.performance.now() - timeAtStart < 100) {
+    // Wait 100ms
+  }
+  assert_equals(document.timeline.currentTime, valueAtStart,
+    'document.timeline.currentTime does not change within a script block');
+  window.requestAnimationFrame(t.step_func(function() {
+    assert_true(document.timeline.currentTime > valueAtStart,
+      'document.timeline.currentTime increases between script blocks');
+    t.done();
+  }));
+},
+'document.timeline.currentTime liveness tests',
+{
+  help: 'http://dev.w3.org/fxtf/web-animations/#script-execution-and-live-updates-to-the-model',
+  assert: [ 'The value returned by the currentTime attribute of a' +
+            ' document timeline will not change within a script block' ],
+  author: 'Brian Birtles'
+});
+
+test(function() {
+  var hiddenIFrame = document.getElementById('hidden-iframe');
+  assert_equals(typeof hiddenIFrame.contentDocument.timeline.currentTime,
+    'number',
+    'currentTime of an initially hidden subframe\'s timeline is a number');
+  assert_true(hiddenIFrame.contentDocument.timeline.currentTime >= 0,
+    'currentTime of an initially hidden subframe\'s timeline is >= 0');
+}, 'document.timeline.currentTime hidden subframe test');
+
+async_test(function(t) {
+  var hiddenIFrame = document.getElementById('hidden-iframe');
+
+  // Don't run the test until after the iframe has completed loading or else the
+  // contentDocument may change.
+  var testToRunOnLoad = t.step_func(function() {
+    // Remove display:none
+    hiddenIFrame.style.display = 'block';
+    window.getComputedStyle(hiddenIFrame).display;
+
+    window.requestAnimationFrame(t.step_func(function() {
+      assert_true(hiddenIFrame.contentDocument.timeline.currentTime > 0,
+        'document.timeline.currentTime is positive after removing'
+        + ' display:none');
+      var previousValue = hiddenIFrame.contentDocument.timeline.currentTime;
+
+      // Re-introduce display:none
+      hiddenIFrame.style.display = 'none';
+      window.getComputedStyle(hiddenIFrame).display;
+
+      window.requestAnimationFrame(t.step_func(function() {
+        assert_true(
+          hiddenIFrame.contentDocument.timeline.currentTime >= previousValue,
+          'document.timeline.currentTime does not go backwards after'
+          + ' re-setting display:none');
+        t.done();
+      }));
+    }));
   });
+
+  if (hiddenIFrame.contentDocument.readyState === 'complete') {
+    testToRunOnLoad();
+  } else {
+    hiddenIFrame.addEventListener("load", testToRunOnLoad);
+  }
+}, 'document.timeline.currentTime hidden subframe dynamic test');
+
 </script>
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -1,54 +1,31 @@
 [DEFAULT]
 support-files =
   testcommon.js
 
 [css-animations/test_animations-dynamic-changes.html]
-support-files = css-animations/file_animations-dynamic-changes.html
 [css-animations/test_animation-cancel.html]
-support-files = css-animations/file_animation-cancel.html
 [css-animations/test_animation-currenttime.html]
-support-files = css-animations/file_animation-currenttime.html
 [css-animations/test_animation-finish.html]
-support-files = css-animations/file_animation-finish.html
 [css-animations/test_animation-finished.html]
-support-files = css-animations/file_animation-finished.html
 [css-animations/test_animation-pausing.html]
-support-files = css-animations/file_animation-pausing.html
 [css-animations/test_animation-playstate.html]
-support-files = css-animations/file_animation-playstate.html
 [css-animations/test_animation-ready.html]
-support-files = css-animations/file_animation-ready.html
 [css-animations/test_animation-starttime.html]
-support-files = css-animations/file_animation-starttime.html
 [css-animations/test_effect-name.html]
-support-files = css-animations/file_effect-name.html
 [css-animations/test_effect-target.html]
-support-files = css-animations/file_effect-target.html
 [css-animations/test_element-get-animations.html]
 skip-if = buildapp == 'mulet'
-support-files = css-animations/file_element-get-animations.html
 [css-transitions/test_animation-cancel.html]
-support-files = css-transitions/file_animation-cancel.html
 [css-transitions/test_animation-currenttime.html]
-support-files = css-transitions/file_animation-currenttime.html
 [css-transitions/test_animation-finished.html]
-support-files = css-transitions/file_animation-finished.html
 [css-transitions/test_animation-pausing.html]
-support-files = css-transitions/file_animation-pausing.html
 [css-transitions/test_animation-ready.html]
-support-files = css-transitions/file_animation-ready.html
 [css-transitions/test_animation-starttime.html]
-support-files = css-transitions/file_animation-starttime.html
 [css-transitions/test_effect-name.html]
-support-files = css-transitions/file_effect-name.html
 [css-transitions/test_effect-target.html]
-support-files = css-transitions/file_effect-target.html
 [css-transitions/test_element-get-animations.html]
 skip-if = buildapp == 'mulet'
-support-files = css-transitions/file_element-get-animations.html
 [document-timeline/test_document-timeline.html]
-support-files = document-timeline/file_document-timeline.html
 [document-timeline/test_request_animation_frame.html]
 skip-if = buildapp == 'mulet'
 [mozilla/test_deferred_start.html]
-support-files = mozilla/file_deferred_start.html
deleted file mode 100644
--- a/dom/animation/test/mozilla/file_deferred_start.html
+++ /dev/null
@@ -1,123 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-@keyframes empty { }
-@keyframes animTransform {
-  from { transform: translate(0px); }
-  to { transform: translate(100px); }
-}
-.target {
-  /* Element needs geometry to be eligible for layerization */
-  width: 100px;
-  height: 100px;
-  background-color: white;
-}
-</style>
-<body>
-<script>
-'use strict';
-
-function waitForDocLoad() {
-  return new Promise(function(resolve, reject) {
-    if (document.readyState === 'complete') {
-      resolve();
-    } else {
-      window.addEventListener('load', resolve);
-    }
-  });
-}
-
-async_test(function(t) {
-  var div = addDiv(t);
-  var cs = window.getComputedStyle(div);
-
-  // Test that empty animations actually start.
-  //
-  // Normally we tie the start of animations to when their first frame of
-  // the animation is rendered. However, for animations that don't actually
-  // trigger a paint (e.g. because they are empty, or are animating something
-  // that doesn't render or is offscreen) we want to make sure they still
-  // start.
-  //
-  // Before we start, wait for the document to finish loading. This is because
-  // during loading we will have other paint events taking place which might,
-  // by luck, happen to trigger animations that otherwise would not have been
-  // triggered, leading to false positives.
-  //
-  // As a result, it's better to wait until we have a more stable state before
-  // continuing.
-  var promiseCallbackDone = false;
-  waitForDocLoad().then(function() {
-    div.style.animation = 'empty 1000s';
-    var animation = div.getAnimations()[0];
-
-    animation.ready.then(function() {
-      promiseCallbackDone = true;
-    }).catch(function() {
-      assert_unreached('ready promise was rejected');
-    });
-
-  // We need to wait for up to three frames. This is because in some
-  // cases it can take up to two frames for the initial layout
-  // to take place. Even after that happens we don't actually resolve the
-  // ready promise until the following tick.
-  })
-  .then(waitForFrame)
-  .then(waitForFrame)
-  .then(waitForFrame)
-  .then(t.step_func(function() {
-    assert_true(promiseCallbackDone,
-                'ready promise for an empty animation was resolved'
-                + ' within three animation frames');
-    t.done();
-  }));
-}, 'Animation.ready is resolved for an empty animation');
-
-// Test that compositor animations with delays get synced correctly
-//
-// NOTE: It is important that we DON'T use
-// SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh here since that takes
-// us through a different code path.
-async_test(function(t) {
-  // This test only applies to compositor animations
-  const OMTAPrefKey = 'layers.offmainthreadcomposition.async-animations';
-  var omtaEnabled = SpecialPowers.DOMWindowUtils.layerManagerRemote &&
-                    SpecialPowers.getBoolPref(OMTAPrefKey);
-  if (!omtaEnabled) {
-    t.done();
-    return;
-  }
-
-  // Setup animation
-  var div = addDiv(t);
-  div.classList.add('target');
-  div.style.animation = 'animTransform 100s -50s forwards';
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(function() {
-    var transformStr =
-      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
-
-    var matrixComponents =
-      transformStr.startsWith('matrix(')
-      ? transformStr.substring('matrix('.length, transformStr.length-1)
-                    .split(',')
-                    .map(component => Number(component))
-      : [];
-    assert_equals(matrixComponents.length, 6,
-                  'Got a valid transform matrix on the compositor'
-                  + ' (got: "' + transformStr + '")');
-
-    // If the delay has been applied correctly we should be at least
-    // half-way through the animation
-    assert_true(matrixComponents[4] >= 50,
-                'Animation is at least half-way through on the compositor'
-                + ' (got translation of ' + matrixComponents[4] + ')');
-    t.done();
-  }));
-}, 'Starting an animation with a delay starts from the correct point');
-
-done();
-</script>
-</body>
--- a/dom/animation/test/mozilla/test_deferred_start.html
+++ b/dom/animation/test/mozilla/test_deferred_start.html
@@ -1,14 +1,123 @@
 <!doctype html>
 <meta charset=utf-8>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
 <div id="log"></div>
+<style>
+@keyframes empty { }
+@keyframes animTransform {
+  from { transform: translate(0px); }
+  to { transform: translate(100px); }
+}
+.target {
+  /* Element needs geometry to be eligible for layerization */
+  width: 100px;
+  height: 100px;
+  background-color: white;
+}
+</style>
 <script>
 'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_deferred_start.html");
+
+function waitForDocLoad() {
+  return new Promise(function(resolve, reject) {
+    if (document.readyState === 'complete') {
+      resolve();
+    } else {
+      window.addEventListener('load', resolve);
+    }
   });
+}
+
+async_test(function(t) {
+  var div = addDiv(t);
+  var cs = window.getComputedStyle(div);
+
+  // Test that empty animations actually start.
+  //
+  // Normally we tie the start of animations to when their first frame of
+  // the animation is rendered. However, for animations that don't actually
+  // trigger a paint (e.g. because they are empty, or are animating something
+  // that doesn't render or is offscreen) we want to make sure they still
+  // start.
+  //
+  // Before we start, wait for the document to finish loading. This is because
+  // during loading we will have other paint events taking place which might,
+  // by luck, happen to trigger animations that otherwise would not have been
+  // triggered, leading to false positives.
+  //
+  // As a result, it's better to wait until we have a more stable state before
+  // continuing.
+  var promiseCallbackDone = false;
+  waitForDocLoad().then(function() {
+    div.style.animation = 'empty 1000s';
+    var animation = div.getAnimations()[0];
+
+    animation.ready.then(function() {
+      promiseCallbackDone = true;
+    }).catch(function() {
+      assert_unreached('ready promise was rejected');
+    });
+
+  // We need to wait for up to three frames. This is because in some
+  // cases it can take up to two frames for the initial layout
+  // to take place. Even after that happens we don't actually resolve the
+  // ready promise until the following tick.
+  })
+  .then(waitForFrame)
+  .then(waitForFrame)
+  .then(waitForFrame)
+  .then(t.step_func(function() {
+    assert_true(promiseCallbackDone,
+                'ready promise for an empty animation was resolved'
+                + ' within three animation frames');
+    t.done();
+  }));
+}, 'Animation.ready is resolved for an empty animation');
+
+// Test that compositor animations with delays get synced correctly
+//
+// NOTE: It is important that we DON'T use
+// SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh here since that takes
+// us through a different code path.
+async_test(function(t) {
+  // This test only applies to compositor animations
+  const OMTAPrefKey = 'layers.offmainthreadcomposition.async-animations';
+  var omtaEnabled = SpecialPowers.DOMWindowUtils.layerManagerRemote &&
+                    SpecialPowers.getBoolPref(OMTAPrefKey);
+  if (!omtaEnabled) {
+    t.done();
+    return;
+  }
+
+  // Setup animation
+  var div = addDiv(t);
+  div.classList.add('target');
+  div.style.animation = 'animTransform 100s -50s forwards';
+  var animation = div.getAnimations()[0];
+
+  animation.ready.then(t.step_func(function() {
+    var transformStr =
+      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
+
+    var matrixComponents =
+      transformStr.startsWith('matrix(')
+      ? transformStr.substring('matrix('.length, transformStr.length-1)
+                    .split(',')
+                    .map(component => Number(component))
+      : [];
+    assert_equals(matrixComponents.length, 6,
+                  'Got a valid transform matrix on the compositor'
+                  + ' (got: "' + transformStr + '")');
+
+    // If the delay has been applied correctly we should be at least
+    // half-way through the animation
+    assert_true(matrixComponents[4] >= 50,
+                'Animation is at least half-way through on the compositor'
+                + ' (got translation of ' + matrixComponents[4] + ')');
+    t.done();
+  }));
+}, 'Starting an animation with a delay starts from the correct point');
+
 </script>
--- a/dom/animation/test/testcommon.js
+++ b/dom/animation/test/testcommon.js
@@ -72,23 +72,8 @@ function waitForAllAnimations(animations
  * to be computed so that when we synchronouslyet set it to a different value
  * we actually get a transition instead of that being the initial value.
  */
 function flushComputedStyle(elem) {
   var cs = window.getComputedStyle(elem);
   cs.marginLeft;
 }
 
-for (var funcName of ["async_test", "assert_not_equals", "assert_equals",
-                      "assert_approx_equals", "assert_less_than_equal",
-                      "assert_between_inclusive", "assert_true", "assert_false",
-                      "test"]) {
-  window[funcName] = opener[funcName].bind(opener);
-}
-
-window.EventWatcher = opener.EventWatcher;
-
-function done() {
-  opener.add_completion_callback(function() {
-    self.close();
-  });
-  opener.done();
-}
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -125,23 +125,23 @@ var interfaceNamesInGlobalScope =
   [
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozAbortablePromise", pref: "dom.abortablepromise.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "AlarmsManager", pref: "dom.mozAlarms.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "AnalyserNode",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "Animation", release: false},
+    {name: "Animation", pref: "dom.animations-api.core.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "AnimationEffectReadOnly", release: false},
+    {name: "AnimationEffectReadOnly", pref: "dom.animations-api.core.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "AnimationEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "AnimationTimeline", release: false},
+    {name: "AnimationTimeline", pref: "dom.animations-api.core.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Attr",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Audio",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "AudioBuffer",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "AudioChannelManager", b2g: true},
@@ -346,17 +346,17 @@ var interfaceNamesInGlobalScope =
     { name: "DeviceStorageChangeEvent", pref: "device.storage.enabled" },
     // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "DisplayPortInputPort", b2g: true, pref: "dom.inputport.enabled", permission: ["inputport"]},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Document",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DocumentFragment",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "DocumentTimeline", release: false},
+    {name: "DocumentTimeline", pref: "dom.animations-api.core.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DocumentType",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "DOMConstructor", xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DOMCursor",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DOMError",
@@ -646,17 +646,17 @@ var interfaceNamesInGlobalScope =
     {name: "InputPortManager", b2g: true, pref: "dom.inputport.enabled", permission: ["inputport"]},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "InstallTrigger", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "KeyEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "KeyboardEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "KeyframeEffectReadOnly", release: false},
+    {name: "KeyframeEffectReadOnly", pref: "dom.animations-api.core.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "LocalMediaStream",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Location",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MediaDeviceInfo",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MediaDevices",
--- a/dom/xslt/tests/mochitest/test_bug1135764.html
+++ b/dom/xslt/tests/mochitest/test_bug1135764.html
@@ -21,33 +21,25 @@ https://bugzilla.mozilla.org/show_bug.cg
       frames[0].requestAnimationFrame(waitATick);
       return;
     }
     ok(frames[0].document.timeline.currentTime !== startTimelineValue,
        "The timeline in an XSLT-transformed document should still advance");
     SimpleTest.finish();
   }
   addLoadEvent(function() {
-    SpecialPowers.pushPrefEnv(
-      { "set": [[ "dom.animations-api.core.enabled", true]] },
-      function() {
-        var ifr = document.querySelector("iframe");
-        ifr.onload = function() {
-          startTimelineValue = frames[0].document.timeline.currentTime;
-          frames[0].requestAnimationFrame(waitATick);
-        }
-        ifr.src = "file_bug1135764.xml";
-     })
+    startTimelineValue = frames[0].document.timeline.currentTime;
+    frames[0].requestAnimationFrame(waitATick);
   })
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1135764">Mozilla Bug 1135764</a>
 <p id="display">
-  <iframe></iframe>
+  <iframe src="file_bug1135764.xml"></iframe>
 </p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 </pre>
 </body>
 </html>
deleted file mode 100644
--- a/layout/style/test/file_animations_pausing.html
+++ /dev/null
@@ -1,85 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <script type="application/javascript"
-    src="/tests/SimpleTest/paint_listener.js"></script>
-  <script type="application/javascript" src="animation_utils.js"></script>
-  <style type="text/css">
-    @keyframes anim {
-      0% { transform: translate(0px) }
-      100% { transform: translate(100px) }
-    }
-    .target {
-      /* The animation target needs geometry in order to qualify for OMTA */
-      width: 100px;
-      height: 100px;
-      background-color: white;
-    }
-  </style>
-  <script>
-    var ok = opener.ok.bind(opener);
-    var is = opener.is.bind(opener);
-    var okOrTodo = opener.okOrTodo.bind(opener);
-    function finish() {
-      var o = opener;
-      self.close();
-      o.SimpleTest.finish();
-    }
-  </script>
-</head>
-<body>
-<div id="display"></div>
-<script type="application/javascript">
-"use strict";
-
-runOMTATest(function() {
-  runAllAsyncAnimTests().then(function() {
-    finish();
-  });
-}, finish);
-
-addAsyncAnimTest(function *() {
-  var [ div, cs ] = new_div("animation: anim 10s 2 linear alternate");
-
-  // Animation is initially running on compositor
-  yield waitForPaintsFlushed();
-  advance_clock(1000);
-  omta_is(div, "transform", { tx: 10 }, RunningOn.Compositor,
-          "Animation is initally animating on compositor");
-
-  // pause() means it is no longer on the compositor
-  var animation = div.getAnimations()[0];
-  animation.pause();
-  // pause() should set up the changes to animations for the next layer
-  // transaction but it won't schedule a paint immediately so we need to tick
-  // the refresh driver before we can wait on the next paint.
-  advance_clock(0);
-  yield waitForPaints();
-  omta_is(div, "transform", { tx: 10 }, RunningOn.MainThread,
-          "After pausing, animation is removed from compositor");
-
-  // Animation remains paused
-  advance_clock(1000);
-  omta_is(div, "transform", { tx: 10 }, RunningOn.MainThread,
-          "Animation remains paused");
-
-  // play() puts the animation back on the compositor
-  animation.play();
-  // As with pause(), play() will set up pending animations for the next layer
-  // transaction but won't schedule a paint so we need to tick the refresh
-  // driver before waiting on the next paint.
-  advance_clock(0);
-  yield waitForPaints();
-  omta_is(div, "transform", { tx: 10 }, RunningOn.Compositor,
-          "After playing, animation is sent to compositor");
-
-  // Where it continues to run
-  advance_clock(1000);
-  omta_is(div, "transform", { tx: 20 }, RunningOn.Compositor,
-          "Animation continues playing on compositor");
-
-  done_div();
-});
-</script>
-</body>
-</html>
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -262,12 +262,12 @@ skip-if = buildapp == 'b2g' || toolkit =
 support-files = bug732209-css.sjs
 [test_bug795520.html]
 [test_background_blend_mode.html]
 [test_property_database.html]
 [test_counter_style.html]
 [test_counter_descriptor_storage.html]
 [test_position_float_display.html]
 [test_animations_async_tests.html]
-support-files = ../../reftests/fonts/Ahem.ttf file_animations_pausing.html
+support-files = ../../reftests/fonts/Ahem.ttf
 [test_setPropertyWithNull.html]
 [test_attribute_selector_eof_behavior.html]
 [test_css_loader_crossorigin_data_url.html]
--- a/layout/style/test/test_animations_pausing.html
+++ b/layout/style/test/test_animations_pausing.html
@@ -1,28 +1,87 @@
 <!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=1070745
 -->
 <head>
   <title>Test for play() and pause() on animations (Bug 1070745)</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+    src="/tests/SimpleTest/paint_listener.js"></script>
+  <script type="application/javascript" src="animation_utils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <style type="text/css">
+    @keyframes anim {
+      0% { transform: translate(0px) }
+      100% { transform: translate(100px) }
+    }
+    .target {
+      /* The animation target needs geometry in order to qualify for OMTA */
+      width: 100px;
+      height: 100px;
+      background-color: white;
+    }
+  </style>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1070745">Mozilla Bug 1070745</a>
 <div id="display"></div>
 <pre id="test">
 <script type="application/javascript">
 "use strict";
 
 SimpleTest.waitForExplicitFinish();
 
-SpecialPowers.pushPrefEnv(
-  { "set": [[ "dom.animations-api.core.enabled", true]] },
-  function() {
-    window.open("file_animations_pausing.html");
+runOMTATest(function() {
+  runAllAsyncAnimTests().then(function() {
+    SimpleTest.finish();
   });
+}, SimpleTest.finish);
+
+addAsyncAnimTest(function *() {
+  var [ div, cs ] = new_div("animation: anim 10s 2 linear alternate");
+
+  // Animation is initially running on compositor
+  yield waitForPaintsFlushed();
+  advance_clock(1000);
+  omta_is(div, "transform", { tx: 10 }, RunningOn.Compositor,
+          "Animation is initally animating on compositor");
+
+  // pause() means it is no longer on the compositor
+  var animation = div.getAnimations()[0];
+  animation.pause();
+  // pause() should set up the changes to animations for the next layer
+  // transaction but it won't schedule a paint immediately so we need to tick
+  // the refresh driver before we can wait on the next paint.
+  advance_clock(0);
+  yield waitForPaints();
+  omta_is(div, "transform", { tx: 10 }, RunningOn.MainThread,
+          "After pausing, animation is removed from compositor");
+
+  // Animation remains paused
+  advance_clock(1000);
+  omta_is(div, "transform", { tx: 10 }, RunningOn.MainThread,
+          "Animation remains paused");
+
+  // play() puts the animation back on the compositor
+  animation.play();
+  // As with pause(), play() will set up pending animations for the next layer
+  // transaction but won't schedule a paint so we need to tick the refresh
+  // driver before waiting on the next paint.
+  advance_clock(0);
+  yield waitForPaints();
+  omta_is(div, "transform", { tx: 10 }, RunningOn.Compositor,
+          "After playing, animation is sent to compositor");
+
+  // Where it continues to run
+  advance_clock(1000);
+  omta_is(div, "transform", { tx: 20 }, RunningOn.Compositor,
+          "Animation continues playing on compositor");
+
+  done_div();
+});
+
 </script>
 </pre>
 </body>
 </html>
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -46,16 +46,17 @@ user_pref("app.update.staging.enabled", 
 user_pref("app.update.url.android", "");
 // Make sure GMPInstallManager won't hit the network.
 user_pref("media.gmp-manager.url.override", "http://%(server)s/dummy-gmp-manager.xml");
 user_pref("browser.panorama.experienced_first_run", true); // Assume experienced
 user_pref("dom.w3c_touch_events.enabled", 1);
 user_pref("dom.undo_manager.enabled", true);
 user_pref("dom.webcomponents.enabled", true);
 user_pref("dom.htmlimports.enabled", true);
+user_pref("dom.animations-api.core.enabled", true);
 // Set a future policy version to avoid the telemetry prompt.
 user_pref("toolkit.telemetry.prompted", 999);
 user_pref("toolkit.telemetry.notifiedOptOut", 999);
 // Existing tests assume there is no font size inflation.
 user_pref("font.size.inflation.emPerLine", 0);
 user_pref("font.size.inflation.minTwips", 0);
 
 // AddonManager tests require that the experiments provider be present.
deleted file mode 100644
--- a/testing/web-platform/meta/web-animations/animation-timeline/animation-timeline.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[animation-timeline.html]
-  type: testharness
-  prefs: [dom.animations-api.core.enabled:true]
--- a/testing/web-platform/meta/web-animations/animation-timeline/idlharness.html.ini
+++ b/testing/web-platform/meta/web-animations/animation-timeline/idlharness.html.ini
@@ -1,9 +1,8 @@
 [idlharness.html]
   type: testharness
-  prefs: [dom.animations-api.core.enabled:true]
   [AnimationTimeline must be primary interface of document.timeline]
     expected: FAIL
 
   [Stringification of document.timeline]
     expected: FAIL