Bug 1488379 - guard for errors; r=daisuke
authoryulia <ystartsev@mozilla.com>
Thu, 18 Oct 2018 08:54:56 +0000
changeset 490240 a0e2d7e922d83b15720c193f672312e639634a33
parent 490239 d522a86504a76831e59348784c25e81162fe540a
child 490241 1f35618c6e3c52748c84e62a15854dbb7a575206
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersdaisuke
bugs1488379
milestone64.0a1
Bug 1488379 - guard for errors; r=daisuke Depends on D7986 Differential Revision: https://phabricator.services.mozilla.com/D8736
devtools/client/inspector/animation/animation.js
devtools/client/inspector/animation/test/browser_animation_logic_mutations_fast.js
devtools/client/inspector/animation/test/head.js
--- a/devtools/client/inspector/animation/animation.js
+++ b/devtools/client/inspector/animation/animation.js
@@ -320,17 +320,22 @@ class AnimationInspector {
         animation.off("changed", this.onAnimationStateChanged);
       }
     }
 
     // Update existing other animations as well since the currentTime would be proceeded
     // sice the scrubber position is related the currentTime.
     // Also, don't update the state of removed animations since React components
     // may refer to the same instance still.
-    animations = await this.updateAnimations(animations);
+    try {
+      animations = await this.updateAnimations(animations);
+    } catch (_) {
+      console.error(`Updating Animations failed`);
+      return;
+    }
 
     this.updateState(animations.concat(addedAnimations));
   }
 
   onElementPickerStarted() {
     this.inspector.store.dispatch(updateElementPickerEnabled(true));
   }
 
--- a/devtools/client/inspector/animation/test/browser_animation_logic_mutations_fast.js
+++ b/devtools/client/inspector/animation/test/browser_animation_logic_mutations_fast.js
@@ -5,18 +5,28 @@
 
 // Test whether the animation inspector will not crash when remove/add animations faster.
 
 add_task(async function() {
   const tab = await addTab(URL_ROOT + "doc_mutations_fast.html");
   const { inspector } = await openAnimationInspector();
 
   info("Check state of the animation inspector after fast mutations");
+  const animationsFinished = waitForAnimations(inspector);
   await startFastMutations(tab);
   ok(inspector.panelWin.document.getElementById("animation-container"),
     "Animation inspector should be live");
+  await animationsFinished;
 });
 
 async function startFastMutations(tab) {
   await ContentTask.spawn(tab.linkedBrowser, {}, async function() {
     await content.wrappedJSObject.startFastMutations();
   });
 }
+
+function waitForAnimations(inspector) {
+  // wait at least once
+  let count = 1;
+  // queue any further waits
+  inspector.animationinspector.animationsFront.on("mutations", () => count++);
+  return waitForDispatch(inspector, "UPDATE_ANIMATIONS", () => count);
+}
--- a/devtools/client/inspector/animation/test/head.js
+++ b/devtools/client/inspector/animation/test/head.js
@@ -549,16 +549,61 @@ const setStyles = async function(animati
 const waitForRendering = async function(animationInspector) {
   await Promise.all([
     waitForAllAnimationTargets(animationInspector),
     waitForAllSummaryGraph(animationInspector),
     waitForAnimationDetail(animationInspector),
   ]);
 };
 
+// Wait until an action of `type` is dispatched. If it's part of an
+// async operation, wait until the `status` field is "done" or "error"
+function _afterDispatchDone(store, type) {
+  return new Promise(resolve => {
+    store.dispatch({
+      // Normally we would use `services.WAIT_UNTIL`, but use the
+      // internal name here so tests aren't forced to always pass it
+      // in
+      type: "@@service/waitUntil",
+      predicate: action => {
+        if (action.type === type) {
+          return true;
+        }
+        return false;
+      },
+      run: (dispatch, getState, action) => {
+        resolve(action);
+      }
+    });
+  });
+}
+
+/**
+ * Wait for a specific action type to be dispatch.
+ * If an async action, will wait for it to be done.
+ * This is a custom waitForDispatch, and rather than having a number to wait on
+ * the function has a callback, that returns a number. This allows us to wait for
+ * an unknown number of dispatches.
+ *
+ * @memberof mochitest/waits
+ * @param {Object} inspector
+ * @param {String} type
+ * @param {Function} repeat
+ * @return {Promise}
+ * @static
+ */
+async function waitForDispatch(inspector, type, repeat) {
+  let count = 0;
+
+  while (count < repeat()) {
+    await _afterDispatchDone(inspector.store, type);
+    count++;
+  }
+}
+
 /**
  * Wait for rendering of animation keyframes.
  *
  * @param {AnimationInspector} inspector
  */
 
 const waitForAnimationDetail = async function(animationInspector) {
   if (animationInspector.state.selectedAnimation &&