Backed out 14 changesets (bug 1436659) for Eslint failures on devtools/server/actors/animation.js:876:12 on a CLOSED TREE
authorarthur.iakab <aiakab@mozilla.com>
Wed, 14 Feb 2018 22:40:07 +0200
changeset 443065 1d864693c47c8c791a3c8cd8e84860ecf6351aa7
parent 443064 7270c9ee964b72cd9aaf6fc2b483d67633baef90
child 443066 d8bb0ab25ecbb2a8d67a37dfbc4e0a64fee1c575
push idunknown
push userunknown
push dateunknown
bugs1436659
milestone60.0a1
backs outa2890507d13a9812cbe2b5761a6103f58a39eb51
c653d7a1b3ef042bf7b2cc06ea340378dc34d546
4ae911f19aee5b6738ed4bd405e1d75acd428358
e9381081ab6a3354c236096453735f93aa68b870
7301bfeeb65c5d7840a86bcd9406d21df83b3c31
607dccfa8387c5b28eaf5d6663d1c759df98bf6b
8f61bf3de90affb12962bd6556a6ee5530c15c5f
920aa51ae3a22c858daaad63b54d520259b856d2
bfa0d1a4bf1cc49f63ad1aee3c4ab5edc5a0f529
467dd218d3d32373191863a79e5d6716b45ad043
737ff1676ff0776b213b71a5d44784bd3dcd1aa7
071666b6c7e9c6de8a6ec20ba138ee18fd1972e3
c2932cd4839fd8d93b73860bf50b20b8499a4986
a9777027b7ad5daed663df32ce3fcc9cb6502b9d
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 14 changesets (bug 1436659) for Eslint failures on devtools/server/actors/animation.js:876:12 on a CLOSED TREE Backed out changeset a2890507d13a (bug 1436659) Backed out changeset c653d7a1b3ef (bug 1436659) Backed out changeset 4ae911f19aee (bug 1436659) Backed out changeset e9381081ab6a (bug 1436659) Backed out changeset 7301bfeeb65c (bug 1436659) Backed out changeset 607dccfa8387 (bug 1436659) Backed out changeset 8f61bf3de90a (bug 1436659) Backed out changeset 920aa51ae3a2 (bug 1436659) Backed out changeset bfa0d1a4bf1c (bug 1436659) Backed out changeset 467dd218d3d3 (bug 1436659) Backed out changeset 737ff1676ff0 (bug 1436659) Backed out changeset 071666b6c7e9 (bug 1436659) Backed out changeset c2932cd4839f (bug 1436659) Backed out changeset a9777027b7ad (bug 1436659)
devtools/server/actors/animation.js
dom/animation/Animation.cpp
dom/animation/Animation.h
dom/webidl/Animation.webidl
gfx/layers/AnimationInfo.cpp
gfx/layers/ipc/LayersMessages.ipdlh
layout/painting/nsDisplayList.cpp
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/web-animations/animation-model/combining-effects/applying-the-composited-result.html
testing/web-platform/tests/web-animations/interfaces/Animation/finish.html
testing/web-platform/tests/web-animations/interfaces/Animation/idlharness.html
testing/web-platform/tests/web-animations/interfaces/Animation/playbackRate.html
testing/web-platform/tests/web-animations/timing-model/animations/canceling-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/current-time.html
testing/web-platform/tests/web-animations/timing-model/animations/finishing-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/pausing-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/play-states.html
testing/web-platform/tests/web-animations/timing-model/animations/playing-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/reversing-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/seamlessly-updating-the-playback-rate-of-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/set-the-animation-start-time.html
testing/web-platform/tests/web-animations/timing-model/animations/set-the-target-effect-of-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/set-the-timeline-of-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/setting-the-current-time-of-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/setting-the-playback-rate-of-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/setting-the-start-time-of-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/setting-the-target-effect-of-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/setting-the-timeline-of-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/the-current-time-of-an-animation.html
testing/web-platform/tests/web-animations/timing-model/animations/updating-the-finished-state.html
--- a/devtools/server/actors/animation.js
+++ b/devtools/server/actors/animation.js
@@ -385,26 +385,24 @@ var AnimationPlayerActor = protocol.Acto
         // Reset the local copy of the state on removal, since the animation can
         // be kept on the client and re-added, its state needs to be sent in
         // full.
         this.currentState = null;
       }
 
       if (hasCurrentAnimation(changedAnimations)) {
         // Only consider the state has having changed if any of delay, duration,
-        // iterationCount, iterationStart, or playbackRate has changed (for now
-        // at least).
+        // iterationcount or iterationStart has changed (for now at least).
         let newState = this.getState();
         let oldState = this.currentState;
         hasChanged = newState.delay !== oldState.delay ||
                      newState.iterationCount !== oldState.iterationCount ||
                      newState.iterationStart !== oldState.iterationStart ||
                      newState.duration !== oldState.duration ||
-                     newState.endDelay !== oldState.endDelay ||
-                     newState.playbackRate !== oldState.playbackRate;
+                     newState.endDelay !== oldState.endDelay;
         break;
       }
     }
 
     if (hasChanged) {
       this.emit("changed", this.getCurrentState());
     }
   },
@@ -461,18 +459,17 @@ var AnimationPlayerActor = protocol.Acto
     }
     this.player.currentTime = currentTime * this.player.playbackRate;
   },
 
   /**
    * Set the playback rate of the animation player.
    */
   setPlaybackRate: function (playbackRate) {
-    this.player.updatePlaybackRate(playbackRate);
-    return this.player.ready;
+    this.player.playbackRate = playbackRate;
   },
 
   /**
    * Get data about the keyframes of this animation player.
    * @return {Object} Returns a list of frames, each frame containing the list
    * animated properties as well as the frame's offset.
    */
   getFrames: function () {
@@ -868,13 +865,13 @@ exports.AnimationsActor = protocol.Actor
   },
 
   /**
    * Set the playback rate of several animations at the same time.
    * @param {Array} players A list of AnimationPlayerActor.
    * @param {Number} rate The new rate.
    */
   setPlaybackRates: function (players, rate) {
-    return promise.all(
-      players.map(player => player.setPlaybackRate(rate))
-    );
+    for (let player of players) {
+      player.setPlaybackRate(rate);
+    }
   }
 });
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -268,20 +268,17 @@ Animation::SetStartTime(const Nullable<T
     // the already null time to null.
     timelineTime = mTimeline->GetCurrentTime();
   }
   if (timelineTime.IsNull() && !aNewStartTime.IsNull()) {
     mHoldTime.SetNull();
   }
 
   Nullable<TimeDuration> previousCurrentTime = GetCurrentTime();
-
-  ApplyPendingPlaybackRate();
   mStartTime = aNewStartTime;
-
   if (!aNewStartTime.IsNull()) {
     if (mPlaybackRate != 0.0) {
       mHoldTime.SetNull();
     }
   } else {
     mHoldTime = previousCurrentTime;
   }
 
@@ -296,30 +293,29 @@ Animation::SetStartTime(const Nullable<T
   if (IsRelevant()) {
     nsNodeUtils::AnimationChanged(this);
   }
   PostUpdate();
 }
 
 // https://drafts.csswg.org/web-animations/#current-time
 Nullable<TimeDuration>
-Animation::GetCurrentTimeForHoldTime(
-  const Nullable<TimeDuration>& aHoldTime) const
+Animation::GetCurrentTime() const
 {
   Nullable<TimeDuration> result;
-  if (!aHoldTime.IsNull()) {
-    result = aHoldTime;
+  if (!mHoldTime.IsNull()) {
+    result = mHoldTime;
     return result;
   }
 
   if (mTimeline && !mStartTime.IsNull()) {
     Nullable<TimeDuration> timelineTime = mTimeline->GetCurrentTime();
     if (!timelineTime.IsNull()) {
-      result = CurrentTimeFromTimelineTime(
-        timelineTime.Value(), mStartTime.Value(), mPlaybackRate);
+      result.SetValue((timelineTime.Value() - mStartTime.Value())
+                        .MultDouble(mPlaybackRate));
     }
   }
   return result;
 }
 
 // https://drafts.csswg.org/web-animations/#set-the-current-time
 void
 Animation::SetCurrentTime(const TimeDuration& aSeekTime)
@@ -335,39 +331,35 @@ Animation::SetCurrentTime(const TimeDura
 
   AutoMutationBatchForAnimation mb(*this);
 
   SilentlySetCurrentTime(aSeekTime);
 
   if (mPendingState == PendingState::PausePending) {
     // Finish the pause operation
     mHoldTime.SetValue(aSeekTime);
-
-    ApplyPendingPlaybackRate();
     mStartTime.SetNull();
 
     if (mReady) {
       mReady->MaybeResolve(this);
     }
     CancelPendingTasks();
   }
 
   UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Async);
   if (IsRelevant()) {
     nsNodeUtils::AnimationChanged(this);
   }
   PostUpdate();
 }
 
-// https://drafts.csswg.org/web-animations/#set-the-playback-rate
+// https://drafts.csswg.org/web-animations/#set-the-animation-playback-rate
 void
 Animation::SetPlaybackRate(double aPlaybackRate)
 {
-  mPendingPlaybackRate.reset();
-
   if (aPlaybackRate == mPlaybackRate) {
     return;
   }
 
   AutoMutationBatchForAnimation mb(*this);
 
   Nullable<TimeDuration> previousTime = GetCurrentTime();
   mPlaybackRate = aPlaybackRate;
@@ -385,93 +377,16 @@ Animation::SetPlaybackRate(double aPlayb
   // - update the playback rate on animations on layers.
   UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Async);
   if (IsRelevant()) {
     nsNodeUtils::AnimationChanged(this);
   }
   PostUpdate();
 }
 
