Bug 1115276 - Make tests that set toolbar visibility wait for any animations to finish before continuing. r=mak, a=test-only
☠☠ backed out by fd6e773ba8ed ☠ ☠
authorBrian Birtles <birtles@gmail.com>
Tue, 27 Jan 2015 16:05:33 +0900
changeset 249577 5e7224465ff5cefc69ac77fca6fc225bdcbac60f
parent 249576 d4082de0ab03cf91c785effe6b0db1ce12ee0bef
child 249578 c5ad3e0d1f4d2e689405b4a3685f235bedc71f2d
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak, test-only
bugs1115276
milestone37.0a2
Bug 1115276 - Make tests that set toolbar visibility wait for any animations to finish before continuing. r=mak, a=test-only
browser/components/places/tests/browser/browser.ini
browser/components/places/tests/browser/browser_475045.js
browser/components/places/tests/browser/browser_555547.js
browser/components/places/tests/browser/browser_drag_bookmarks_on_toolbar.js
browser/components/places/tests/browser/browser_views_liveupdate.js
browser/components/places/tests/browser/head.js
--- a/browser/components/places/tests/browser/browser.ini
+++ b/browser/components/places/tests/browser/browser.ini
@@ -43,17 +43,17 @@ skip-if = e10s # Bug ?????? - test fails
 skip-if = true
 
 [browser_library_infoBox.js]
 [browser_markPageAsFollowedLink.js]
 skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly (test does EventUtils.sendMouseEvent...)
 [browser_toolbar_migration.js]
 [browser_library_batch_delete.js]
 [browser_555547.js]
-skip-if = e10s || (os == "win" && !debug) # Bug 1115276
+skip-if = e10s
 [browser_416459_cut.js]
 skip-if = e10s # Bug ?????? - clipboard operations don't seem to work in this test?
 [browser_library_downloads.js]
 [browser_library_left_pane_select_hierarchy.js]
 [browser_435851_copy_query.js]
 skip-if = e10s
 [browser_toolbarbutton_menu_context.js]
 skip-if = e10s
--- a/browser/components/places/tests/browser/browser_475045.js
+++ b/browser/components/places/tests/browser/browser_475045.js
@@ -2,25 +2,25 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 // Instead of loading ChromeUtils.js into the test scope in browser-test.js for all tests,
 // we only need ChromeUtils.js for a few files which is why we are using loadSubScript.
 var ChromeUtils = {};
 this._scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
                      getService(Ci.mozIJSSubScriptLoader);
 this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js", ChromeUtils);
 