-// https://drafts.csswg.org/web-animations/#seamlessly-update-the-playback-rate
-void
-Animation::UpdatePlaybackRate(double aPlaybackRate)
-{
-  if (mPendingPlaybackRate && mPendingPlaybackRate.value() == aPlaybackRate) {
-    return;
-  }
-
-  mPendingPlaybackRate = Some(aPlaybackRate);
-
-  // If we already have a pending task, there is nothing more to do since the
-  // playback rate will be applied then.
-  if (Pending()) {
-    return;
-  }
-
-  AutoMutationBatchForAnimation mb(*this);
-
-  AnimationPlayState playState = PlayState();
-  if (playState == AnimationPlayState::Idle ||
-      playState == AnimationPlayState::Paused) {
-    // We are either idle or paused. In either case we can apply the pending
-    // playback rate immediately.
-    ApplyPendingPlaybackRate();
-
-    // We don't need to update timing or post an update here because:
-    //
-    // * the current time hasn't changed -- it's either unresolved or fixed
-    //   with a hold time -- so the output won't have changed
-    // * the finished state won't have changed even if the sign of the
-    //   playback rate changed since we're not finished (we're paused or idle)
-    // * the playback rate on layers doesn't need to be updated since we're not
-    //   moving. Once we get a start time etc. we'll update the playback rate
-    //   then.
-    //
-    // All we need to do is update observers so that, e.g. DevTools, report the
-    // right information.
-    if (IsRelevant()) {
-      nsNodeUtils::AnimationChanged(this);
-    }
-  } else if (playState == AnimationPlayState::Finished) {
-    MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(),
-               "If we have no active timeline, we should be idle or paused");
-    if (aPlaybackRate != 0) {
-      // The unconstrained current time can only be unresolved if either we
-      // don't have an active timeline (and we already asserted that is not
-      // true) or we have an unresolved start time (in which case we should be
-      // paused).
-      MOZ_ASSERT(!GetUnconstrainedCurrentTime().IsNull(),
-                 "Unconstrained current time should be resolved");
-      TimeDuration unconstrainedCurrentTime =
-        GetUnconstrainedCurrentTime().Value();
-      TimeDuration timelineTime = mTimeline->GetCurrentTime().Value();
-      mStartTime = StartTimeFromTimelineTime(
-        timelineTime, unconstrainedCurrentTime, aPlaybackRate);
-    } else {
-      mStartTime = mTimeline->GetCurrentTime();
-    }
-
-    ApplyPendingPlaybackRate();
-
-    // Even though we preserve the current time, we might now leave the finished
-    // state (e.g. if the playback rate changes sign) so we need to update
-    // timing.
-    UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
-    if (IsRelevant()) {
-      nsNodeUtils::AnimationChanged(this);
-    }
-    PostUpdate();
-  } else {
-    ErrorResult rv;
-    Play(rv, LimitBehavior::Continue);
-    MOZ_ASSERT(!rv.Failed(),
-               "We should only fail to play when using auto-rewind behavior");
-  }
-}
-
 // https://drafts.csswg.org/web-animations/#play-state
 AnimationPlayState
 Animation::PlayState() const
 {
   if (!nsContentUtils::AnimationsAPIPendingMemberEnabled() && Pending()) {
     return AnimationPlayState::Pending;
   }
 
@@ -534,46 +449,42 @@ Animation::Cancel()
   CancelNoUpdate();
   PostUpdate();
 }
 
 // https://drafts.csswg.org/web-animations/#finish-an-animation
 void
 Animation::Finish(ErrorResult& aRv)
 {
-  double effectivePlaybackRate = CurrentOrPendingPlaybackRate();
-
-  if (effectivePlaybackRate == 0 ||
-      (effectivePlaybackRate > 0 && EffectEnd() == TimeDuration::Forever())) {
+  if (mPlaybackRate == 0 ||
+      (mPlaybackRate > 0 && EffectEnd() == TimeDuration::Forever())) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   AutoMutationBatchForAnimation mb(*this);
 
-  ApplyPendingPlaybackRate();
-
   // Seek to the end
   TimeDuration limit =
     mPlaybackRate > 0 ? TimeDuration(EffectEnd()) : TimeDuration(0);
   bool didChange = GetCurrentTime() != Nullable<TimeDuration>(limit);
   SilentlySetCurrentTime(limit);
 
   // If we are paused or play-pending we need to fill in the start time in
   // order to transition to the finished state.
   //
   // We only do this, however, if we have an active timeline. If we have an
   // inactive timeline we can't transition into the finished state just like
   // we can't transition to the running state (this finished state is really
   // a substate of the running state).
   if (mStartTime.IsNull() &&
       mTimeline &&
       !mTimeline->GetCurrentTime().IsNull()) {
-    mStartTime = StartTimeFromTimelineTime(
-      mTimeline->GetCurrentTime().Value(), limit, mPlaybackRate);
+    mStartTime.SetValue(mTimeline->GetCurrentTime().Value() -
+                        limit.MultDouble(1.0 / mPlaybackRate));
     didChange = true;
   }
 
   // If we just resolved the start time for a pause or play-pending
   // animation, we need to clear the task. We don't do this as a branch of
   // the above however since we can have a play-pending animation with a
   // resolved start time if we aborted a pause operation.
   if (!mStartTime.IsNull() &&
@@ -613,34 +524,35 @@ Animation::Pause(ErrorResult& aRv)
 void
 Animation::Reverse(ErrorResult& aRv)
 {
   if (!mTimeline || mTimeline->GetCurrentTime().IsNull()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
-  double effectivePlaybackRate = CurrentOrPendingPlaybackRate();
-
-  if (effectivePlaybackRate == 0.0) {
+  if (mPlaybackRate == 0.0) {
     return;
   }
 
-  Maybe<double> originalPendingPlaybackRate = mPendingPlaybackRate;
+  AutoMutationBatchForAnimation mb(*this);
 
-  mPendingPlaybackRate = Some(-effectivePlaybackRate);
-
+  SilentlySetPlaybackRate(-mPlaybackRate);
   Play(aRv, LimitBehavior::AutoRewind);
 
   // If Play() threw, restore state and don't report anything to mutation
   // observers.
   if (aRv.Failed()) {
-    mPendingPlaybackRate = originalPendingPlaybackRate;
+    SilentlySetPlaybackRate(-mPlaybackRate);
+    return;
   }
 
+  if (IsRelevant()) {
+    nsNodeUtils::AnimationChanged(this);
+  }
   // Play(), above, unconditionally calls PostUpdate so we don't need to do
   // it here.
 }
 
 // ---------------------------------------------------------------------------
 //
 // JS wrappers for Animation interface:
 //
@@ -760,53 +672,42 @@ Animation::TriggerNow()
   FinishPendingAt(mTimeline->GetCurrentTime().Value());
 }
 
 Nullable<TimeDuration>
 Animation::GetCurrentOrPendingStartTime() const
 {
   Nullable<TimeDuration> result;
 
-  // If we have a pending playback rate, work out what start time we will use
-  // when we come to updating that playback rate.
-  //
-  // This logic roughly shadows that in ResumeAt but is just different enough
-  // that it is difficult to extract out the common functionality (and
-  // extracting that functionality out would make it harder to match ResumeAt up
-  // against the spec).
-  if (mPendingPlaybackRate && !mPendingReadyTime.IsNull() &&
-      !mStartTime.IsNull()) {
-    // If we have a hold time, use it as the current time to match.
-    TimeDuration currentTimeToMatch =
-      !mHoldTime.IsNull()
-        ? mHoldTime.Value()
-        : CurrentTimeFromTimelineTime(
-            mPendingReadyTime.Value(), mStartTime.Value(), mPlaybackRate);
-
-    result = StartTimeFromTimelineTime(
-      mPendingReadyTime.Value(), currentTimeToMatch, *mPendingPlaybackRate);
-    return result;
-  }
-
   if (!mStartTime.IsNull()) {
     result = mStartTime;
     return result;
   }
 
   if (mPendingReadyTime.IsNull() || mHoldTime.IsNull()) {
     return result;
   }
 
   // Calculate the equivalent start time from the pending ready time.
-  result = StartTimeFromTimelineTime(
-    mPendingReadyTime.Value(), mHoldTime.Value(), mPlaybackRate);
+  result = StartTimeFromReadyTime(mPendingReadyTime.Value());
 
   return result;
 }
 
+TimeDuration
+Animation::StartTimeFromReadyTime(const TimeDuration& aReadyTime) const
+{
+  MOZ_ASSERT(!mHoldTime.IsNull(), "Hold time should be set in order to"
+                                  " convert a ready time to a start time");
+  if (mPlaybackRate == 0) {
+    return aReadyTime;
+  }
+  return aReadyTime - mHoldTime.Value().MultDouble(1 / mPlaybackRate);
+}
+
 TimeStamp
 Animation::AnimationTimeToTimeStamp(const StickyTimeDuration& aTime) const
 {
   // Initializes to null. Return the same object every time to benefit from
   // return-value-optimization.
   TimeStamp result;
 
   // We *don't* check for mTimeline->TracksWallclockTime() here because that
@@ -827,17 +728,17 @@ Animation::AnimationTimeToTimeStamp(cons
   // Check the time is convertible to a timestamp
   if (aTime == TimeDuration::Forever() ||
       mPlaybackRate == 0.0 ||
       mStartTime.IsNull()) {
     return result;
   }
 
   // Invert the standard relation:
-  //   current time = (timeline time - start time) * playback rate
+  //   animation time = (timeline time - start time) * playback rate
   TimeDuration timelineTime =
     TimeDuration(aTime).MultDouble(1.0 / mPlaybackRate) + mStartTime.Value();
 
   result = mTimeline->ToTimeStamp(timelineTime);
   return result;
 }
 
 TimeStamp
@@ -859,23 +760,33 @@ Animation::SilentlySetCurrentTime(const 
       !mTimeline ||
       mTimeline->GetCurrentTime().IsNull() ||
       mPlaybackRate == 0.0) {
     mHoldTime.SetValue(aSeekTime);
     if (!mTimeline || mTimeline->GetCurrentTime().IsNull()) {
       mStartTime.SetNull();
     }
   } else {
-    mStartTime = StartTimeFromTimelineTime(
-      mTimeline->GetCurrentTime().Value(), aSeekTime, mPlaybackRate);
+    mStartTime.SetValue(mTimeline->GetCurrentTime().Value() -
+                          (aSeekTime.MultDouble(1 / mPlaybackRate)));
   }
 
   mPreviousCurrentTime.SetNull();
 }
 
+void
+Animation::SilentlySetPlaybackRate(double aPlaybackRate)
+{
+  Nullable<TimeDuration> previousTime = GetCurrentTime();
+  mPlaybackRate = aPlaybackRate;
+  if (!previousTime.IsNull()) {
+    SilentlySetCurrentTime(previousTime.Value());
+  }
+}
+
 // https://drafts.csswg.org/web-animations/#cancel-an-animation
 void
 Animation::CancelNoUpdate()
 {
   if (PlayState() != AnimationPlayState::Idle) {
     ResetPendingTasks();
 
     if (mFinished) {
@@ -1085,18 +996,18 @@ Animation::ComposeStyle(ComposeAnimation
     if (pending && mHoldTime.IsNull() && !mStartTime.IsNull()) {
       Nullable<TimeDuration> timeToUse = mPendingReadyTime;
       if (timeToUse.IsNull() &&
           mTimeline &&
           mTimeline->TracksWallclockTime()) {
         timeToUse = mTimeline->ToTimelineTime(TimeStamp::Now());
       }
       if (!timeToUse.IsNull()) {
-        mHoldTime = CurrentTimeFromTimelineTime(
-          timeToUse.Value(), mStartTime.Value(), mPlaybackRate);
+        mHoldTime.SetValue((timeToUse.Value() - mStartTime.Value())
+                            .MultDouble(mPlaybackRate));
       }
     }
 
     KeyframeEffectReadOnly* keyframeEffect = mEffect->AsKeyframeEffect();
     if (keyframeEffect) {
       keyframeEffect->ComposeStyle(Forward<ComposeAnimationResult>(aComposeResult),
                                    aPropertiesToSkip);
     }
@@ -1129,57 +1040,48 @@ Animation::NotifyGeometricAnimationsStar
 // https://drafts.csswg.org/web-animations/#play-an-animation
 void
 Animation::PlayNoUpdate(ErrorResult& aRv, LimitBehavior aLimitBehavior)
 {
   AutoMutationBatchForAnimation mb(*this);
 
   bool abortedPause = mPendingState == PendingState::PausePending;
 
-  double effectivePlaybackRate = CurrentOrPendingPlaybackRate();
-
   Nullable<TimeDuration> currentTime = GetCurrentTime();
-  if (effectivePlaybackRate > 0.0 &&
+  if (mPlaybackRate > 0.0 &&
       (currentTime.IsNull() ||
        (aLimitBehavior == LimitBehavior::AutoRewind &&
         (currentTime.Value() < TimeDuration() ||
          currentTime.Value() >= EffectEnd())))) {
     mHoldTime.SetValue(TimeDuration(0));
-  } else if (effectivePlaybackRate < 0.0 &&
+  } else if (mPlaybackRate < 0.0 &&
              (currentTime.IsNull() ||
               (aLimitBehavior == LimitBehavior::AutoRewind &&
                (currentTime.Value() <= TimeDuration() ||
                 currentTime.Value() > EffectEnd())))) {
     if (EffectEnd() == TimeDuration::Forever()) {
       aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
       return;
     }
     mHoldTime.SetValue(TimeDuration(EffectEnd()));
-  } else if (effectivePlaybackRate == 0.0 && currentTime.IsNull()) {
+  } else if (mPlaybackRate == 0.0 && currentTime.IsNull()) {
     mHoldTime.SetValue(TimeDuration(0));
   }
 
   bool reuseReadyPromise = false;
   if (mPendingState != PendingState::NotPending) {
     CancelPendingTasks();
     reuseReadyPromise = true;
   }
 
-  // If the hold time is null then we're already playing normally and,
-  // typically, we can bail out here.
-  //
-  // However, there are two cases where we can't do that:
-  //
-  // (a) If we just aborted a pause. In this case, for consistency, we need to
-  //     go through the motions of doing an asynchronous start.
-  //
-  // (b) If we have timing changes (specifically a change to the playbackRate)
-  //     that should be applied asynchronously.
-  //
-  if (mHoldTime.IsNull() && !abortedPause && !mPendingPlaybackRate) {
+  // If the hold time is null then we're either already playing normally (and
+  // we can ignore this call) or we aborted a pending pause operation (in which
+  // case, for consistency, we need to go through the motions of doing an
+  // asynchronous start even though we already have a resolved start time).
+  if (mHoldTime.IsNull() && !abortedPause) {
     return;
   }
 
   // Clear the start time until we resolve a new one. We do this except
   // for the case where we are aborting a pause and don't have a hold time.
   //
   // If we're aborting a pause and *do* have a hold time (e.g. because
   // the animation is finished or we just applied the auto-rewind behavior
@@ -1266,79 +1168,55 @@ Animation::PauseNoUpdate(ErrorResult& aR
   }
 
   UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
   if (IsRelevant()) {
     nsNodeUtils::AnimationChanged(this);
   }
 }
 
-// https://drafts.csswg.org/web-animations/#play-an-animation
 void
 Animation::ResumeAt(const TimeDuration& aReadyTime)
 {
   // This method is only expected to be called for an animation that is
   // waiting to play. We can easily adapt it to handle other states
   // but it's currently not necessary.
   MOZ_ASSERT(mPendingState == PendingState::PlayPending,
              "Expected to resume a play-pending animation");
   MOZ_ASSERT(!mHoldTime.IsNull() || !mStartTime.IsNull(),
              "An animation in the play-pending state should have either a"
              " resolved hold time or resolved start time");
 
-  AutoMutationBatchForAnimation mb(*this);
-  bool hadPendingPlaybackRate = mPendingPlaybackRate.isSome();
-
-  if (!mHoldTime.IsNull()) {
-    // The hold time is set, so we don't need any special handling to preserve
-    // the current time.
-    ApplyPendingPlaybackRate();
-    mStartTime =
-      StartTimeFromTimelineTime(aReadyTime, mHoldTime.Value(), mPlaybackRate);
+  // If we aborted a pending pause operation we will already have a start time
+  // we should use. In all other cases, we resolve it from the ready time.
+  if (mStartTime.IsNull()) {
+    mStartTime = StartTimeFromReadyTime(aReadyTime);
     if (mPlaybackRate != 0) {
       mHoldTime.SetNull();
     }
-  } else if (!mStartTime.IsNull() && mPendingPlaybackRate) {
-    // Apply any pending playback rate, preserving the current time.
-    TimeDuration currentTimeToMatch = CurrentTimeFromTimelineTime(
-      aReadyTime, mStartTime.Value(), mPlaybackRate);
-    ApplyPendingPlaybackRate();
-    mStartTime =
-      StartTimeFromTimelineTime(aReadyTime, currentTimeToMatch, mPlaybackRate);
-    if (mPlaybackRate == 0) {
-      mHoldTime.SetValue(currentTimeToMatch);
-    }
   }
-
   mPendingState = PendingState::NotPending;
 
   UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
 
-  // If we had a pending playback rate, we will have now applied it so we need
-  // to notify observers.
-  if (hadPendingPlaybackRate && IsRelevant()) {
-    nsNodeUtils::AnimationChanged(this);
-  }
-
   if (mReady) {
     mReady->MaybeResolve(this);
   }
 }
 
 void
 Animation::PauseAt(const TimeDuration& aReadyTime)
 {
   MOZ_ASSERT(mPendingState == PendingState::PausePending,
              "Expected to pause a pause-pending animation");
 
   if (!mStartTime.IsNull() && mHoldTime.IsNull()) {
-    mHoldTime = CurrentTimeFromTimelineTime(
-      aReadyTime, mStartTime.Value(), mPlaybackRate);
+    mHoldTime.SetValue((aReadyTime - mStartTime.Value())
+                        .MultDouble(mPlaybackRate));
   }
-  ApplyPendingPlaybackRate();
   mStartTime.SetNull();
   mPendingState = PendingState::NotPending;
 
   UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
 
   if (mReady) {
     mReady->MaybeResolve(this);
   }
@@ -1388,20 +1266,18 @@ Animation::UpdateFinishedState(SeekFlag 
       } else {
         mHoldTime.SetValue(0);
       }
     } else if (mPlaybackRate != 0.0 &&
                !currentTime.IsNull() &&
                mTimeline &&
                !mTimeline->GetCurrentTime().IsNull()) {
       if (aSeekFlag == SeekFlag::DidSeek && !mHoldTime.IsNull()) {
-        mStartTime =
-          StartTimeFromTimelineTime(mTimeline->GetCurrentTime().Value(),
-                                    mHoldTime.Value(),
-                                    mPlaybackRate);
+        mStartTime.SetValue(mTimeline->GetCurrentTime().Value() -
+                             (mHoldTime.Value().MultDouble(1 / mPlaybackRate)));
       }
       mHoldTime.SetNull();
     }
   }
 
   bool currentFinishedState = PlayState() == AnimationPlayState::Finished;
   if (currentFinishedState && !mFinishedIsResolved) {
     DoFinishNotification(aSyncNotifyFlag);
@@ -1476,18 +1352,16 @@ Animation::CancelPendingTasks()
 void
 Animation::ResetPendingTasks()
 {
   if (mPendingState == PendingState::NotPending) {
     return;
   }
 
   CancelPendingTasks();
-  ApplyPendingPlaybackRate();
-
   if (mReady) {
     mReady->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     mReady = nullptr;
   }
 }
 
 bool
 Animation::IsPossiblyOrphanedPendingAnimation() const
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -100,32 +100,29 @@ public:
   void GetId(nsAString& aResult) const { aResult = mId; }
   void SetId(const nsAString& aId);
   AnimationEffectReadOnly* GetEffect() const { return mEffect; }
   void SetEffect(AnimationEffectReadOnly* aEffect);
   AnimationTimeline* GetTimeline() const { return mTimeline; }
   void SetTimeline(AnimationTimeline* aTimeline);
   Nullable<TimeDuration> GetStartTime() const { return mStartTime; }
   void SetStartTime(const Nullable<TimeDuration>& aNewStartTime);
-  Nullable<TimeDuration> GetCurrentTime() const {
-    return GetCurrentTimeForHoldTime(mHoldTime);
-  }
+  Nullable<TimeDuration> GetCurrentTime() const;
   void SetCurrentTime(const TimeDuration& aNewCurrentTime);
   double PlaybackRate() const { return mPlaybackRate; }
   void SetPlaybackRate(double aPlaybackRate);
   AnimationPlayState PlayState() const;
   bool Pending() const { return mPendingState != PendingState::NotPending; }
   virtual Promise* GetReady(ErrorResult& aRv);
   Promise* GetFinished(ErrorResult& aRv);
   void Cancel();
   void Finish(ErrorResult& aRv);
   virtual void Play(ErrorResult& aRv, LimitBehavior aLimitBehavior);
   virtual void Pause(ErrorResult& aRv);
   void Reverse(ErrorResult& aRv);
-  void UpdatePlaybackRate(double aPlaybackRate);
   bool IsRunningOnCompositor() const;
   IMPL_EVENT_HANDLER(finish);
   IMPL_EVENT_HANDLER(cancel);
 
   // Wrapper functions for Animation DOM methods when called
   // from script.
   //
   // We often use the same methods internally and from script but when called
@@ -240,64 +237,21 @@ public:
    *
    * This method returns the start time, if resolved. Otherwise, if we have
    * a pending ready time, it returns the corresponding start time. If neither
    * of those are available, it returns null.
    */
   Nullable<TimeDuration> GetCurrentOrPendingStartTime() const;
 
   /**
-   * As with the start time, we should use the pending playback rate when
-   * producing layer animations.
-   */
-  double CurrentOrPendingPlaybackRate() const
-  {
-    return mPendingPlaybackRate.valueOr(mPlaybackRate);
-  }
-  bool HasPendingPlaybackRate() const { return mPendingPlaybackRate.isSome(); }
-
-  /**
-   * The following relationship from the definition of the 'current time' is
-   * re-used in many algorithms so we extract it here into a static method that
-   * can be re-used:
-   *
-   *   current time = (timeline time - start time) * playback rate
-   *
-   * As per https://drafts.csswg.org/web-animations-1/#current-time
+   * Calculates the corresponding start time to use for an animation that is
+   * currently pending with current time |mHoldTime| but should behave
+   * as if it began or resumed playback at timeline time |aReadyTime|.
    */
-  static TimeDuration CurrentTimeFromTimelineTime(
-    const TimeDuration& aTimelineTime,
-    const TimeDuration& aStartTime,
-    float aPlaybackRate)
-  {
-    return (aTimelineTime - aStartTime).MultDouble(aPlaybackRate);
-  }
-
-  /**
-   * As with calculating the current time, we often need to calculate a start
-   * time from a current time. The following method simply inverts the current
-   * time relationship.
-   *
-   * In each case where this is used, the desired behavior for playbackRate ==
-   * 0 is to return the specified timeline time (often referred to as the ready
-   * time).
-   */
-  static TimeDuration StartTimeFromTimelineTime(
-    const TimeDuration& aTimelineTime,
-    const TimeDuration& aCurrentTime,
-    float aPlaybackRate)
-  {
-    TimeDuration result = aTimelineTime;
-    if (aPlaybackRate == 0) {
-      return result;
-    }
-
-    result -= aCurrentTime.MultDouble(1.0 / aPlaybackRate);
-    return result;
-  }
+  TimeDuration StartTimeFromReadyTime(const TimeDuration& aReadyTime) const;
 
   /**
    * Converts a time in the timescale of this Animation's currentTime, to a
    * TimeStamp. Returns a null TimeStamp if the conversion cannot be performed
    * because of the current state of this Animation (e.g. it has no timeline, a
    * zero playbackRate, an unresolved start time etc.) or the value of the time
    * passed-in (e.g. an infinite time).
    */
@@ -397,38 +351,32 @@ public:
    * We need to do this synchronously because after a CSS animation/transition
    * is canceled, it will be released by its owning element and may not still
    * exist when we would normally go to queue events on the next tick.
    */
   virtual void MaybeQueueCancelEvent(const StickyTimeDuration& aActiveTime) {};
 
 protected:
   void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime);
+  void SilentlySetPlaybackRate(double aPlaybackRate);
   void CancelNoUpdate();
   void PlayNoUpdate(ErrorResult& aRv, LimitBehavior aLimitBehavior);
   void PauseNoUpdate(ErrorResult& aRv);
   void ResumeAt(const TimeDuration& aReadyTime);
   void PauseAt(const TimeDuration& aReadyTime);
   void FinishPendingAt(const TimeDuration& aReadyTime)
   {
     if (mPendingState == PendingState::PlayPending) {
       ResumeAt(aReadyTime);
     } else if (mPendingState == PendingState::PausePending) {
       PauseAt(aReadyTime);
     } else {
       NS_NOTREACHED("Can't finish pending if we're not in a pending state");
     }
   }
-  void ApplyPendingPlaybackRate()
-  {
-    if (mPendingPlaybackRate) {
-      mPlaybackRate = *mPendingPlaybackRate;
-      mPendingPlaybackRate.reset();
-    }
-  }
 
   /**
    * Finishing behavior depends on if changes to timing occurred due
    * to a seek or regular playback.
    */
   enum class SeekFlag {
     NoSeek,
     DidSeek
@@ -467,47 +415,34 @@ protected:
 
   /**
    * Returns true if this animation is not only play-pending, but has
    * yet to be given a pending ready time. This roughly corresponds to
    * animations that are waiting to be painted (since we set the pending
    * ready time at the end of painting). Identifying such animations is
    * useful because in some cases animations that are painted together
    * may need to be synchronized.
-   *
-   * We don't, however, want to include animations with a fixed start time such
-   * as animations that are simply having their playbackRate updated or which
-   * are resuming from an aborted pause.
    */
   bool IsNewlyStarted() const {
     return mPendingState == PendingState::PlayPending &&
-           mPendingReadyTime.IsNull() &&
-           mStartTime.IsNull();
+           mPendingReadyTime.IsNull();
   }
   bool IsPossiblyOrphanedPendingAnimation() const;
   StickyTimeDuration EffectEnd() const;
 
-  Nullable<TimeDuration> GetCurrentTimeForHoldTime(
-    const Nullable<TimeDuration>& aHoldTime) const;
-  Nullable<TimeDuration> GetUnconstrainedCurrentTime() const
-  {
-    return GetCurrentTimeForHoldTime(Nullable<TimeDuration>());
-  }
-
   nsIDocument* GetRenderedDocument() const;
 
   RefPtr<AnimationTimeline> mTimeline;
   RefPtr<AnimationEffectReadOnly> mEffect;
   // The beginning of the delay period.
   Nullable<TimeDuration> mStartTime; // Timeline timescale
   Nullable<TimeDuration> mHoldTime;  // Animation timescale
   Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale
   Nullable<TimeDuration> mPreviousCurrentTime; // Animation timescale
   double mPlaybackRate;
-  Maybe<double> mPendingPlaybackRate;
 
   // A Promise that is replaced on each call to Play()
   // and fulfilled when Play() is successfully completed.
   // This object is lazily created by GetReady.
   // See http://drafts.csswg.org/web-animations/#current-ready-promise
   RefPtr<Promise> mReady;
 
   // A Promise that is resolved when we reach the end of the effect, or
--- a/dom/webidl/Animation.webidl
+++ b/dom/webidl/Animation.webidl
@@ -39,17 +39,16 @@ interface Animation : EventTarget {
            attribute EventHandler       oncancel;
   void cancel ();
   [Throws]
   void finish ();
   [Throws, BinaryName="playFromJS"]
   void play ();
   [Throws, BinaryName="pauseFromJS"]
   void pause ();
-  void updatePlaybackRate (double playbackRate);
   [Throws]
   void reverse ();
 };
 
 // Non-standard extensions
 partial interface Animation {
   [ChromeOnly] readonly attribute boolean isRunningOnCompositor;
 };
--- a/gfx/layers/AnimationInfo.cpp
+++ b/gfx/layers/AnimationInfo.cpp
@@ -2,17 +2,16 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AnimationInfo.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
 #include "mozilla/layers/AnimationHelper.h"
-#include "mozilla/dom/Animation.h"
 
 namespace mozilla {
 namespace layers {
 
 AnimationInfo::AnimationInfo(LayerManager* aManager) :
   mManager(aManager),
   mCompositorAnimationsId(0),
   mAnimationGeneration(0),
@@ -99,37 +98,27 @@ AnimationInfo::SetCompositorAnimations(c
 bool
 AnimationInfo::StartPendingAnimations(const TimeStamp& aReadyTime)
 {
   bool updated = false;
   for (size_t animIdx = 0, animEnd = mAnimations.Length();
        animIdx < animEnd; animIdx++) {
     Animation& anim = mAnimations[animIdx];
 
-    // If the animation is doing an async update of its playback rate, then we
-    // want to match whatever its current time would be at *aReadyTime*.
-    if (!std::isnan(anim.previousPlaybackRate()) &&
-        anim.startTime().type() == MaybeTimeDuration::TTimeDuration &&
-        !anim.originTime().IsNull() && !anim.isNotPlaying()) {
-      TimeDuration readyTime = aReadyTime - anim.originTime();
-      anim.holdTime() = dom::Animation::CurrentTimeFromTimelineTime(
-        readyTime,
-        anim.startTime().get_TimeDuration(),
-        anim.previousPlaybackRate());
-      // Make start time null so that we know to update it below.
-      anim.startTime() = null_t();
-    }
-
     // If the animation is play-pending, resolve the start time.
+    // This mirrors the calculation in Animation::StartTimeFromReadyTime.
     if (anim.startTime().type() == MaybeTimeDuration::Tnull_t &&
         !anim.originTime().IsNull() &&
         !anim.isNotPlaying()) {
       TimeDuration readyTime = aReadyTime - anim.originTime();
-      anim.startTime() = dom::Animation::StartTimeFromTimelineTime(
-        readyTime, anim.holdTime(), anim.playbackRate());
+      anim.startTime() =
+        anim.playbackRate() == 0
+        ? readyTime
+        : readyTime - anim.holdTime().MultDouble(1.0 /
+                                                 anim.playbackRate());
       updated = true;
     }
   }
   return updated;
 }
 
 void
 AnimationInfo::TransferMutatedFlagToLayer(Layer* aLayer)
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -236,25 +236,16 @@ struct Animation {
   float iterationStart;
   // This uses the NS_STYLE_ANIMATION_DIRECTION_* constants.
   uint8_t direction;
   // This uses dom::FillMode.
   uint8_t fillMode;
   nsCSSPropertyID property;
   AnimationData data;
   float playbackRate;
-  // When performing an asynchronous update to the playbackRate, |playbackRate|
-  // above is the updated playbackRate while |previousPlaybackRate| is the
-  // existing playbackRate. This is used by AnimationInfo to update the
-  // startTime based on the 'readyTime' (timestamp at the end of painting)
-  // and is not used beyond that point.
-  //
-  // It is set to numeric_limits<float>::quiet_NaN() when no asynchronous update
-  // to the playbackRate is being performed.
-  float previousPlaybackRate;
   // This is used in the transformed progress calculation.
   TimingFunction easingFunction;
   uint8_t iterationComposite;
   // True if the animation has a fixed current time (e.g. paused and
   // forward-filling animations).
   bool isNotPlaying;
   // The base style that animations should composite with. This is only set for
   // animations with a composite mode of additive or accumulate, and only for
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -566,21 +566,17 @@ AddAnimationForProperty(nsIFrame* aFrame
   animation->delay() = timing.Delay();
   animation->endDelay() = timing.EndDelay();
   animation->duration() = computedTiming.mDuration;
   animation->iterations() = computedTiming.mIterations;
   animation->iterationStart() = computedTiming.mIterationStart;
   animation->direction() = static_cast<uint8_t>(timing.Direction());
   animation->fillMode() = static_cast<uint8_t>(computedTiming.mFill);
   animation->property() = aProperty.mProperty;
-  animation->playbackRate() = aAnimation->CurrentOrPendingPlaybackRate();
-  animation->previousPlaybackRate() =
-    aAnimation->HasPendingPlaybackRate()
-      ? aAnimation->PlaybackRate()
-      : std::numeric_limits<float>::quiet_NaN();
+  animation->playbackRate() = aAnimation->PlaybackRate();
   animation->data() = aData;
   animation->easingFunction() = ToTimingFunction(timing.TimingFunction());
   animation->iterationComposite() =
     static_cast<uint8_t>(aAnimation->GetEffect()->
                          AsKeyframeEffect()->IterationComposite());
   animation->isNotPlaying() = !aAnimation->IsPlaying();
 
   TransformReferenceBox refBox(aFrame);
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -358577,22 +358577,16 @@
     ]
    ],
    "web-animations/animation-model/animation-types/visibility.html": [
     [
      "/web-animations/animation-model/animation-types/visibility.html",
      {}
     ]
    ],
-   "web-animations/animation-model/combining-effects/applying-the-composited-result.html": [
-    [
-     "/web-animations/animation-model/combining-effects/applying-the-composited-result.html",
-     {}
-    ]
-   ],
    "web-animations/animation-model/combining-effects/effect-composition.html": [
     [
      "/web-animations/animation-model/combining-effects/effect-composition.html",
      {}
     ]
    ],
    "web-animations/animation-model/keyframe-effects/effect-value-context.html": [
     [
@@ -358649,16 +358643,22 @@
     ]
    ],
    "web-animations/interfaces/Animation/effect.html": [
     [
      "/web-animations/interfaces/Animation/effect.html",
      {}
     ]
    ],
+   "web-animations/interfaces/Animation/finish.html": [
+    [
+     "/web-animations/interfaces/Animation/finish.html",
+     {}
+    ]
+   ],
    "web-animations/interfaces/Animation/finished.html": [
     [
      "/web-animations/interfaces/Animation/finished.html",
      {}
     ]
    ],
    "web-animations/interfaces/Animation/id.html": [
     [
@@ -358697,16 +358697,22 @@
     ]
    ],
    "web-animations/interfaces/Animation/play.html": [
     [
      "/web-animations/interfaces/Animation/play.html",
      {}
     ]
    ],
+   "web-animations/interfaces/Animation/playbackRate.html": [
+    [
+     "/web-animations/interfaces/Animation/playbackRate.html",
+     {}
+    ]
+   ],
    "web-animations/interfaces/Animation/ready.html": [
     [
      "/web-animations/interfaces/Animation/ready.html",
      {}
     ]
    ],
    "web-animations/interfaces/Animation/startTime.html": [
     [
@@ -358895,16 +358901,22 @@
     ]
    ],
    "web-animations/timing-model/animations/canceling-an-animation.html": [
     [
      "/web-animations/timing-model/animations/canceling-an-animation.html",
      {}
     ]
    ],
+   "web-animations/timing-model/animations/current-time.html": [
+    [
+     "/web-animations/timing-model/animations/current-time.html",
+     {}
+    ]
+   ],
    "web-animations/timing-model/animations/finishing-an-animation.html": [
     [
      "/web-animations/timing-model/animations/finishing-an-animation.html",
      {}
     ]
    ],
    "web-animations/timing-model/animations/pausing-an-animation.html": [
     [
@@ -358925,55 +358937,31 @@
     ]
    ],
    "web-animations/timing-model/animations/reversing-an-animation.html": [
     [
      "/web-animations/timing-model/animations/reversing-an-animation.html",
      {}
     ]
    ],
-   "web-animations/timing-model/animations/seamlessly-updating-the-playback-rate-of-an-animation.html": [
-    [
-     "/web-animations/timing-model/animations/seamlessly-updating-the-playback-rate-of-an-animation.html",
-     {}
-    ]
-   ],
-   "web-animations/timing-model/animations/setting-the-current-time-of-an-animation.html": [
-    [
-     "/web-animations/timing-model/animations/setting-the-current-time-of-an-animation.html",
-     {}
-    ]
-   ],
-   "web-animations/timing-model/animations/setting-the-playback-rate-of-an-animation.html": [
-    [
-     "/web-animations/timing-model/animations/setting-the-playback-rate-of-an-animation.html",
-     {}
-    ]
-   ],
-   "web-animations/timing-model/animations/setting-the-start-time-of-an-animation.html": [
-    [
-     "/web-animations/timing-model/animations/setting-the-start-time-of-an-animation.html",
-     {}
-    ]
-   ],
-   "web-animations/timing-model/animations/setting-the-target-effect-of-an-animation.html": [
-    [
-     "/web-animations/timing-model/animations/setting-the-target-effect-of-an-animation.html",
-     {}
-    ]
-   ],
-   "web-animations/timing-model/animations/setting-the-timeline-of-an-animation.html": [
-    [
-     "/web-animations/timing-model/animations/setting-the-timeline-of-an-animation.html",
-     {}
-    ]
-   ],
-   "web-animations/timing-model/animations/the-current-time-of-an-animation.html": [
-    [
-     "/web-animations/timing-model/animations/the-current-time-of-an-animation.html",
+   "web-animations/timing-model/animations/set-the-animation-start-time.html": [
+    [
+     "/web-animations/timing-model/animations/set-the-animation-start-time.html",
+     {}
+    ]
+   ],
+   "web-animations/timing-model/animations/set-the-target-effect-of-an-animation.html": [
+    [
+     "/web-animations/timing-model/animations/set-the-target-effect-of-an-animation.html",
+     {}
+    ]
+   ],
+   "web-animations/timing-model/animations/set-the-timeline-of-an-animation.html": [
+    [
+     "/web-animations/timing-model/animations/set-the-timeline-of-an-animation.html",
      {}
     ]
    ],
    "web-animations/timing-model/animations/updating-the-finished-state.html": [
     [
      "/web-animations/timing-model/animations/updating-the-finished-state.html",
      {}
     ]
@@ -591488,20 +591476,16 @@
   "web-animations/animation-model/animation-types/property-types.js": [
    "d5ccae3dd857f15eab45de2e70b332aaa126a575",
    "support"
   ],
   "web-animations/animation-model/animation-types/visibility.html": [
    "da3370704ca9e83a1171a64320a240e3145fab2c",
    "testharness"
   ],
-  "web-animations/animation-model/combining-effects/applying-the-composited-result.html": [
-   "5262331e6a2f957dd70e9a9888825250de65fd5b",
-   "testharness"
-  ],
   "web-animations/animation-model/combining-effects/effect-composition.html": [
    "5d6c3904de02eb3b6c890163ccdc6b8cb6499e56",
    "testharness"
   ],
   "web-animations/animation-model/keyframe-effects/effect-value-context.html": [
    "da405e4bfc35d5d0b4c151706b09eb1a84d2f0da",
    "testharness"
   ],
@@ -591536,26 +591520,30 @@
   "web-animations/interfaces/Animation/constructor.html": [
    "f4dc4fdca61255557ed346412e134745bce1a3ed",
    "testharness"
   ],
   "web-animations/interfaces/Animation/effect.html": [
    "4445fc8bd2120fb1e212dfc6a1fcf786a531ee6f",
    "testharness"
   ],
+  "web-animations/interfaces/Animation/finish.html": [
+   "64acecec8528b4d241d5dcb9248ef82eafa02810",
+   "testharness"
+  ],
   "web-animations/interfaces/Animation/finished.html": [
    "ffcba3379db7094455a7798e4d5972d8e52caec5",
    "testharness"
   ],
   "web-animations/interfaces/Animation/id.html": [
    "4e3dd92351d76c5c7d09ddd1ca025520f4c8875d",
    "testharness"
   ],
   "web-animations/interfaces/Animation/idlharness.html": [
-   "d61aa2d95ea31809a275183408e822c8c1eec87d",
+   "989e773dbf3d7d57f26b41108bc3d7f0b3ea3168",
    "testharness"
   ],
   "web-animations/interfaces/Animation/oncancel.html": [
    "82abc08a0b416f5198239464fb4fc01d2edd6e1c",
    "testharness"
   ],
   "web-animations/interfaces/Animation/onfinish.html": [
    "db82fabeaf2b646647f134634fef30f05e5ec7f8",
@@ -591568,16 +591556,20 @@
   "web-animations/interfaces/Animation/pending.html": [
    "5677f7e8b076dc096d636aaaa4d4191c286f1d90",
    "testharness"
   ],
   "web-animations/interfaces/Animation/play.html": [
    "54edbdd6c0e1953f8d0e2bfbb92bfe318114ab74",
    "testharness"
   ],
+  "web-animations/interfaces/Animation/playbackRate.html": [
+   "a298a65aaeb5a337fe894f0160493693f309c2a1",
+   "testharness"
+  ],
   "web-animations/interfaces/Animation/ready.html": [
    "bd4a18205791b2b0271a6266dba3ebc8482c835b",
    "testharness"
   ],
   "web-animations/interfaces/Animation/startTime.html": [
    "01f669542434f03d37e9f148a4f3135fe3122d46",
    "testharness"
   ],
@@ -591721,69 +591713,57 @@
    "3edd2c4bdd8409c2c12f08bc998dd8d532e0fd7d",
    "testharness"
   ],
   "web-animations/timing-model/animation-effects/simple-iteration-progress.html": [
    "602fe7e6880e0b18329262699872c696f451d744",
    "testharness"
   ],
   "web-animations/timing-model/animations/canceling-an-animation.html": [
-   "e03baa30d438529a0ebe39f0f623563aa9850d74",
+   "d82cbc5caf654b9811c90d5165fb0429891cb149",
+   "testharness"
+  ],
+  "web-animations/timing-model/animations/current-time.html": [
+   "52d23e752878c821754b2c2b752e7393882609e2",
    "testharness"
   ],
   "web-animations/timing-model/animations/finishing-an-animation.html": [
-   "4c1cf823a81e72541abcafaa08950cf87424ae55",
+   "8d430adcb97bf3dab9703bc2d31be23e1adaec85",
    "testharness"
   ],
   "web-animations/timing-model/animations/pausing-an-animation.html": [
-   "a4cb7b89c778ad5c294eeb55e94461e19ca8eb4b",
+   "c46fbcb8bc40fc3ee26e10802a205926ab97a84f",
    "testharness"
   ],
   "web-animations/timing-model/animations/play-states.html": [
-   "0ab2fa3a464001272d1af541ea769fa967490c3b",
+   "3ec76eff991e306699b21fb03bc1f346ffd9cee3",
    "testharness"
   ],
   "web-animations/timing-model/animations/playing-an-animation.html": [
-   "10580a1e72892208a14c6fe55091e998edf0171c",
+   "1ae05a904e5b4fbcf1d904f02825f836da7b4c18",
    "testharness"
   ],
   "web-animations/timing-model/animations/reversing-an-animation.html": [
-   "72b89e78ca7dac261af8de370389d89c810b3718",
-   "testharness"
-  ],
-  "web-animations/timing-model/animations/seamlessly-updating-the-playback-rate-of-an-animation.html": [
-   "a7e28aa0b40a39b00da257e347cb6ecf8d1d2882",
-   "testharness"
-  ],
-  "web-animations/timing-model/animations/setting-the-current-time-of-an-animation.html": [
-   "a7da92b9624750eccb9dce1d32e522fdbb65176f",
-   "testharness"
-  ],
-  "web-animations/timing-model/animations/setting-the-playback-rate-of-an-animation.html": [
-   "b2698d9a829a1eadb3ef3b6d8e0050e7a6315305",
-   "testharness"
-  ],
-  "web-animations/timing-model/animations/setting-the-start-time-of-an-animation.html": [
-   "cf6040eb52964f12b06a9e3cdf14948ce8141270",
-   "testharness"
-  ],
-  "web-animations/timing-model/animations/setting-the-target-effect-of-an-animation.html": [
-   "5575a251b9c265d98471e758b3cf9b218e381cba",
-   "testharness"
-  ],
-  "web-animations/timing-model/animations/setting-the-timeline-of-an-animation.html": [
-   "e4e134b566327c9d7316aee4f3e7fe4eeb2116ba",
-   "testharness"
-  ],
-  "web-animations/timing-model/animations/the-current-time-of-an-animation.html": [
-   "90ba3d81ee9e32b1f13845301c4ad1c8ad47f2f7",
+   "3afdb3cc9a9dafb28ebe46902276c19c24aeb9a8",
+   "testharness"
+  ],
+  "web-animations/timing-model/animations/set-the-animation-start-time.html": [
+   "fa26feebcde00a5b0b63f8f3587acc313a58f26a",
+   "testharness"
+  ],
+  "web-animations/timing-model/animations/set-the-target-effect-of-an-animation.html": [
+   "3b7f1f60cd771ff8587daf7ab76ccbecff59f781",
+   "testharness"
+  ],
+  "web-animations/timing-model/animations/set-the-timeline-of-an-animation.html": [
+   "bd33cb8638aa373b17cda20906af5aea2f5a7503",
    "testharness"
   ],
   "web-animations/timing-model/animations/updating-the-finished-state.html": [
-   "59e7ed8e4eac5c9edf2526ef748b22e1877b7016",
+   "c30161f7d5a20db616ade354133ae6a8989d149f",
    "testharness"
   ],
   "web-animations/timing-model/time-transformations/transformed-progress.html": [
    "2e55f43def584a67eeb313f050154cd146002938",
    "testharness"
   ],
   "web-animations/timing-model/timelines/document-timelines.html": [
    "d0fcb390c19c9ede7288278dc11ea5b3d33671cb",
deleted file mode 100644
--- a/testing/web-platform/tests/web-animations/animation-model/combining-effects/applying-the-composited-result.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>Applying the composited result</title>
-<link rel="help"
-  href="https://drafts.csswg.org/web-animations-1/#applying-the-composited-result">
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src="../../testcommon.js"></script>
-<div id="log"></div>
-<script>
-'use strict';
-
-promise_test(async t => {
-  const div = createDiv(t);
-  div.style.marginLeft = '10px';
-  const animation = div.animate(
-    { marginLeft: ['100px', '200px'] },
-    100 * MS_PER_SEC
-  );
-  await animation.ready;
-
-  animation.finish();
-
-  const marginLeft = parseFloat(getComputedStyle(div).marginLeft);
-  assert_equals(marginLeft, 10, 'The computed style should be reset');
-}, 'Finishing an animation that does not fill forwards causes its animation'
-   + ' style to be cleared');
-
-</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/web-animations/interfaces/Animation/finish.html
@@ -0,0 +1,246 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Animation.finish</title>
+<link rel="help" href="https://drafts.csswg.org/web-animations/#dom-animation-finish">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../testcommon.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+const gKeyFrames = { 'marginLeft': ['100px', '200px'] };
+
+test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(gKeyFrames, 100 * MS_PER_SEC);
+  animation.playbackRate = 0;
+
+  assert_throws({name: 'InvalidStateError'}, () => {
+    animation.finish();
+  });
+}, 'Test exceptions when finishing non-running animation');
+
+test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(gKeyFrames,
+                                { duration : 100 * MS_PER_SEC,
+                                  iterations : Infinity });
+
+  assert_throws({name: 'InvalidStateError'}, () => {
+    animation.finish();
+  });
+}, 'Test exceptions when finishing infinite animation');
+
+test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(gKeyFrames, 100 * MS_PER_SEC);
+  animation.finish();
+
+  assert_equals(animation.currentTime, 100 * MS_PER_SEC,
+                'After finishing, the currentTime should be set to the end ' +
+                'of the active duration');
+}, 'Test finishing of animation');
+
+test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(gKeyFrames, 100 * MS_PER_SEC);
+   // 1s past effect end
+  animation.currentTime =
+    animation.effect.getComputedTiming().endTime + 1 * MS_PER_SEC;
+  animation.finish();
+
+  assert_equals(animation.currentTime, 100 * MS_PER_SEC,
+                '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');
+
+promise_test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(gKeyFrames, 100 * MS_PER_SEC);
+  animation.currentTime = 100 * MS_PER_SEC;
+  return animation.finished.then(() => {
+    animation.playbackRate = -1;
+    animation.finish();
+
+    assert_equals(animation.currentTime, 0,
+                  'After finishing a reversed animation the currentTime ' +
+                  'should be set to zero');
+  });
+}, 'Test finishing of reversed animation');
+
+promise_test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(gKeyFrames, 100 * MS_PER_SEC);
+  animation.currentTime = 100 * MS_PER_SEC;
+  return animation.finished.then(() => {
+    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');
+  });
+}, 'Test finishing of reversed animation with a current time less than zero');
+
+promise_test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(gKeyFrames, 100 * MS_PER_SEC);
+  animation.pause();
+  return animation.ready.then(() => {
+    animation.finish();
+
+    assert_equals(animation.playState, 'finished',
+                  'The play state of a paused animation should become ' +
+                  '"finished" after finish() is called');
+    assert_times_equal(animation.startTime,
+                       animation.timeline.currentTime - 100 * MS_PER_SEC,
+                       'The start time of a paused animation should be set ' +
+                       'after calling finish()');
+  });
+}, 'Test finish() while paused');
+
+test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(gKeyFrames, 100 * MS_PER_SEC);
+  animation.pause();
+  // Update playbackRate so we can test that the calculated startTime
+  // respects it
+  animation.playbackRate = 2;
+  // While animation is still pause-pending call finish()
+  animation.finish();
+
+  assert_equals(animation.playState, 'finished',
+                'The play state of a pause-pending animation should become ' +
+                '"finished" after finish() is called');
+  assert_times_equal(animation.startTime,
+                     animation.timeline.currentTime - 100 * MS_PER_SEC / 2,
+                     'The start time of a pause-pending animation should ' +
+                     'be set after calling finish()');
+}, 'Test finish() while pause-pending with positive playbackRate');
+
+test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(gKeyFrames, 100 * MS_PER_SEC);
+  animation.pause();
+  animation.playbackRate = -2;
+  animation.finish();
+
+  assert_equals(animation.playState, 'finished',
+                'The play state of a pause-pending animation should become ' +
+                '"finished" after finish() is called');
+  assert_equals(animation.startTime, animation.timeline.currentTime,
+                'The start time of a pause-pending animation should be ' +
+                'set after calling finish()');
+}, 'Test finish() while pause-pending with negative playbackRate');
+
+test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(gKeyFrames, 100 * MS_PER_SEC);
+  animation.playbackRate = 0.5;
+  animation.finish();
+
+  assert_equals(animation.playState, 'finished',
+                'The play state of a play-pending animation should become ' +
+                '"finished" after finish() is called');
+  assert_times_equal(animation.startTime,
+                     animation.timeline.currentTime - 100 * MS_PER_SEC / 0.5,
+                     'The start time of a play-pending animation should ' +
+                     'be set after calling finish()');
+}, 'Test finish() while play-pending');
+
+// FIXME: Add a test for when we are play-pending without an active timeline.
+// - In that case even after calling finish() we should still be pending but
+//   the current time should be updated
+
+promise_test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(gKeyFrames, 100 * MS_PER_SEC);
+  return animation.ready.then(() => {
+    animation.pause();
+    animation.play();
+    // We are now in the unusual situation of being play-pending whilst having
+    // a resolved start time. Check that finish() still triggers a transition
+    // to the finished state immediately.
+    animation.finish();
+
+    assert_equals(animation.playState, 'finished',
+                  'After aborting a pause then calling finish() the play ' +
+                  'state of an animation should become "finished" immediately');
+  });
+}, 'Test finish() during aborted pause');
+
+promise_test(t => {
+  const div = createDiv(t);
+  div.style.marginLeft = '10px';
+  const animation = div.animate(gKeyFrames, 100 * MS_PER_SEC);
+  return animation.ready.then(() => {
+    animation.finish();
+    const marginLeft = parseFloat(getComputedStyle(div).marginLeft);
+
+    assert_equals(marginLeft, 10,
+                  'The computed style should be reset when finish() is ' +
+                  'called');
+  });
+}, 'Test resetting of computed style');
+
+promise_test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(gKeyFrames, 100 * MS_PER_SEC);
+  let resolvedFinished = false;
+  animation.finished.then(() => {
+    resolvedFinished = true;
+  });
+
+  return animation.ready.then(() => {
+    animation.finish();
+  }).then(() => {
+    assert_true(resolvedFinished,
+      'Animation.finished should be resolved soon after ' +
+      'Animation.finish()');
+  });
+}, 'Test finish() resolves finished promise synchronously');
+
+promise_test(t => {
+  const effect = new KeyframeEffectReadOnly(null, gKeyFrames, 100 * MS_PER_SEC);
+  const animation = new Animation(effect, document.timeline);
+  let resolvedFinished = false;
+  animation.finished.then(() => {
+    resolvedFinished = true;
+  });
+
+  return animation.ready.then(() => {
+    animation.finish();
+  }).then(() => {
+    assert_true(resolvedFinished,
+                'Animation.finished should be resolved soon after ' +
+                'Animation.finish()');
+  });
+}, 'Test finish() resolves finished promise synchronously with an animation ' +
+   'without a target');
+
+promise_test(t => {
+  const effect = new KeyframeEffectReadOnly(null, gKeyFrames, 100 * MS_PER_SEC);
+  const animation = new Animation(effect, document.timeline);
+  animation.play();
+
+  let resolvedFinished = false;
+  animation.finished.then(() => {
+    resolvedFinished = true;
+  });
+
+  return animation.ready.then(() => {
+    animation.currentTime = animation.effect.getComputedTiming().endTime - 1;
+    return waitForAnimationFrames(2);
+  }).then(() => {
+    assert_true(resolvedFinished,
+                'Animation.finished should be resolved soon after ' +
+                'Animation finishes normally');
+  });
+}, 'Test normally finished animation resolves finished promise synchronously ' +
+   'with an animation without a target');
+
+</script>
+</body>
--- a/testing/web-platform/tests/web-animations/interfaces/Animation/idlharness.html
+++ b/testing/web-platform/tests/web-animations/interfaces/Animation/idlharness.html
@@ -24,17 +24,16 @@ interface Animation : EventTarget {
     readonly attribute Promise<Animation>       ready;
     readonly attribute Promise<Animation>       finished;
              attribute EventHandler             onfinish;
              attribute EventHandler             oncancel;
     void cancel ();
     void finish ();
     void play ();
     void pause ();
-    void updatePlaybackRate (double playbackRate);
     void reverse ();
 };
 </script>
 <script>
 'use strict';
 
 const idlArray = new IdlArray();
 
rename from testing/web-platform/tests/web-animations/timing-model/animations/setting-the-playback-rate-of-an-animation.html
rename to testing/web-platform/tests/web-animations/interfaces/Animation/playbackRate.html
--- a/testing/web-platform/tests/web-animations/timing-model/animations/setting-the-playback-rate-of-an-animation.html
+++ b/testing/web-platform/tests/web-animations/interfaces/Animation/playbackRate.html
@@ -1,61 +1,84 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
-<title>Setting the playback rate of an animation</title>
-<link rel="help" href="https://drafts.csswg.org/web-animations/#setting-the-playback-rate-of-an-animation">
+<title>Animation.playbackRate</title>
+<link rel="help" href="https://drafts.csswg.org/web-animations/#dom-animation-playbackrate">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../../testcommon.js"></script>
 <body>
 <div id="log"></div>
 <script>
 'use strict';
 
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  animation.playbackRate = 2;
-  await animation.ready;
-
-  const previousAnimationCurrentTime = animation.currentTime;
-  const previousTimelineCurrentTime = animation.timeline.currentTime;
-
-  await waitForAnimationFrames(1);
-
+function assert_playbackrate(animation,
+                             previousAnimationCurrentTime,
+                             previousTimelineCurrentTime,
+                             description) {
   const animationCurrentTimeDifference =
     animation.currentTime - previousAnimationCurrentTime;
   const timelineCurrentTimeDifference =
     animation.timeline.currentTime - previousTimelineCurrentTime;
 
-  assert_times_equal(
-    animationCurrentTimeDifference,
-    timelineCurrentTimeDifference * animation.playbackRate,
-    'The current time should increase two times faster than timeline'
-  );
-}, 'The playback rate affects the rate of progress of the current time');
+  assert_times_equal(animationCurrentTimeDifference,
+                     timelineCurrentTimeDifference * animation.playbackRate,
+                     description);
+}
 
-test(t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  animation.currentTime = 50 * MS_PER_SEC;
-  animation.playbackRate = 2;
-  assert_time_equals_literal(animation.currentTime, 50 * MS_PER_SEC);
-}, 'Setting the playback rate while play-pending preserves the current time');
+promise_test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(null, 100 * MS_PER_SEC);
+  return animation.ready.then(() => {
+    animation.currentTime = 7 * MS_PER_SEC; // ms
+    animation.playbackRate = 0.5;
+
+    assert_equals(animation.currentTime, 7 * MS_PER_SEC,
+      'Reducing Animation.playbackRate should not change the currentTime ' +
+      'of a playing animation');
+    animation.playbackRate = 2;
+    assert_equals(animation.currentTime, 7 * MS_PER_SEC,
+      'Increasing Animation.playbackRate should not change the currentTime ' +
+      'of a playing animation');
+  });
+}, 'Test the initial effect of setting playbackRate on currentTime');
 
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  animation.currentTime = 50 * MS_PER_SEC;
-  await animation.ready;
+promise_test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(null, 100 * MS_PER_SEC);
   animation.playbackRate = 2;
-  assert_greater_than_equal(animation.currentTime, 50 * MS_PER_SEC);
-  assert_less_than(animation.currentTime, 100 * MS_PER_SEC);
-}, 'Setting the playback rate while playing preserves the current time');
+  let previousTimelineCurrentTime;
+  let previousAnimationCurrentTime;
+  return animation.ready.then(() => {
+    previousAnimationCurrentTime = animation.currentTime;
+    previousTimelineCurrentTime = animation.timeline.currentTime;
+    return waitForAnimationFrames(1);
+  }).then(() => {
+    assert_playbackrate(animation,
+      previousAnimationCurrentTime,
+      previousTimelineCurrentTime,
+      'animation.currentTime should be 2 times faster than timeline.');
+  });
+}, 'Test the effect of setting playbackRate on currentTime');
 
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  animation.currentTime = 50 * MS_PER_SEC;
-  animation.updatePlaybackRate(2);
-  animation.playbackRate = 1;
-  await animation.ready;
-  assert_equals(animation.playbackRate, 1);
-}, 'Setting the playback rate should clear any pending playback rate');
+promise_test(t => {
+  const div = createDiv(t);
+  const animation = div.animate(null, 100 * MS_PER_SEC);
+  animation.playbackRate = 2;
+  let previousTimelineCurrentTime;
+  let previousAnimationCurrentTime;
+  return animation.ready.then(() => {
+    previousAnimationCurrentTime = animation.currentTime;
+    previousTimelineCurrentTime = animation.timeline.currentTime;
+    animation.playbackRate = 1;
+    return waitForAnimationFrames(1);
+  }).then(() => {
+    assert_equals(animation.playbackRate, 1,
+      'sanity check: animation.playbackRate is still 1.');
+    assert_playbackrate(animation,
+      previousAnimationCurrentTime,
+      previousTimelineCurrentTime,
+      'animation.currentTime should be the same speed as timeline now.');
+  });
+}, 'Test the effect of setting playbackRate while playing animation');
 
 </script>
 </body>
--- a/testing/web-platform/tests/web-animations/timing-model/animations/canceling-an-animation.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/canceling-an-animation.html
@@ -21,38 +21,39 @@ promise_test(t => {
   });
 
   animation.cancel();
 
   return retPromise;
 }, 'A play-pending ready promise should be rejected when the animation is'
    + ' canceled');
 
-promise_test(async t => {
+promise_test(t => {
   const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  await animation.ready;
-
-  // Make it pause-pending
-  animation.pause();
-
-  // We need to store the original ready promise since cancel() will
-  // replace it
-  const originalPromise = animation.ready;
-  animation.cancel();
-
-  await promise_rejects(t, 'AbortError', originalPromise,
-                        'Cancel should abort ready promise');
+  return animation.ready.then(() => {
+    animation.pause();
+    // Set up listeners on pause-pending ready promise
+    const retPromise = animation.ready.then(() => {
+      assert_unreached('ready promise was fulfilled');
+    }).catch(err => {
+      assert_equals(err.name, 'AbortError',
+                    'ready promise is rejected with AbortError');
+    });
+    animation.cancel();
+    return retPromise;
+  });
 }, 'A pause-pending ready promise should be rejected when the animation is'
    + ' canceled');
 
-promise_test(async t => {
+promise_test(t => {
   const animation = createDiv(t).animate(null);
   animation.cancel();
-  const promiseResult = await animation.ready;
-  assert_equals(promiseResult, animation);
+  return animation.ready.then(p => {
+    assert_equals(p, animation);
+  });
 }, 'When an animation is canceled, it should create a resolved Promise');
 
 test(t => {
   const animation = createDiv(t).animate(null);
   const promise = animation.ready;
   animation.cancel();
   assert_not_equals(animation.ready, promise);
 }, 'The ready promise should be replaced when the animation is canceled');
rename from testing/web-platform/tests/web-animations/timing-model/animations/the-current-time-of-an-animation.html
rename to testing/web-platform/tests/web-animations/timing-model/animations/current-time.html
--- a/testing/web-platform/tests/web-animations/timing-model/animations/the-current-time-of-an-animation.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/current-time.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
-<title>The current time of an animation</title>
-<link rel="help" href="https://drafts.csswg.org/web-animations/#the-current-time-of-an-animation">
+<title>Current time</title>
+<link rel="help" href="https://drafts.csswg.org/web-animations/#current-time">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../../testcommon.js"></script>
 <body>
 <div id="log"></div>
 <script>
 'use strict';
 
@@ -16,23 +16,24 @@ test(t => {
                   document.timeline);
 
   animation.play();
   assert_equals(animation.currentTime, 0,
     'Current time returns the hold time set when entering the play-pending ' +
     'state');
 }, 'The current time returns the hold time when set');
 
-promise_test(async t => {
+promise_test(t => {
   const animation =
     new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
                   null);
 
-  await animation.ready;
-  assert_equals(animation.currentTime, null);
+  return animation.ready.then(() => {
+    assert_equals(animation.currentTime, null);
+  });
 }, 'The current time is unresolved when there is no associated timeline ' +
    '(and no hold time is set)');
 
 // FIXME: Test that the current time is unresolved when we have an inactive
 // timeline if we find a way of creating an inactive timeline!
 
 test(t => {
   const animation =
@@ -56,19 +57,20 @@ test(t => {
   const startTime = animation.startTime;
   const playbackRate = animation.playbackRate;
   assert_times_equal(animation.currentTime,
                      (timelineTime - startTime) * playbackRate,
                      'Animation has a unresolved start time');
 }, 'The current time is calculated from the timeline time, start time and ' +
    'playback rate');
 
-promise_test(async t => {
+promise_test(t => {
   const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
   animation.playbackRate = 0;
 
-  await animation.ready;
-  await waitForAnimationFrames(1);
-  assert_time_equals_literal(animation.currentTime, 0);
+  return animation.ready.then(() => waitForAnimationFrames(1))
+  .then(() => {
+    assert_time_equals_literal(animation.currentTime, 0);
+  });
 }, 'The current time does not progress if playback rate is 0');
 
 </script>
 </body>
--- a/testing/web-platform/tests/web-animations/timing-model/animations/finishing-an-animation.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/finishing-an-animation.html
@@ -6,283 +6,26 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../../testcommon.js"></script>
 <body>
 <div id="log"></div>
 <script>
 'use strict';
 
-test(t => {
-  const div = createDiv(t);
-  const animation = div.animate(null, 100 * MS_PER_SEC);
-  animation.playbackRate = 0;
-
-  assert_throws({name: 'InvalidStateError'}, () => {
-    animation.finish();
-  });
-}, 'Finishing an animation with a zero playback rate throws');
-
-test(t => {
-  const div = createDiv(t);
-  const animation = div.animate(null,
-                                { duration : 100 * MS_PER_SEC,
-                                  iterations : Infinity });
-
-  assert_throws({name: 'InvalidStateError'}, () => {
-    animation.finish();
-  });
-}, 'Finishing an infinite animation throws');
-
-test(t => {
-  const div = createDiv(t);
-  const animation = div.animate(null, 100 * MS_PER_SEC);
-  animation.finish();
-
-  assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC,
-    'After finishing, the currentTime should be set to the end of the'
-    + ' active duration');
-}, 'Finishing an animation seeks to the end time');
-
-test(t => {
-  const div = createDiv(t);
-  const animation = div.animate(null, 100 * MS_PER_SEC);
-   // 1s past effect end
-  animation.currentTime =
-    animation.effect.getComputedTiming().endTime + 1 * MS_PER_SEC;
-  animation.finish();
-
-  assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC,
-    'After finishing, the currentTime should be set back to the end of the'
-    + ' active duration');
-}, 'Finishing an animation with a current time past the effect end jumps'
-   + ' back to the end');
-
-promise_test(async t => {
-  const div = createDiv(t);
-  const animation = div.animate(null, 100 * MS_PER_SEC);
-  animation.currentTime = 100 * MS_PER_SEC;
-  await animation.finished;
-
-  animation.playbackRate = -1;
-  animation.finish();
-
-  assert_equals(animation.currentTime, 0,
-                'After finishing a reversed animation the currentTime ' +
-                'should be set to zero');
-}, 'Finishing a reversed animation jumps to zero time');
-
-promise_test(async t => {
-  const div = createDiv(t);
-  const animation = div.animate(null, 100 * MS_PER_SEC);
-  animation.currentTime = 100 * MS_PER_SEC;
-  await animation.finished;
-
-  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');
-}, 'Finishing a reversed animation with a current time less than zero'
-   + ' makes it jump back to zero');
-
-promise_test(async t => {
-  const div = createDiv(t);
-  const animation = div.animate(null, 100 * MS_PER_SEC);
-  animation.pause();
-  await animation.ready;
-
-  animation.finish();
-
-  assert_equals(animation.playState, 'finished',
-                'The play state of a paused animation should become ' +
-                '"finished"');
-  assert_times_equal(animation.startTime,
-                     animation.timeline.currentTime - 100 * MS_PER_SEC,
-                     'The start time of a paused animation should be set');
-}, 'Finishing a paused animation resolves the start time');
-
-test(t => {
-  const div = createDiv(t);
-  const animation = div.animate(null, 100 * MS_PER_SEC);
-  // Update playbackRate so we can test that the calculated startTime
-  // respects it
-  animation.playbackRate = 2;
-  animation.pause();
-  // While animation is still pause-pending call finish()
-  animation.finish();
-
-  assert_false(animation.pending);
-  assert_equals(animation.playState, 'finished',
-                'The play state of a pause-pending animation should become ' +
-                '"finished"');
-  assert_times_equal(animation.startTime,
-                     animation.timeline.currentTime - 100 * MS_PER_SEC / 2,
-                     'The start time of a pause-pending animation should ' +
-                     'be set');
-}, 'Finishing a pause-pending animation resolves the pending task'
-   + ' immediately and update the start time');
-
-test(t => {
-  const div = createDiv(t);
-  const animation = div.animate(null, 100 * MS_PER_SEC);
-  animation.playbackRate = -2;
-  animation.pause();
-  animation.finish();
-
-  assert_false(animation.pending);
-  assert_equals(animation.playState, 'finished',
-                'The play state of a pause-pending animation should become ' +
-                '"finished"');
-  assert_times_equal(animation.startTime, animation.timeline.currentTime,
-                     'The start time of a pause-pending animation should be ' +
-                     'set');
-}, 'Finishing a pause-pending animation with negative playback rate'
-   + ' resolves the pending task immediately');
-
-test(t => {
-  const div = createDiv(t);
-  const animation = div.animate(null, 100 * MS_PER_SEC);
-  animation.playbackRate = 0.5;
-  animation.finish();
-
-  assert_false(animation.pending);
-  assert_equals(animation.playState, 'finished',
-                'The play state of a play-pending animation should become ' +
-                '"finished"');
-  assert_times_equal(animation.startTime,
-                     animation.timeline.currentTime - 100 * MS_PER_SEC / 0.5,
-                     'The start time of a play-pending animation should ' +
-                     'be set');
-}, 'Finishing an animation while play-pending resolves the pending'
-   + ' task immediately');
-
-// FIXME: Add a test for when we are play-pending without an active timeline.
-// - In that case even after calling finish() we should still be pending but
-//   the current time should be updated
-
-promise_test(async t => {
-  const div = createDiv(t);
-  const animation = div.animate(null, 100 * MS_PER_SEC);
-  await animation.ready;
-
-  animation.pause();
-  animation.play();
-  // We are now in the unusual situation of being play-pending whilst having
-  // a resolved start time. Check that finish() still triggers a transition
-  // to the finished state immediately.
-  animation.finish();
-
-  assert_equals(animation.playState, 'finished',
-                'After aborting a pause then finishing an animation its play ' +
-                'state should become "finished" immediately');
-}, 'Finishing an animation during an aborted pause makes it finished'
-   + ' immediately');
-
-promise_test(async t => {
-  const div = createDiv(t);
-  const animation = div.animate(null, 100 * MS_PER_SEC);
-  let resolvedFinished = false;
-  animation.finished.then(() => {
-    resolvedFinished = true;
-  });
-
-  await animation.ready;
-
-  animation.finish();
-  await Promise.resolve();
-
-  assert_true(resolvedFinished, 'finished promise should be resolved');
-}, 'Finishing an animation resolves the finished promise synchronously');
-
-promise_test(async t => {
-  const effect = new KeyframeEffectReadOnly(null, null, 100 * MS_PER_SEC);
-  const animation = new Animation(effect, document.timeline);
-  let resolvedFinished = false;
-  animation.finished.then(() => {
-    resolvedFinished = true;
-  });
-
-  await animation.ready;
-
-  animation.finish();
-  await Promise.resolve();
-
-  assert_true(resolvedFinished, 'finished promise should be resolved');
-}, 'Finishing an animation without a target resolves the finished promise'
-   + ' synchronously');
-
-promise_test(async t => {
+promise_test(t => {
   const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
   const promise = animation.ready;
   let readyResolved = false;
 
   animation.finish();
   animation.ready.then(() => { readyResolved = true; });
 
-  const promiseResult = await animation.finished;
-
-  assert_equals(promiseResult, animation);
-  assert_equals(animation.ready, promise);
-  assert_true(readyResolved);
-}, 'A pending ready promise is resolved and not replaced when the animation'
-   + ' is finished');
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  await animation.ready;
-
-  animation.updatePlaybackRate(2);
-  assert_true(animation.pending);
-
-  animation.finish();
-  assert_false(animation.pending);
-  assert_equals(animation.playbackRate, 2);
-  assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC);
-}, 'A pending playback rate should be applied immediately when an animation'
-   + ' is finished');
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  await animation.ready;
-
-  animation.updatePlaybackRate(0);
-
-  assert_throws('InvalidStateError', () => {
-    animation.finish();
+  return animation.finished.then(p => {
+    assert_equals(p, animation);
+    assert_equals(animation.ready, promise);
+    assert_true(readyResolved);
   });
-}, 'An exception should be thrown if the effective playback rate is zero');
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, {
-    duration: 100 * MS_PER_SEC,
-    iterations: Infinity
-  });
-  animation.currentTime = 50 * MS_PER_SEC;
-  animation.playbackRate = -1;
-  await animation.ready;
-
-  animation.updatePlaybackRate(1);
-
-  assert_throws('InvalidStateError', () => {
-    animation.finish();
-  });
-}, 'An exception should be thrown when finishing if the effective playback rate'
-   + ' is positive and the target effect end is infinity');
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, {
-    duration: 100 * MS_PER_SEC,
-    iterations: Infinity
-  });
-  await animation.ready;
-
-  animation.updatePlaybackRate(-1);
-
-  animation.finish();
-  // Should not have thrown
-}, 'An exception is NOT thrown when finishing if the effective playback rate'
-   + ' is negative and the target effect end is infinity');
+}, 'A pending ready promise should be resolved and not replaced when the'
+   + ' animation is finished');
 
 </script>
 </body>
--- a/testing/web-platform/tests/web-animations/timing-model/animations/pausing-an-animation.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/pausing-an-animation.html
@@ -6,41 +6,22 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../../testcommon.js"></script>
 <body>
 <div id="log"></div>
 <script>
 'use strict';
 
-promise_test(async t => {
+promise_test(t => {
   const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
   const promise = animation.ready;
   animation.pause();
-
-  const promiseResult = await promise;
-
-  assert_equals(promiseResult, animation);
-  assert_equals(animation.ready, promise);
-  assert_false(animation.pending, 'No longer pause-pending');
+  return promise.then(p => {
+    assert_equals(p, animation);
+    assert_equals(animation.ready, promise);
+    assert_false(animation.pending, 'No longer pause-pending');
+  });
 }, 'A pending ready promise should be resolved and not replaced when the'
    + ' animation is paused');
 
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  // Let animation start roughly half-way through
-  animation.currentTime = 50 * MS_PER_SEC;
-  await animation.ready;
-
-  // Go pause-pending and also set a pending playback rate
-  animation.pause();
-  animation.updatePlaybackRate(0.5);
-
-  await animation.ready;
-  // If the current time was updated using the new playback rate it will jump
-  // back to 25s but if we correctly used the old playback rate the current time
-  // will be >50s.
-  assert_greater_than(animation.currentTime, 50 * MS_PER_SEC);
-}, 'A pause-pending animation maintains the current time when applying a'
-   + ' pending playback rate');
-
 </script>
 </body>
--- a/testing/web-platform/tests/web-animations/timing-model/animations/play-states.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/play-states.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
 <title>Play states</title>
-<link rel="help" href="https://drafts.csswg.org/web-animations/#play-states">
+<link rel="help" href="https://drafts.csswg.org/web-animations/#play-state">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../../testcommon.js"></script>
 <body>
 <div id="log"></div>
 <script>
 'use strict';
 
--- a/testing/web-platform/tests/web-animations/timing-model/animations/playing-an-animation.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/playing-an-animation.html
@@ -40,36 +40,20 @@ test(t => {
   const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
   animation.cancel();
   const promise = animation.ready;
   animation.play();
   assert_not_equals(animation.ready, promise);
 }, 'The ready promise should be replaced if the animation is not already'
    + ' pending');
 
-promise_test(async t => {
+promise_test(t => {
   const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
   const promise = animation.ready;
-  const promiseResult = await promise;
-  assert_equals(promiseResult, animation);
-  assert_equals(animation.ready, promise);
+  return promise.then(p => {
+    assert_equals(p, animation);
+    assert_equals(animation.ready, promise);
+  });
 }, 'A pending ready promise should be resolved and not replaced when the'
    + ' animation enters the running state');
 
-promise_test(async t => {
-  // Seek animation beyond target end
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  animation.currentTime = -100 * MS_PER_SEC;
-  await animation.ready;
-
-  // Set pending playback rate to the opposite direction
-  animation.updatePlaybackRate(-1);
-  assert_true(animation.pending);
-  assert_equals(animation.playbackRate, 1);
-
-  // When we play, we should seek to the target end, NOT to zero (which
-  // is where we would seek to if we used the playbackRate of 1.
-  animation.play();
-  assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC);
-}, 'A pending playback rate is used when determining auto-rewind behavior');
-
 </script>
 </body>
--- a/testing/web-platform/tests/web-animations/timing-model/animations/reversing-an-animation.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/reversing-an-animation.html
@@ -1,58 +1,53 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
-<title>Reversing an animation</title>
+<title>Reverse an animation</title>
 <link rel="help"
-      href="https://drafts.csswg.org/web-animations/#reversing-an-animation-section">
+      href="https://drafts.csswg.org/web-animations/#reverse-an-animation">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../../testcommon.js"></script>
 <body>
 <div id="log"></div>
 <script>
 'use strict';
 
-promise_test(async t => {
+promise_test(t => {
   const div = createDiv(t);
   const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
                                       iterations: Infinity });
 
-  await animation.ready;
   // Wait a frame because if currentTime is still 0 when we call
   // reverse(), it will throw (per spec).
-  await waitForAnimationFrames(1);
-
-  assert_greater_than_equal(animation.currentTime, 0,
-    'currentTime expected to be greater than 0, one frame after starting');
-  animation.currentTime = 50 * MS_PER_SEC;
-  const previousPlaybackRate = animation.playbackRate;
-  animation.reverse();
-  assert_equals(animation.playbackRate, previousPlaybackRate,
-                'Playback rate should not have changed');
-  await animation.ready;
-
-  assert_equals(animation.playbackRate, -previousPlaybackRate,
-                'Playback rate should be inverted');
+  return animation.ready.then(waitForAnimationFrames(1)).then(() => {
+    assert_greater_than_equal(animation.currentTime, 0,
+      'currentTime expected to be greater than 0, one frame after starting');
+    animation.currentTime = 50 * MS_PER_SEC;
+    const previousPlaybackRate = animation.playbackRate;
+    animation.reverse();
+    assert_equals(animation.playbackRate, -previousPlaybackRate,
+      'playbackRate should be inverted');
+  });
 }, 'Reversing an animation inverts the playback rate');
 
-promise_test(async t => {
+promise_test(t => {
   const div = createDiv(t);
   const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
                                       iterations: Infinity });
   animation.currentTime = 50 * MS_PER_SEC;
   animation.pause();
 
-  await animation.ready;
-
-  animation.reverse();
-  await animation.ready;
-
-  assert_equals(animation.playState, 'running',
-    'Animation.playState should be "running" after reverse()');
+  return animation.ready.then(() => {
+    animation.reverse();
+    return animation.ready;
+  }).then(() => {
+    assert_equals(animation.playState, 'running',
+      'Animation.playState should be "running" after reverse()');
+  });
 }, 'Reversing an animation plays a pausing animation');
 
 test(t => {
   const div = createDiv(t);
   const animation = div.animate({}, 100 * MS_PER_SEC);
   animation.currentTime = 50 * MS_PER_SEC;
   animation.reverse();
 
@@ -69,28 +64,29 @@ test(t => {
               'The animation is pending before we call reverse');
 
   animation.reverse();
 
   assert_true(animation.pending,
               'The animation is still pending after calling reverse');
 }, 'Reversing an animation does not cause it to leave the pending state');
 
-promise_test(async t => {
+promise_test(t => {
   const div = createDiv(t);
   const animation = div.animate({}, { duration: 200 * MS_PER_SEC,
                                       delay: -100 * MS_PER_SEC });
   let readyResolved = false;
   animation.ready.then(() => { readyResolved = true; });
 
   animation.reverse();
 
-  await Promise.resolve();
-  assert_false(readyResolved,
-               'ready promise should not have been resolved yet');
+  return Promise.resolve(() => {
+    assert_false(readyResolved,
+                 'ready promise should not have been resolved yet');
+  });
 }, 'Reversing an animation does not cause it to resolve the ready promise');
 
 test(t => {
   const div = createDiv(t);
   const animation = div.animate({}, 100 * MS_PER_SEC);
   animation.currentTime = 200 * MS_PER_SEC;
   animation.reverse();
 
@@ -148,26 +144,23 @@ test(t => {
   assert_throws('InvalidStateError',
     () => { animation.reverse(); },
     'reverse() should throw InvalidStateError ' +
     'if the playbackRate > 0 and the currentTime < 0 ' +
     'and the target effect is positive infinity');
 }, 'Reversing an animation when playbackRate > 0 and currentTime < 0 ' +
    'and the target effect end is positive infinity should throw an exception');
 
-promise_test(async t => {
+test(t => {
   const animation = createDiv(t).animate({}, { duration: 100 * MS_PER_SEC,
                                                iterations: Infinity });
   animation.currentTime = -200 * MS_PER_SEC;
 
   try { animation.reverse(); } catch(e) { }
 
-  assert_equals(animation.playbackRate, 1, 'playbackRate is unchanged');
-
-  await animation.ready;
   assert_equals(animation.playbackRate, 1, 'playbackRate remains unchanged');
 }, 'When reversing throws an exception, the playback rate remains unchanged');
 
 test(t => {
   const div = createDiv(t);
   const animation = div.animate({}, { duration: 100 * MS_PER_SEC,
                                       iterations: Infinity });
   animation.currentTime = -200 * MS_PER_SEC;
@@ -193,62 +186,34 @@ test(t => {
   assert_equals(animation.currentTime, 0,
     'reverse() should start playing from the start of animation time ' +
     'if the playbackRate < 0 and the currentTime < 0 ' +
     'and the target effect is positive infinity');
 }, 'Reversing an animation when playbackRate < 0 and currentTime < 0 ' +
    'and the target effect end is positive infinity should make it play ' +
    'from the start');
 
-promise_test(async t => {
+test(t => {
   const div = createDiv(t);
   const animation = div.animate({}, 100 * MS_PER_SEC);
   animation.playbackRate = 0;
   animation.currentTime = 50 * MS_PER_SEC;
   animation.reverse();
 
-  await animation.ready;
   assert_equals(animation.playbackRate, 0,
     'reverse() should preserve playbackRate if the playbackRate == 0');
   assert_equals(animation.currentTime, 50 * MS_PER_SEC,
     'reverse() should not affect the currentTime if the playbackRate == 0');
+  t.done();
 }, 'Reversing when when playbackRate == 0 should preserve the current ' +
    'time and playback rate');
 
 test(t => {
   const div = createDiv(t);
   const animation =
     new Animation(new KeyframeEffect(div, null, 100 * MS_PER_SEC), null);
 
   assert_throws('InvalidStateError', () => { animation.reverse(); });
 }, 'Reversing an animation without an active timeline throws an ' +
    'InvalidStateError');
 
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  await animation.ready;
-
-  animation.updatePlaybackRate(2);
-  animation.reverse();
-
-  await animation.ready;
-  assert_equals(animation.playbackRate, -2);
-}, 'Reversing should use the negative pending playback rate');
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, {
-    duration: 100 * MS_PER_SEC,
-    iterations: Infinity,
-  });
-  animation.currentTime = -200 * MS_PER_SEC;
-  await animation.ready;
-
-  animation.updatePlaybackRate(2);
-  assert_throws('InvalidStateError', () => { animation.reverse(); });
-  assert_equals(animation.playbackRate, 1);
-
-  await animation.ready;
-  assert_equals(animation.playbackRate, 2);
-}, 'When reversing fails, it should restore any previous pending playback'
-   + ' rate');
-
 </script>
 </body>
deleted file mode 100644
--- a/testing/web-platform/tests/web-animations/timing-model/animations/seamlessly-updating-the-playback-rate-of-an-animation.html
+++ /dev/null
@@ -1,142 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>Seamlessly updating the playback rate of an animation</title>
-<link rel="help"
-  href="https://drafts.csswg.org/web-animations-1/#seamlessly-updating-the-playback-rate-of-an-animation">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="../../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-'use strict';
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  await animation.ready;
-
-  animation.currentTime = 50 * MS_PER_SEC;
-
-  animation.updatePlaybackRate(0.5);
-  await animation.ready;
-  // Since the animation is in motion (and we want to test it while it is in
-  // motion!) we can't assert that the current time == 50s but we can check
-  // that the current time is NOT re-calculated by simply substituting in the
-  // new playback rate (i.e. without adjusting the start time). If that were
-  // the case the currentTime would jump to 25s. So we just test the currentTime
-  // hasn't gone backwards.
-  assert_greater_than_equal(animation.currentTime, 50 * MS_PER_SEC,
-    'Reducing the playback rate should not change the current time ' +
-    'of a playing animation');
-
-  animation.updatePlaybackRate(2);
-  await animation.ready;
-  // Likewise, we test here that the current time does not jump to 100s as it
-  // would if we naively applied a playbackRate of 2 without adjusting the
-  // startTime.
-  assert_less_than(animation.currentTime, 100 * MS_PER_SEC,
-    'Increasing the playback rate should not change the current time ' +
-    'of a playing animation');
-}, 'Updating the playback rate maintains the current time');
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  await animation.ready;
-
-  assert_false(animation.pending);
-  animation.updatePlaybackRate(2);
-  assert_true(animation.pending);
-}, 'Updating the playback rate while running makes the animation pending');
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  animation.currentTime = 50 * MS_PER_SEC;
-  assert_true(animation.pending);
-
-  animation.updatePlaybackRate(0.5);
-
-  // Check that the hold time is updated as expected
-  assert_time_equals_literal(animation.currentTime, 50 * MS_PER_SEC);
-
-  await animation.ready;
-
-  // As above, check that the currentTime is not calculated by simply
-  // substituting in the updated playbackRate without updating the startTime.
-  assert_greater_than_equal(animation.currentTime, 50 * MS_PER_SEC,
-    'Reducing the playback rate should not change the current time ' +
-    'of a play-pending animation');
-}, 'Updating the playback rate on a play-pending animation maintains'
-   + ' the current time');
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  animation.currentTime = 50 * MS_PER_SEC;
-  await animation.ready;
-
-  animation.pause();
-  animation.updatePlaybackRate(0.5);
-
-  assert_greater_than_equal(animation.currentTime, 50 * MS_PER_SEC);
-}, 'Updating the playback rate on a pause-pending animation maintains'
-   + ' the current time');
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-
-  animation.updatePlaybackRate(2);
-  animation.updatePlaybackRate(3);
-  animation.updatePlaybackRate(4);
-
-  assert_equals(animation.playbackRate, 1);
-  await animation.ready;
-
-  assert_equals(animation.playbackRate, 4);
-}, 'If a pending playback rate is set multiple times, the latest wins');
-
-test(t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  animation.cancel();
-
-  animation.updatePlaybackRate(2);
-  assert_equals(animation.playbackRate, 2);
-  assert_false(animation.pending);
-}, 'In the idle state, the playback rate is applied immediately');
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  animation.pause();
-  await animation.ready;
-
-  animation.updatePlaybackRate(2);
-  assert_equals(animation.playbackRate, 2);
-  assert_false(animation.pending);
-}, 'In the paused state, the playback rate is applied immediately');
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  animation.finish();
-  assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC);
-  assert_false(animation.pending);
-
-  animation.updatePlaybackRate(2);
-  assert_equals(animation.playbackRate, 2);
-  assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC);
-  assert_false(animation.pending);
-}, 'Updating the playback rate on a finished animation maintains'
-   + ' the current time');
-
-promise_test(async t => {
-  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  animation.finish();
-  assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC);
-  assert_false(animation.pending);
-
-  animation.updatePlaybackRate(0);
-  assert_equals(animation.playbackRate, 0);
-  assert_time_equals_literal(animation.currentTime, 100 * MS_PER_SEC);
-  assert_false(animation.pending);
-}, 'Updating the playback rate to zero on a finished animation maintains'
-   + ' the current time');
-
-</script>
-</body>
rename from testing/web-platform/tests/web-animations/timing-model/animations/setting-the-start-time-of-an-animation.html
rename to testing/web-platform/tests/web-animations/timing-model/animations/set-the-animation-start-time.html
--- a/testing/web-platform/tests/web-animations/timing-model/animations/setting-the-start-time-of-an-animation.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/set-the-animation-start-time.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
-<title>Setting the start time of an animation</title>
-<link rel="help" href="https://drafts.csswg.org/web-animations/#setting-the-start-time-of-an-animation">
+<title>Set the animation start time</title>
+<link rel="help" href="https://drafts.csswg.org/web-animations/#set-the-animation-start-time">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../../testcommon.js"></script>
 <body>
 <div id="log"></div>
 <script>
 'use strict';
 
@@ -107,17 +107,17 @@ test(t => {
   assert_time_equals_literal(animation.currentTime, 1000,
                              'Hold time is set after start time is made'
                              + ' unresolved');
   assert_equals(animation.playState, 'paused',
                 'Animation reports it is paused after setting an unresolved'
                 + ' start time');
 }, 'Setting an unresolved start time sets the hold time');
 
-promise_test(async t => {
+promise_test(t => {
   const animation =
     new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
                   document.timeline);
 
   let readyPromiseCallbackCalled = false;
   animation.ready.then(() => { readyPromiseCallbackCalled = true; } );
 
   // Put the animation in the play-pending state
@@ -130,22 +130,23 @@ promise_test(async t => {
   // Setting the start time should resolve the 'ready' promise, i.e.
   // it should schedule a microtask to run the promise callbacks.
   animation.startTime = document.timeline.currentTime;
   assert_false(readyPromiseCallbackCalled,
                'Ready promise callback is not called synchronously');
 
   // If we schedule another microtask then it should run immediately after
   // the ready promise resolution microtask.
-  await Promise.resolve();
-  assert_true(readyPromiseCallbackCalled,
-              'Ready promise callback called after setting startTime');
+  return Promise.resolve().then(() => {
+    assert_true(readyPromiseCallbackCalled,
+                'Ready promise callback called after setting startTime');
+  });
 }, 'Setting the start time resolves a pending ready promise');
 
-promise_test(async t => {
+promise_test(t => {
   const animation =
     new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
                   document.timeline);
 
   let readyPromiseCallbackCalled = false;
   animation.ready.then(() => { readyPromiseCallbackCalled = true; } );
 
   // Put the animation in the pause-pending state
@@ -157,22 +158,23 @@ promise_test(async t => {
               'Animation is in pause-pending state');
 
   // Setting the start time should resolve the 'ready' promise although
   // the resolution callbacks when be run in a separate microtask.
   animation.startTime = null;
   assert_false(readyPromiseCallbackCalled,
                'Ready promise callback is not called synchronously');
 
-  await Promise.resolve();
-  assert_true(readyPromiseCallbackCalled,
-              'Ready promise callback called after setting startTime');
+  return Promise.resolve().then(() => {
+    assert_true(readyPromiseCallbackCalled,
+                'Ready promise callback called after setting startTime');
+  });
 }, 'Setting the start time resolves a pending pause task');
 
-promise_test(async t => {
+promise_test(t => {
   const animation =
     new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
                   document.timeline);
 
   // Set start time such that the current time is past the end time
   animation.startTime = document.timeline.currentTime
                         - 110 * MS_PER_SEC;
   assert_equals(animation.playState, 'finished',
@@ -183,65 +185,17 @@ promise_test(async t => {
   assert_greater_than(animation.currentTime,
                       animation.effect.getComputedTiming().endTime,
                       'Setting the start time updated the finished state with'
                       + ' the \'did seek\' flag set to true');
 
   // Furthermore, that time should persist if we have correctly updated
   // the hold time
   const finishedCurrentTime = animation.currentTime;
-  await waitForAnimationFrames(1);
-  assert_equals(animation.currentTime, finishedCurrentTime,
-                'Current time does not change after seeking past the effect'
-                + ' end time by setting the current time');
+  return waitForAnimationFrames(1).then(() => {
+    assert_equals(animation.currentTime, finishedCurrentTime,
+                  'Current time does not change after seeking past the effect'
+                  + ' end time by setting the current time');
+  });
 }, 'Setting the start time updates the finished state');
 
-promise_test(async t => {
-  const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
-
-  // We should be play-pending now
-  assert_true(anim.pending);
-  assert_equals(anim.playState, 'running');
-
-  // Apply a pending playback rate
-  anim.updatePlaybackRate(2);
-  assert_equals(anim.playbackRate, 1);
-  assert_true(anim.pending);
-
-  // Setting the start time should apply the pending playback rate
-  anim.startTime = anim.timeline.currentTime - 25 * MS_PER_SEC;
-  assert_equals(anim.playbackRate, 2);
-  assert_false(anim.pending);
-
-  // Sanity check that the start time is preserved and current time is
-  // calculated using the new playback rate
-  assert_times_equal(anim.startTime,
-                     anim.timeline.currentTime - 25 * MS_PER_SEC);
-  assert_time_equals_literal(anim.currentTime, 50 * MS_PER_SEC);
-}, 'Setting the start time of a play-pending animation applies a pending playback rate');
-
-promise_test(async t => {
-  const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  await anim.ready;
-
-  // We should be running now
-  assert_false(anim.pending);
-  assert_equals(anim.playState, 'running');
-
-  // Apply a pending playback rate
-  anim.updatePlaybackRate(2);
-  assert_equals(anim.playbackRate, 1);
-  assert_true(anim.pending);
-
-  // Setting the start time should apply the pending playback rate
-  anim.startTime = anim.timeline.currentTime - 25 * MS_PER_SEC;
-  assert_equals(anim.playbackRate, 2);
-  assert_false(anim.pending);
-
-  // Sanity check that the start time is preserved and current time is
-  // calculated using the new playback rate
-  assert_times_equal(anim.startTime,
-                     anim.timeline.currentTime - 25 * MS_PER_SEC);
-  assert_time_equals_literal(anim.currentTime, 50 * MS_PER_SEC);
-}, 'Setting the start time of a playing animation applies a pending playback rate');
-
 </script>
 </body>
rename from testing/web-platform/tests/web-animations/timing-model/animations/setting-the-target-effect-of-an-animation.html
rename to testing/web-platform/tests/web-animations/timing-model/animations/set-the-target-effect-of-an-animation.html
--- a/testing/web-platform/tests/web-animations/timing-model/animations/setting-the-target-effect-of-an-animation.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/set-the-target-effect-of-an-animation.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
-<title>Setting the target effect of an animation</title>
+<title>Setting the target effect</title>
 <link rel='help' href='https://drafts.csswg.org/web-animations/#setting-the-target-effect'>
 <script src='/resources/testharness.js'></script>
 <script src='/resources/testharnessreport.js'></script>
 <script src='../../testcommon.js'></script>
 <body>
 <div id='log'></div>
 <script>
 'use strict';
@@ -26,58 +26,60 @@ promise_test(t => {
   // This is a bit odd, see: https://github.com/w3c/web-animations/issues/207
   assert_equals(anim.playState, 'paused');
   assert_false(anim.pending);
 
   return retPromise;
 }, 'If new effect is null and old effect is not null, we reset the pending ' +
    'tasks and ready promise is rejected');
 
-promise_test(async t => {
+promise_test(t => {
   const anim = new Animation();
   anim.pause();
   assert_true(anim.pending);
 
   anim.effect = new KeyframeEffectReadOnly(createDiv(t),
                                            { marginLeft: [ '0px', '100px' ] },
                                            100 * MS_PER_SEC);
   assert_true(anim.pending);
-  await anim.ready;
 
-  assert_false(anim.pending);
-  assert_equals(anim.playState, 'paused');
+  return anim.ready.then(() => {
+    assert_false(anim.pending);
+    assert_equals(anim.playState, 'paused');
+  });
 }, 'If animation has a pending pause task, reschedule that task to run ' +
    'as soon as animation is ready.');
 
-promise_test(async t => {
+promise_test(t => {
   const anim = new Animation();
   anim.play();
   assert_true(anim.pending);
 
   anim.effect = new KeyframeEffectReadOnly(createDiv(t),
                                            { marginLeft: [ '0px', '100px' ] },
                                            100 * MS_PER_SEC);
   assert_true(anim.pending);
-  await anim.ready;
 
-  assert_false(anim.pending);
-  assert_equals(anim.playState, 'running');
+  return anim.ready.then(() => {
+    assert_false(anim.pending);
+    assert_equals(anim.playState, 'running');
+  });
 }, 'If animation has a pending play task, reschedule that task to run ' +
    'as soon as animation is ready to play new effect.');
 
-promise_test(async t => {
+promise_test(t => {
   const animA = createDiv(t).animate({ marginLeft: [ '0px', '100px' ] },
                                      100 * MS_PER_SEC);
   const animB = new Animation();
 
-  await animA.ready;
-
-  animB.effect = animA.effect;
-  assert_equals(animA.effect, null);
-  assert_equals(animA.playState, 'finished');
+  return animA.ready.then(() => {
+    animB.effect = animA.effect;
+    assert_equals(animA.effect, null);
+    assert_equals(animA.playState, 'finished');
+  });
 }, 'When setting the effect of an animation to the effect of an existing ' +
    'animation, the existing animation\'s target effect should be set to null.');
 
 test(t => {
   const animA = createDiv(t).animate({ marginLeft: [ '0px', '100px' ] },
                                      100 * MS_PER_SEC);
   const animB = new Animation();
   const effect = animA.effect;
@@ -88,20 +90,10 @@ test(t => {
   animB.effect = effect;
   assert_equals(effect.getComputedTiming().progress, 0.2,
                 'After setting the effect on a different animation, ' +
                 'it uses the new animation\'s timing');
 }, 'After setting the target effect of animation to the target effect of an ' +
    'existing animation, the target effect\'s timing is updated to reflect ' +
    'the current time of the new animation.');
 
-test(t => {
-  const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  anim.updatePlaybackRate(2);
-  assert_equals(anim.playbackRate, 1);
-
-  anim.effect = null;
-  assert_equals(anim.playbackRate, 2);
-}, 'Setting the target effect to null causes a pending playback rate to be'
-   + ' applied');
-
 </script>
 </body>
rename from testing/web-platform/tests/web-animations/timing-model/animations/setting-the-timeline-of-an-animation.html
rename to testing/web-platform/tests/web-animations/timing-model/animations/set-the-timeline-of-an-animation.html
--- a/testing/web-platform/tests/web-animations/timing-model/animations/setting-the-timeline-of-an-animation.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/set-the-timeline-of-an-animation.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
-<title>Setting the timeline of an animation</title>
+<title>Setting the timeline</title>
 <link rel="help" href="https://drafts.csswg.org/web-animations/#setting-the-timeline">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../../testcommon.js"></script>
 <body>
 <div id="log"></div>
 <script>
 'use strict';
@@ -76,53 +76,55 @@ test(t => {
   assert_equals(animation.playState, 'idle');
 
   animation.timeline = document.timeline;
 
   assert_equals(animation.playState, 'finished');
 }, 'After setting timeline on an idle animation with a sufficiently ancient'
    + ' start time it is finished');
 
-promise_test(async t => {
+promise_test(t => {
   const animation =
     new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
                   null);
   animation.play();
   assert_true(animation.pending && animation.playState === 'running',
               'Animation is initially play-pending');
 
   animation.timeline = document.timeline;
 
   assert_true(animation.pending && animation.playState === 'running',
               'Animation is still play-pending after setting timeline');
 
-  await animation.ready;
-  assert_true(!animation.pending && animation.playState === 'running',
-              'Animation plays after it finishes pending');
+  return animation.ready.then(() => {
+    assert_true(!animation.pending && animation.playState === 'running',
+                'Animation plays after it finishes pending');
+  });
 }, 'After setting timeline on a play-pending animation it begins playing'
    + ' after pending');
 
-promise_test(async t => {
+promise_test(t => {
   const animation =
     new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
                   null);
   animation.startTime = document.timeline.currentTime;
   animation.pause();
   animation.timeline = null;
   assert_true(animation.pending && animation.playState === 'paused',
               'Animation is initially pause-pending');
 
   animation.timeline = document.timeline;
 
   assert_true(animation.pending && animation.playState === 'paused',
               'Animation is still pause-pending after setting timeline');
 
-  await animation.ready;
-  assert_true(!animation.pending && animation.playState === 'paused',
-              'Animation pauses after it finishes pending');
+  return animation.ready.then(() => {
+    assert_true(!animation.pending && animation.playState === 'paused',
+                'Animation pauses after it finishes pending');
+  });
 }, 'After setting timeline on a pause-pending animation it becomes paused'
    + ' after pending');
 
 // ---------------------------------------------------------------------
 //
 // Tests from timeline to no timeline
 //
 // ---------------------------------------------------------------------
@@ -186,70 +188,73 @@ test(t => {
   const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
   assert_true(animation.pending && animation.playState === 'running');
 
   animation.timeline = null;
 
   assert_true(animation.pending && animation.playState === 'running');
 }, 'After clearing timeline on play-pending animation it is still pending');
 
-promise_test(async t => {
+promise_test(t => {
   const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
   assert_true(animation.pending && animation.playState === 'running');
 
   animation.timeline = null;
   animation.timeline = document.timeline;
 
   assert_true(animation.pending && animation.playState === 'running');
-  await animation.ready;
-  assert_true(!animation.pending && animation.playState === 'running');
+  return animation.ready.then(() => {
+    assert_true(!animation.pending && animation.playState === 'running');
+  });
 }, 'After clearing and re-setting timeline on play-pending animation it'
    + ' begins to play');
 
 test(t => {
   const animation =
     new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
                   document.timeline);
   animation.startTime = document.timeline.currentTime;
   animation.pause();
   assert_true(animation.pending && animation.playState === 'paused');
 
   animation.timeline = null;
 
   assert_true(animation.pending && animation.playState === 'paused');
 }, 'After clearing timeline on a pause-pending animation it is still pending');
 
-promise_test(async t => {
+promise_test(t => {
   const animation =
     new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
                   document.timeline);
   animation.startTime = document.timeline.currentTime;
   animation.pause();
   assert_true(animation.pending && animation.playState === 'paused');
 
   animation.timeline = null;
   animation.timeline = document.timeline;
 
   assert_true(animation.pending && animation.playState === 'paused');
-  await animation.ready;
-  assert_true(!animation.pending && animation.playState === 'paused');
+  return animation.ready.then(() => {
+    assert_true(!animation.pending && animation.playState === 'paused');
+  });
 }, 'After clearing and re-setting timeline on a pause-pending animation it'
    + ' completes pausing');
 
-promise_test(async t => {
+promise_test(t => {
   const animation =
     new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
                   document.timeline);
   const initialStartTime = document.timeline.currentTime - 50 * MS_PER_SEC;
   animation.startTime = initialStartTime;
   animation.pause();
   animation.play();
 
   animation.timeline = null;
   animation.timeline = document.timeline;
 
-  await animation.ready;
-  assert_times_equal(animation.startTime, initialStartTime);
+  return animation.ready.then(() => {
+    assert_times_equal(animation.startTime, initialStartTime);
+  });
 }, 'After clearing and re-setting timeline on an animation in the middle of'
    + ' an aborted pause, it continues playing using the same start time');
 
 </script>
 </body>
deleted file mode 100644
--- a/testing/web-platform/tests/web-animations/timing-model/animations/setting-the-current-time-of-an-animation.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>Setting the current time of an animation</title>
-<link rel="help"
-  href="https://drafts.csswg.org/web-animations-1/#setting-the-current-time-of-an-animation">
-<script src='/resources/testharness.js'></script>
-<script src='/resources/testharnessreport.js'></script>
-<script src='../../testcommon.js'></script>
-<body>
-<div id='log'></div>
-<script>
-'use strict';
-
-promise_test(async t => {
-  const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  await anim.ready;
-  anim.pause();
-
-  // We should be pause-pending now
-  assert_true(anim.pending);
-  assert_equals(anim.playState, 'paused');
-
-  // Apply a pending playback rate
-  anim.updatePlaybackRate(2);
-  assert_equals(anim.playbackRate, 1);
-
-  // Setting the current time should apply the pending playback rate
-  anim.currentTime = 50 * MS_PER_SEC;
-  assert_equals(anim.playbackRate, 2);
-  assert_false(anim.pending);
-
-  // Sanity check that the current time is preserved
-  assert_time_equals_literal(anim.currentTime, 50 * MS_PER_SEC);
-}, 'Setting the current time of a pausing animation applies a pending playback'
-   + ' rate');
-
-</script>
-</body>
--- a/testing/web-platform/tests/web-animations/timing-model/animations/updating-the-finished-state.html
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/updating-the-finished-state.html
@@ -15,254 +15,251 @@
 // TESTS FOR UPDATING THE HOLD TIME
 //
 // --------------------------------------------------------------------
 
 // CASE 1: playback rate > 0 and current time >= target effect end
 // (Also the start time is resolved and there is pending task)
 
 // Did seek = false
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
 
   // Here and in the following tests we wait until ready resolves as
   // otherwise we don't have a resolved start time. We test the case
   // where the start time is unresolved in a subsequent test.
-  await anim.ready;
-
-  // Seek to 1ms before the target end and then wait 1ms
-  anim.currentTime = 100 * MS_PER_SEC - 1;
-  await waitForAnimationFramesWithDelay(1);
-
-  assert_equals(anim.currentTime, 100 * MS_PER_SEC,
-                'Hold time is set to target end clamping current time');
+  return anim.ready.then(() => {
+    // Seek to 1ms before the target end and then wait 1ms
+    anim.currentTime = 100 * MS_PER_SEC - 1;
+    return waitForAnimationFramesWithDelay(1);
+  }).then(() => {
+    assert_equals(anim.currentTime, 100 * MS_PER_SEC,
+                  'Hold time is set to target end clamping current time');
+  });
 }, 'Updating the finished state when playing past end');
 
 // Did seek = true
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
-
-  await anim.ready;
-
-  anim.currentTime = 200 * MS_PER_SEC;
-  await waitForNextFrame();
-
-  assert_equals(anim.currentTime, 200 * MS_PER_SEC,
-                'Hold time is set so current time should NOT change');
+  return anim.ready.then(() => {
+    anim.currentTime = 200 * MS_PER_SEC;
+    return waitForNextFrame();
+  }).then(() => {
+    assert_equals(anim.currentTime, 200 * MS_PER_SEC,
+                  'Hold time is set so current time should NOT change');
+  });
 }, 'Updating the finished state when seeking past end');
 
 // Test current time == target end
 //
 // We can't really write a test for current time == target end with
 // did seek = false since that would imply setting up an animation where
 // the next animation frame time happens to exactly align with the target end.
 //
 // Fortunately, we don't need to test that case since even if the implementation
 // fails to set the hold time on such a tick, it should be mostly unobservable
 // (on the subsequent tick the hold time will be set to the same value anyway).
 
 // Did seek = true
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
-  await anim.ready;
-
-  anim.currentTime = 100 * MS_PER_SEC;
-  await waitForNextFrame();
-
-  assert_equals(anim.currentTime, 100 * MS_PER_SEC,
-                'Hold time is set so current time should NOT change');
+  return anim.ready.then(() => {
+    anim.currentTime = 100 * MS_PER_SEC;
+    return waitForNextFrame();
+  }).then(() => {
+    assert_equals(anim.currentTime, 100 * MS_PER_SEC,
+                  'Hold time is set so current time should NOT change');
+  });
 }, 'Updating the finished state when seeking exactly to end');
 
 
 // CASE 2: playback rate < 0 and current time <= 0
 // (Also the start time is resolved and there is pending task)
 
 // Did seek = false
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
   anim.playbackRate = -1;
   anim.play(); // Make sure animation is not initially finished
-
-  await anim.ready;
-
-  // Seek to 1ms before 0 and then wait 1ms
-  anim.currentTime = 1;
-  await waitForAnimationFramesWithDelay(1);
-
-  assert_equals(anim.currentTime, 0 * MS_PER_SEC,
-                'Hold time is set to zero clamping current time');
+  return anim.ready.then(() => {
+    // Seek to 1ms before 0 and then wait 1ms
+    anim.currentTime = 1;
+    return waitForAnimationFramesWithDelay(1);
+  }).then(() => {
+    assert_equals(anim.currentTime, 0 * MS_PER_SEC,
+                  'Hold time is set to zero clamping current time');
+  });
 }, 'Updating the finished state when playing in reverse past zero');
 
 // Did seek = true
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
   anim.playbackRate = -1;
   anim.play();
-
-  await anim.ready;
-
-  anim.currentTime = -100 * MS_PER_SEC;
-  await waitForNextFrame();
-
-  assert_equals(anim.currentTime, -100 * MS_PER_SEC,
-                'Hold time is set so current time should NOT change');
+  return anim.ready.then(() => {
+    anim.currentTime = -100 * MS_PER_SEC;
+    return waitForNextFrame();
+  }).then(() => {
+    assert_equals(anim.currentTime, -100 * MS_PER_SEC,
+                  'Hold time is set so current time should NOT change');
+  });
 }, 'Updating the finished state when seeking a reversed animation past zero');
 
 // As before, it's difficult to test current time == 0 for did seek = false but
 // it doesn't really matter.
 
 // Did seek = true
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
   anim.playbackRate = -1;
   anim.play();
-  await anim.ready;
-
-  anim.currentTime = 0;
-  await waitForNextFrame();
-
-  assert_equals(anim.currentTime, 0 * MS_PER_SEC,
-                'Hold time is set so current time should NOT change');
+  return anim.ready.then(() => {
+    anim.currentTime = 0;
+    return waitForNextFrame();
+  }).then(() => {
+    assert_equals(anim.currentTime, 0 * MS_PER_SEC,
+                  'Hold time is set so current time should NOT change');
+  });
 }, 'Updating the finished state when seeking a reversed animation exactly'
    + ' to zero');
 
 // CASE 3: playback rate > 0 and current time < target end OR
 //         playback rate < 0 and current time > 0
 // (Also the start time is resolved and there is pending task)
 
 // Did seek = false; playback rate > 0
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
 
   // We want to test that the hold time is cleared so first we need to
   // put the animation in a state where the hold time is set.
   anim.finish();
-  await anim.ready;
-
-  assert_equals(anim.currentTime, 100 * MS_PER_SEC,
-                'Hold time is initially set');
-  // Then extend the duration so that the hold time is cleared and on
-  // the next tick the current time will increase.
-  anim.effect.timing.duration *= 2;
-  await waitForNextFrame();
-
-  assert_greater_than(anim.currentTime, 100 * MS_PER_SEC,
-                      'Hold time is not set so current time should increase');
+  return anim.ready.then(() => {
+    assert_equals(anim.currentTime, 100 * MS_PER_SEC,
+                  'Hold time is initially set');
+    // Then extend the duration so that the hold time is cleared and on
+    // the next tick the current time will increase.
+    anim.effect.timing.duration *= 2;
+    return waitForNextFrame();
+  }).then(() => {
+    assert_greater_than(anim.currentTime, 100 * MS_PER_SEC,
+                        'Hold time is not set so current time should increase');
+  });
 }, 'Updating the finished state when playing before end');
 
 // Did seek = true; playback rate > 0
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
   anim.finish();
-  await anim.ready;
-
-  anim.currentTime = 50 * MS_PER_SEC;
-  // When did seek = true, updating the finished state: (i) updates
-  // the animation's start time and (ii) clears the hold time.
-  // We can test both by checking that the currentTime is initially
-  // updated and then increases.
-  assert_equals(anim.currentTime, 50 * MS_PER_SEC, 'Start time is updated');
-  await waitForNextFrame();
-
-  assert_greater_than(anim.currentTime, 50 * MS_PER_SEC,
-                      'Hold time is not set so current time should increase');
+  return anim.ready.then(() => {
+    anim.currentTime = 50 * MS_PER_SEC;
+    // When did seek = true, updating the finished state: (i) updates
+    // the animation's start time and (ii) clears the hold time.
+    // We can test both by checking that the currentTime is initially
+    // updated and then increases.
+    assert_equals(anim.currentTime, 50 * MS_PER_SEC, 'Start time is updated');
+    return waitForNextFrame();
+  }).then(() => {
+    assert_greater_than(anim.currentTime, 50 * MS_PER_SEC,
+                        'Hold time is not set so current time should increase');
+  });
 }, 'Updating the finished state when seeking before end');
 
 // Did seek = false; playback rate < 0
 //
 // Unfortunately it is not possible to test this case. We need to have
 // a hold time set, a resolved start time, and then perform some
 // operation that updates the finished state with did seek set to true.
 //
 // However, the only situation where this could arrive is when we
 // replace the timeline and that procedure is likely to change. For all
 // other cases we either have an unresolved start time (e.g. when
 // paused), we don't have a set hold time (e.g. regular playback), or
 // the current time is zero (and anything that gets us out of that state
 // will set did seek = true).
 
 // Did seek = true; playback rate < 0
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
   anim.playbackRate = -1;
-  await anim.ready;
-
-  anim.currentTime = 50 * MS_PER_SEC;
-  assert_equals(anim.currentTime, 50 * MS_PER_SEC, 'Start time is updated');
-  await waitForNextFrame();
-
-  assert_less_than(anim.currentTime, 50 * MS_PER_SEC,
-                    'Hold time is not set so current time should decrease');
+  return anim.ready.then(() => {
+    anim.currentTime = 50 * MS_PER_SEC;
+    assert_equals(anim.currentTime, 50 * MS_PER_SEC, 'Start time is updated');
+    return waitForNextFrame();
+  }).then(() => {
+    assert_less_than(anim.currentTime, 50 * MS_PER_SEC,
+                     'Hold time is not set so current time should decrease');
+  });
 }, 'Updating the finished state when seeking a reversed animation before end');
 
 // CASE 4: playback rate == 0
 
 // current time < 0
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
   anim.playbackRate = 0;
-  await anim.ready;
-
-  anim.currentTime = -100 * MS_PER_SEC;
-  await waitForNextFrame();
-
-  assert_equals(anim.currentTime, -100 * MS_PER_SEC,
-                'Hold time should not be cleared so current time should'
-                + ' NOT change');
+  return anim.ready.then(() => {
+    anim.currentTime = -100 * MS_PER_SEC;
+    return waitForNextFrame();
+  }).then(() => {
+    assert_equals(anim.currentTime, -100 * MS_PER_SEC,
+                  'Hold time should not be cleared so current time should'
+                  + ' NOT change');
+  });
 }, 'Updating the finished state when playback rate is zero and the'
    + ' current time is less than zero');
 
 // current time < target end
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
   anim.playbackRate = 0;
-  await anim.ready;
-
-  anim.currentTime = 50 * MS_PER_SEC;
-  await waitForNextFrame();
-
-  assert_equals(anim.currentTime, 50 * MS_PER_SEC,
-                'Hold time should not be cleared so current time should'
-                + ' NOT change');
+  return anim.ready.then(() => {
+    anim.currentTime = 50 * MS_PER_SEC;
+    return waitForNextFrame();
+  }).then(() => {
+    assert_equals(anim.currentTime, 50 * MS_PER_SEC,
+                  'Hold time should not be cleared so current time should'
+                  + ' NOT change');
+  });
 }, 'Updating the finished state when playback rate is zero and the'
    + ' current time is less than end');
 
 // current time > target end
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
   anim.playbackRate = 0;
-  await anim.ready;
-
-  anim.currentTime = 200 * MS_PER_SEC;
-  await waitForNextFrame();
-
-  assert_equals(anim.currentTime, 200 * MS_PER_SEC,
-                'Hold time should not be cleared so current time should'
-                + ' NOT change');
+  return anim.ready.then(() => {
+    anim.currentTime = 200 * MS_PER_SEC;
+    return waitForNextFrame();
+  }).then(() => {
+    assert_equals(anim.currentTime, 200 * MS_PER_SEC,
+                  'Hold time should not be cleared so current time should'
+                  + ' NOT change');
+  });
 }, 'Updating the finished state when playback rate is zero and the'
    + ' current time is greater than end');
 
 // CASE 5: current time unresolved
 
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
   anim.cancel();
   // Trigger a change that will cause the "update the finished state"
   // procedure to run.
   anim.effect.timing.duration = 200 * MS_PER_SEC;
   assert_equals(anim.currentTime, null,
                 'The animation hold time / start time should not be updated');
   // The "update the finished state" procedure is supposed to run after any
   // change to timing, but just in case an implementation defers that, let's
   // wait a frame and check that the hold time / start time has still not been
   // updated.
-  await waitForAnimationFrames(1);
-
-  assert_equals(anim.currentTime, null,
-                'The animation hold time / start time should not be updated');
+  return waitForAnimationFrames(1).then(() => {
+    assert_equals(anim.currentTime, null,
+                  'The animation hold time / start time should not be updated');
+  });
 }, 'Updating the finished state when current time is unresolved');
 
 // CASE 6: has a pending task
 
 test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
   anim.cancel();
   anim.currentTime = 75 * MS_PER_SEC;
@@ -276,31 +273,31 @@ test(t => {
   anim.effect.timing.duration = 50 * MS_PER_SEC;
   assert_equals(anim.currentTime, 75 * MS_PER_SEC,
                 'Hold time should not be updated');
 }, 'Updating the finished state when there is a pending task');
 
 // CASE 7: start time unresolved
 
 // Did seek = false
-promise_test(async t => {
+promise_test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
   anim.cancel();
   // Make it so that only the start time is unresolved (to avoid overlapping
   // with the test case where current time is unresolved)
   anim.currentTime = 150 * MS_PER_SEC;
   // Trigger a change that will cause the "update the finished state"
   // procedure to run (did seek = false).
   anim.effect.timing.duration = 200 * MS_PER_SEC;
-  await waitForAnimationFrames(1);
-
-  assert_equals(anim.currentTime, 150 * MS_PER_SEC,
-                'The animation hold time should not be updated');
-  assert_equals(anim.startTime, null,
-                'The animation start time should not be updated');
+  return waitForAnimationFrames(1).then(() => {
+    assert_equals(anim.currentTime, 150 * MS_PER_SEC,
+                  'The animation hold time should not be updated');
+    assert_equals(anim.startTime, null,
+                  'The animation start time should not be updated');
+  });
 }, 'Updating the finished state when start time is unresolved and'
    + ' did seek = false');
 
 // Did seek = true
 test(t => {
   const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
   anim.cancel();
   anim.currentTime = 150 * MS_PER_SEC;
@@ -335,71 +332,63 @@ promise_test(t => {
     t.unreached_func('Seeking to finish should not resolve finished promise'));
   animation.currentTime = 1;
   animation.currentTime = 0;
   animation.pause();
   return waitForAnimationFrames(3);
 }, 'Finish notification steps don\'t run when the animation seeks to finish'
    + ' and then seeks back again');
 
-promise_test(async t => {
+promise_test(t => {
   const animation = createDiv(t).animate(null, 1);
-  await animation.ready;
-
-  return waitForFinishEventAndPromise(animation);
+  return animation.ready.then(() => {
+    return waitForFinishEventAndPromise(animation);
+  });
 }, 'Finish notification steps run when the animation completes normally');
 
-promise_test(async t => {
-  const effect = new KeyframeEffectReadOnly(null, null, 1);
-  const animation = new Animation(effect, document.timeline);
-  animation.play();
-  await animation.ready;
-
-  return waitForFinishEventAndPromise(animation);
-}, 'Finish notification steps run when an animation without a target'
-   + ' effect completes normally');
-
-promise_test(async t => {
+promise_test(t => {
   const animation = createDiv(t).animate(null, 1);
-  await animation.ready;
-
-  animation.currentTime = 10;
-  return waitForFinishEventAndPromise(animation);
+  return animation.ready.then(() => {
+    animation.currentTime = 10;
+    return waitForFinishEventAndPromise(animation);
+  });
 }, 'Finish notification steps run when the animation seeks past finish');
 
-promise_test(async t => {
+promise_test(t => {
   const animation = createDiv(t).animate(null, 1);
-  await animation.ready;
-
-  // Register for notifications now since once we seek away from being
-  // finished the 'finished' promise will be replaced.
-  const finishNotificationSteps = waitForFinishEventAndPromise(animation);
-  animation.finish();
-  animation.currentTime = 0;
-  animation.pause();
-  return finishNotificationSteps;
+  return animation.ready.then(() => {
+    // Register for notifications now since once we seek away from being
+    // finished the 'finished' promise will be replaced.
+    const finishNotificationSteps = waitForFinishEventAndPromise(animation);
+    animation.finish();
+    animation.currentTime = 0;
+    animation.pause();
+    return finishNotificationSteps;
+  });
 }, 'Finish notification steps run when the animation completes with .finish(),'
    + ' even if we then seek away');
 
-promise_test(async t => {
+promise_test(t => {
   const animation = createDiv(t).animate(null, 1);
   const initialFinishedPromise = animation.finished;
-  await animation.finished;
 
-  animation.currentTime = 0;
-  assert_not_equals(initialFinishedPromise, animation.finished);
+  return animation.finished.then(target => {
+    animation.currentTime = 0;
+    assert_not_equals(initialFinishedPromise, animation.finished);
+  });
 }, 'Animation finished promise is replaced after seeking back to start');
 
-promise_test(async t => {
+promise_test(t => {
   const animation = createDiv(t).animate(null, 1);
   const initialFinishedPromise = animation.finished;
-  await animation.finished;
 
-  animation.play();
-  assert_not_equals(initialFinishedPromise, animation.finished);
+  return animation.finished.then(target => {
+    animation.play();
+    assert_not_equals(initialFinishedPromise, animation.finished);
+  });
 }, 'Animation finished promise is replaced after replaying from start');
 
 async_test(t => {
   const animation = createDiv(t).animate(null, 1);
   animation.onfinish = event => {
     animation.currentTime = 0;
     animation.onfinish = event => {
       t.done();