-function test() {
+add_task(function* test() {
   // Make sure the bookmarks bar is visible and restore its state on cleanup.
   let toolbar = document.getElementById("PersonalToolbar");
   ok(toolbar, "PersonalToolbar should not be null");
 
   if (toolbar.collapsed) {
-    setToolbarVisibility(toolbar, true);
+    yield promiseSetToolbarVisibility(toolbar, true);
     registerCleanupFunction(function() {
-      setToolbarVisibility(toolbar, false);
+      return promiseSetToolbarVisibility(toolbar, false);
     });
   }
 
   // Setup the node we will use to be dropped. The actual node used does not
   // matter because we will set its data, effect, and mimeType manually.
   let placesItems = document.getElementById("PlacesToolbarItems");
   ok(placesItems, "PlacesToolbarItems should not be null");
   ok(placesItems.localName == "scrollbox", "PlacesToolbarItems should not be null");
@@ -57,9 +57,9 @@ function test() {
   // Simulate a bookmark drop for all of the mime types and effects.
   let mimeTypes = ["text/plain", "text/unicode", "text/x-moz-url"];
   let effects = ["move", "copy", "link"];
   effects.forEach(function (effect) {
     mimeTypes.forEach(function (mimeType) {
       simulateDragDrop(effect, mimeType);
     });
   });
-}
+});
--- a/browser/components/places/tests/browser/browser_555547.js
+++ b/browser/components/places/tests/browser/browser_555547.js
@@ -1,23 +1,23 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-function test() {
+add_task(function* test() {
   waitForExplicitFinish();
 
   let sidebarBox = document.getElementById("sidebar-box");
   is(sidebarBox.hidden, true, "The sidebar should be hidden");
 
   // Uncollapse the personal toolbar if needed.
   let toolbar = document.getElementById("PersonalToolbar");
   let wasCollapsed = toolbar.collapsed;
   if (wasCollapsed)
-    setToolbarVisibility(toolbar, true);
+    yield promiseSetToolbarVisibility(toolbar, true);
 
   let sidebar = document.getElementById("sidebar");
   sidebar.addEventListener("load", function() {
     sidebar.removeEventListener("load", arguments.callee, true);
     let tree = sidebar.contentDocument.getElementById("bookmarks-view");
 
     // The Places view is build on load, so we enqueue our test.
     executeSoon(function() {
@@ -45,15 +45,15 @@ function test() {
 
       // Now that the context menu is closed, try to get the tree controller again.
       tree.focus();
       controller = doGetPlacesControllerForCommand("placesCmd_copy");
       ok(controller == treeController, "tree controller was returned");
 
       toggleSidebar();
       if (wasCollapsed)
-        setToolbarVisibility(toolbar, false);
+        yield promiseSetToolbarVisibility(toolbar, false);
 
       finish();
     });
   }, true);
   toggleSidebar("viewBookmarksSidebar", true);
-}
+});
--- a/browser/components/places/tests/browser/browser_drag_bookmarks_on_toolbar.js
+++ b/browser/components/places/tests/browser/browser_drag_bookmarks_on_toolbar.js
@@ -133,26 +133,16 @@ function getExpectedDataForPlacesNode(aN
     var wrappedFlavor = aFlavor + ": " +
                         PlacesUtils.wrapNode(aNode, aFlavor);
     wrappedNode.push(wrappedFlavor);
   });
 
   return [wrappedNode];
 }
 
-function afterToolbarTransition(callback) {
-  function listener(event) {
-    if (event.propertyName == "max-height") {
-      toolbar.removeEventListener("transitionend", listener);
-      callback();
-    }
-  }
-  toolbar.addEventListener("transitionend", listener);
-}
-
 var gTests = [
 
 //------------------------------------------------------------------------------
 
   {
     desc: "Drag a folder on toolbar",
     run: function() {
       // Create a test folder to be dragged.
@@ -240,31 +230,29 @@ function nextTest() {
     waitForFocus(function() {
       info("Start of test: " + test.desc);
       test.run();
     });
   }
   else {
     // Collapse the personal toolbar if needed.
     if (wasCollapsed) {
-      setToolbarVisibility(toolbar, false);
-      afterToolbarTransition(finish);
+      promiseSetToolbarVisibility(toolbar, false).then(finish);
     } else {
       finish();
     }
   }
 }
 
 let toolbar = document.getElementById("PersonalToolbar");
 let wasCollapsed = toolbar.collapsed;
 
 function test() {
   waitForExplicitFinish();
 
   // Uncollapse the personal toolbar if needed.
   if (wasCollapsed) {
-    setToolbarVisibility(toolbar, true);
-    afterToolbarTransition(nextTest);
+    promiseSetToolbarVisibility(toolbar, true).then(nextTest);
   } else {
     nextTest();
   }
 }
 
--- a/browser/components/places/tests/browser/browser_views_liveupdate.js
+++ b/browser/components/places/tests/browser/browser_views_liveupdate.js
@@ -5,22 +5,27 @@
 /**
  * Tests Places views (menu, toolbar, tree) for liveupdate.
  */
 
 let toolbar = document.getElementById("PersonalToolbar");
 let wasCollapsed = toolbar.collapsed;
 
 function test() {
-  // Uncollapse the personal toolbar if needed.
-  if (wasCollapsed)
-    setToolbarVisibility(toolbar, true);
-
   waitForExplicitFinish();
 
+  // Uncollapse the personal toolbar if needed.
+  if (wasCollapsed) {
+    promiseSetToolbarVisibility(toolbar, true).then(openBookmarksSidebar);
+  } else {
+    openBookmarksSidebar();
+  }
+}
+
+function openBookmarksSidebar() {
   // Sanity checks.
   ok(PlacesUtils, "PlacesUtils in context");
   ok(PlacesUIUtils, "PlacesUIUtils in context");
 
   // Open bookmarks menu.
   var popup = document.getElementById("bookmarksMenuPopup");
   ok(popup, "Menu popup element exists");
   fakeOpenPopup(popup);
@@ -164,20 +169,21 @@ function startTest() {
 /**
  * Restores browser state and calls finish.
  */
 function finishTest() {
   // Close bookmarks sidebar.
   toggleSidebar("viewBookmarksSidebar", false);
 
   // Collapse the personal toolbar if needed.
-  if (wasCollapsed)
-    setToolbarVisibility(toolbar, false);
-
-  finish();
+  if (wasCollapsed) {
+    promiseSetToolbarVisibility(toolbar, false).then(finish);
+  } else {
+    finish();
+  }
 }
 
 /**
  * The observer is where magic happens, for every change we do it will look for
  * nodes positions in the affected views.
  */
 var bookmarksObserver = {
   QueryInterface: XPCOMUtils.generateQI([
--- a/browser/components/places/tests/browser/head.js
+++ b/browser/components/places/tests/browser/head.js
@@ -369,16 +369,81 @@ function promiseHistoryNotification(noti
     let timeout = setTimeout(() => {
       PlacesUtils.history.removeObserver(proxifiedObserver, false);
       reject(new Error("Timed out while waiting for history notification"));
     }, 2000);
   });
 }
 
 /**
+ * Makes the specified toolbar visible or invisible and returns a Promise object
+ * that is resolved when the toolbar has completed any animations associated
+ * with hiding or showing the toolbar.
+ *
+ * Note that this code assumes that changes to a toolbar's visibility trigger
+ * a transition on the max-height property of the toolbar element.
+ * Changes to this styling could cause the returned Promise object to be
+ * resolved too early or not at all.
+ *
+ * @param aToolbar
+ *        The toolbar to update.
+ * @param aVisible
+ *        True to make the toolbar visible, false to make it hidden.
+ *
+ * @return {Promise}
+ * @resolves Any animation associated with updating the toolbar's visibility has
+ *           finished.
+ * @rejects Never.
+ */
+function promiseSetToolbarVisibility(aToolbar, aVisible, aCallback) {
+  return new Promise((resolve, reject) => {
+    function listener(event) {
+      if (event.propertyName == "max-height") {
+        aToolbar.removeEventListener("transitionend", listener);
+        resolve();
+      }
+    }
+
+    let transitionProperties =
+      window.getComputedStyle(aToolbar).transitionProperty.split(", ");
+    if (isToolbarVisible(aToolbar) != aVisible &&
+        (transitionProperties.includes("max-height") ||
+         transitionProperties.includes("all"))) {
+      // Just because max-height is a transitionable property doesn't mean
+      // a transition will be triggered, but it's more likely.
+      aToolbar.addEventListener("transitionend", listener);
+      setToolbarVisibility(aToolbar, aVisible);
+      return;
+    }
+
+    // No animation to wait for
+    setToolbarVisibility(aToolbar, aVisible);
+    resolve();
+  });
+}
+
+/**
+ * Helper function to determine if the given toolbar is in the visible
+ * state according to its autohide/collapsed attribute.
+ *
+ * @aToolbar The toolbar to query.
+ *
+ * @returns True if the relevant attribute on |aToolbar| indicates it is
+ *          visible, false otherwise.
+ */
+function isToolbarVisible(aToolbar) {
+  let hidingAttribute = aToolbar.getAttribute("type") == "menubar"
+                        ? "autohide"
+                        : "collapsed";
+  let hidingValue = aToolbar.getAttribute(hidingAttribute).toLowerCase();
+  // Check for both collapsed="true" and collapsed="collapsed"
+  return hidingValue !== "true" && hidingValue !== hidingAttribute;
+}
+
+/**
  * Clears history asynchronously.
  *
  * @return {Promise}
  * @resolves When history has been cleared.
  * @rejects Never.
  */
 function promiseClearHistory() {
   let promise = promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED);