Bug 1426250 - make tests actually pass valid mouse coordinates when testing Customize Mode, r?jaws draft
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Fri, 05 Jan 2018 21:35:27 +0000
changeset 719600 a388f02b8d5e00f7e670f41d049518be1de370dc
parent 719599 014c898dff8b446cbaa87e1567b644a66dfe5b53
child 745836 1df068c0750bc9fa3314c85ce90676477c155b2c
push id95299
push usergijskruitbosch@gmail.com
push dateFri, 12 Jan 2018 12:05:27 +0000
reviewersjaws
bugs1426250
milestone59.0a1
Bug 1426250 - make tests actually pass valid mouse coordinates when testing Customize Mode, r?jaws MozReview-Commit-ID: IglKedBqrWQ
browser/components/customizableui/CustomizeMode.jsm
browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js
browser/components/customizableui/test/browser_878452_drag_to_panel.js
browser/components/customizableui/test/browser_918049_skipintoolbarset_dnd.js
browser/components/customizableui/test/browser_968565_insert_before_hidden_items.js
browser/components/customizableui/test/browser_newtab_button_customizemode.js
browser/components/customizableui/test/browser_remove_customized_specials.js
browser/components/customizableui/test/head.js
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -2312,20 +2312,16 @@ CustomizeMode.prototype = {
     return aElement.closest(areas.map(a => "#" + CSS.escape(a)).join(","));
   },
 
   _getDragOverNode(aEvent, aAreaElement, aAreaType, aDraggedItemId) {
     let expectedParent = aAreaElement.customizationTarget || aAreaElement;
     if (!expectedParent.contains(aEvent.target)) {
       return expectedParent;
     }
-    // Our tests are stupid. Cope:
-    if (!aEvent.clientX && !aEvent.clientY) {
-      return aEvent.target;
-    }
     // Offset the drag event's position with the offset to the center of
     // the thing we're dragging
     let dragX = aEvent.clientX - this._dragOffset.x;
     let dragY = aEvent.clientY - this._dragOffset.y;
 
     // Ensure this is within the container
     let boundsContainer = expectedParent;
     let bounds = this._dwu.getBoundsWithoutFlushing(boundsContainer);
--- a/browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js
+++ b/browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js
@@ -9,53 +9,60 @@ const kAPIWidgetId = "feed-button";
 const kPanel = CustomizableUI.AREA_FIXED_OVERFLOW_PANEL;
 const kToolbar = CustomizableUI.AREA_NAVBAR;
 const kVisiblePalette = "customization-palette";
 
 function checkWrapper(id) {
   is(document.querySelectorAll("#wrapper-" + id).length, 1, "There should be exactly 1 wrapper for " + id + " in the customizing window.");
 }
 
-async function ensureVisibleIfInPalette(node) {
-    if (node.parentNode.parentNode == gNavToolbox.palette) {
-      node.scrollIntoView();
-      window.QueryInterface(Ci.nsIInterfaceRequestor);
-      let dwu = window.getInterface(Ci.nsIDOMWindowUtils);
-      await BrowserTestUtils.waitForCondition(() => {
-        let nodeBounds = dwu.getBoundsWithoutFlushing(node);
-        let paletteBounds = dwu.getBoundsWithoutFlushing(gNavToolbox.palette);
-        return nodeBounds.top >= paletteBounds.top && nodeBounds.bottom <= paletteBounds.bottom;
-      });
+async function ensureVisible(node) {
+  let isInPalette = node.parentNode.parentNode == gNavToolbox.palette;
+  if (isInPalette) {
+    node.scrollIntoView();
+  }
+  window.QueryInterface(Ci.nsIInterfaceRequestor);
+  let dwu = window.getInterface(Ci.nsIDOMWindowUtils);
+  await BrowserTestUtils.waitForCondition(() => {
+    let nodeBounds = dwu.getBoundsWithoutFlushing(node);
+    if (isInPalette) {
+      let paletteBounds = dwu.getBoundsWithoutFlushing(gNavToolbox.palette);
+      if (!(nodeBounds.top >= paletteBounds.top && nodeBounds.bottom <= paletteBounds.bottom)) {
+        return false;
+      }
     }
+    return nodeBounds.height && nodeBounds.width;
+  });
 }
 
 var move = {
   "drag": async function(id, target) {
     let targetNode = document.getElementById(target);
     if (targetNode.customizationTarget) {
       targetNode = targetNode.customizationTarget;
     }
     let nodeToMove = document.getElementById(id);
-    await ensureVisibleIfInPalette(nodeToMove);
-    simulateItemDrag(nodeToMove, targetNode);
+    await ensureVisible(nodeToMove);
+
+    simulateItemDrag(nodeToMove, targetNode, "end");
   },
   "dragToItem": async function(id, target) {
     let targetNode = document.getElementById(target);
     if (targetNode.customizationTarget) {
       targetNode = targetNode.customizationTarget;
     }
     let items = targetNode.querySelectorAll("toolbarpaletteitem");
     if (target == kPanel) {
       targetNode = items[items.length - 1];
     } else {
       targetNode = items[0];
     }
     let nodeToMove = document.getElementById(id);
-    await ensureVisibleIfInPalette(nodeToMove);
-    simulateItemDrag(nodeToMove, targetNode);
+    await ensureVisible(nodeToMove);
+    simulateItemDrag(nodeToMove, targetNode, "start");
   },
   "API": function(id, target) {
     if (target == kVisiblePalette) {
       return CustomizableUI.removeWidgetFromArea(id);
     }
     return CustomizableUI.addWidgetToArea(id, target, null);
   }
 };
@@ -145,16 +152,21 @@ async function checkPanel(id, method) {
 }
 
 async function checkPalette(id, method) {
   // Move back to palette:
   await move[method](id, kVisiblePalette);
   ok(CustomizableUI.inDefaultState, "Should end in default state");
   let visibleChildren = gCustomizeMode.visiblePalette.children;
   let expectedChild = method == "dragToItem" ? visibleChildren[0] : visibleChildren[visibleChildren.length - 1];
+  // Items dragged to the end of the palette should be the final item. That they're the penultimate
+  // item when dragged is tracked in bug 1395950. Once that's fixed, this hack can be removed.
+  if (method == "drag") {
+    expectedChild = expectedChild.previousElementSibling;
+  }
   is(expectedChild.firstChild.id, id, "Widget " + id + " was moved using " + method + " and should now be wrapped in palette in customizing window.");
   if (id == kXULWidgetId) {
     ok(otherWin.gNavToolbox.palette.querySelector("#" + id), "Widget " + id + " should be in invisible palette in other window.");
   }
   checkWrapper(id);
 }
 
 // This test needs a XUL button that's in the palette by default. No such
--- a/browser/components/customizableui/test/browser_878452_drag_to_panel.js
+++ b/browser/components/customizableui/test/browser_878452_drag_to_panel.js
@@ -10,17 +10,17 @@ add_task(async function() {
   await startCustomizing();
   let btn = document.getElementById("feed-button");
   let placements = getAreaWidgetIds(CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
 
   let lastButtonIndex = placements.length - 1;
   let lastButton = placements[lastButtonIndex];
   let placementsAfterInsert = placements.slice(0, lastButtonIndex).concat(["feed-button", lastButton]);
   let lastButtonNode = document.getElementById(lastButton);
-  simulateItemDrag(btn, lastButtonNode);
+  simulateItemDrag(btn, lastButtonNode, "start");
   assertAreaPlacements(CustomizableUI.AREA_FIXED_OVERFLOW_PANEL, placementsAfterInsert);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let palette = document.getElementById("customization-palette");
   simulateItemDrag(btn, palette);
   CustomizableUI.removeWidgetFromArea("cui-panel-item-to-drag-to");
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
@@ -58,12 +58,13 @@ add_task(async function() {
   simulateItemDrag(btn, panel);
   assertAreaPlacements(CustomizableUI.AREA_FIXED_OVERFLOW_PANEL, placementsAfterAppend);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let palette = document.getElementById("customization-palette");
   simulateItemDrag(btn, palette);
   assertAreaPlacements(panel.id, []);
 });
 
-add_task(async function asyncCleanup() {
+registerCleanupFunction(async function asyncCleanup() {
+  CustomizableUI.destroyWidget("cui-panel-item-to-drag-to");
   await endCustomizing();
   await resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_918049_skipintoolbarset_dnd.js
+++ b/browser/components/customizableui/test/browser_918049_skipintoolbarset_dnd.js
@@ -13,23 +13,24 @@ add_task(async function() {
   skippedItem = document.createElement("toolbarbutton");
   skippedItem.id = "test-skipintoolbarset-item";
   skippedItem.setAttribute("label", "Test");
   skippedItem.setAttribute("skipintoolbarset", "true");
   skippedItem.setAttribute("removable", "true");
   navbar.customizationTarget.appendChild(skippedItem);
   let libraryButton = document.getElementById("library-button");
   await startCustomizing();
+  await waitForElementShown(skippedItem);
   ok(CustomizableUI.inDefaultState, "Should still be in default state");
-  simulateItemDrag(skippedItem, libraryButton);
+  simulateItemDrag(skippedItem, libraryButton, "start");
   ok(CustomizableUI.inDefaultState, "Should still be in default state");
   let skippedItemWrapper = skippedItem.parentNode;
   is(skippedItemWrapper.nextSibling && skippedItemWrapper.nextSibling.id,
      libraryButton.parentNode.id, "Should be next to library button");
-  simulateItemDrag(libraryButton, skippedItem);
+  simulateItemDrag(libraryButton, skippedItem, "start");
   let libraryWrapper = libraryButton.parentNode;
   is(libraryWrapper.nextSibling && libraryWrapper.nextSibling.id,
      skippedItem.parentNode.id, "Should be next to skipintoolbarset item");
   ok(CustomizableUI.inDefaultState, "Should still be in default state");
 });
 
 add_task(async function asyncCleanup() {
   await endCustomizing();
--- a/browser/components/customizableui/test/browser_968565_insert_before_hidden_items.js
+++ b/browser/components/customizableui/test/browser_968565_insert_before_hidden_items.js
@@ -40,17 +40,17 @@ add_task(async function() {
   // Make sure we have some hidden items at the end of the nav-bar.
   navbar.insertItem(hidden1.id);
   navbar.insertItem(hidden2.id);
 
   // Drag an item and drop it onto the nav-bar customization target, but
   // not over a particular item.
   await startCustomizing();
   let homeButton = document.getElementById("home-button");
-  simulateItemDrag(homeButton, navbar.customizationTarget);
+  simulateItemDrag(homeButton, navbar.customizationTarget, "end");
 
   await endCustomizing();
 
   is(homeButton.previousSibling.id, lastVisible.id,
      "The downloads button should be placed after the last visible item.");
 
   await resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_newtab_button_customizemode.js
+++ b/browser/components/customizableui/test/browser_newtab_button_customizemode.js
@@ -27,46 +27,49 @@ function assertNewTabButton(which) {
   }
 }
 
 /**
  * Add and remove items *after* the new tab button in customize mode.
  */
 add_task(async function addremove_after_newtab_customizemode() {
   await startCustomizing();
-  simulateItemDrag(document.getElementById("home-button"),
-                   kGlobalNewTabButton.parentNode.nextElementSibling);
+  await waitForElementShown(kGlobalNewTabButton);
+  simulateItemDrag(document.getElementById("home-button"), kGlobalNewTabButton, "end");
   ok(gBrowser.tabContainer.hasAttribute("hasadjacentnewtabbutton"),
     "tabs should have the adjacent newtab attribute");
   await endCustomizing();
   assertNewTabButton("inner");
 
   await startCustomizing();
-  simulateItemDrag(document.getElementById("home-button"),
-    document.getElementById("stop-reload-button").parentNode.nextElementSibling);
+  let dropTarget = document.getElementById("stop-reload-button");
+  await waitForElementShown(dropTarget);
+  simulateItemDrag(document.getElementById("home-button"), dropTarget, "end");
   ok(gBrowser.tabContainer.hasAttribute("hasadjacentnewtabbutton"),
     "tabs should still have the adjacent newtab attribute");
   await endCustomizing();
   assertNewTabButton("inner");
   ok(CustomizableUI.inDefaultState, "Should be in default state");
 });
 
 /**
  * Add and remove items *before* the new tab button in customize mode.
  */
 add_task(async function addremove_before_newtab_customizemode() {
   await startCustomizing();
-  simulateItemDrag(document.getElementById("home-button"), kGlobalNewTabButton);
+  await waitForElementShown(kGlobalNewTabButton);
+  simulateItemDrag(document.getElementById("home-button"), kGlobalNewTabButton, "start");
   ok(!gBrowser.tabContainer.hasAttribute("hasadjacentnewtabbutton"),
     "tabs should no longer have the adjacent newtab attribute");
   await endCustomizing();
   assertNewTabButton("global");
   await startCustomizing();
-  simulateItemDrag(document.getElementById("home-button"),
-    document.getElementById("stop-reload-button").parentNode.nextElementSibling);
+  let dropTarget = document.getElementById("stop-reload-button");
+  await waitForElementShown(dropTarget);
+  simulateItemDrag(document.getElementById("home-button"), dropTarget, "end");
   ok(gBrowser.tabContainer.hasAttribute("hasadjacentnewtabbutton"),
     "tabs should have the adjacent newtab attribute again");
   await endCustomizing();
   assertNewTabButton("inner");
   ok(CustomizableUI.inDefaultState, "Should be in default state");
 });
 
 /**
@@ -105,17 +108,18 @@ add_task(async function addremove_before
   ok(CustomizableUI.inDefaultState, "Should be in default state");
 });
 
 /**
   * Reset to defaults in customize mode to see if that doesn't break things.
   */
 add_task(async function reset_before_newtab_customizemode() {
   await startCustomizing();
-  simulateItemDrag(document.getElementById("home-button"), kGlobalNewTabButton);
+  await waitForElementShown(kGlobalNewTabButton);
+  simulateItemDrag(document.getElementById("home-button"), kGlobalNewTabButton, "start");
   ok(!gBrowser.tabContainer.hasAttribute("hasadjacentnewtabbutton"),
     "tabs should no longer have the adjacent newtab attribute");
   await endCustomizing();
   assertNewTabButton("global");
   await startCustomizing();
   await gCustomizeMode.reset();
   ok(gBrowser.tabContainer.hasAttribute("hasadjacentnewtabbutton"),
     "tabs should have the adjacent newtab attribute again");
--- a/browser/components/customizableui/test/browser_remove_customized_specials.js
+++ b/browser/components/customizableui/test/browser_remove_customized_specials.js
@@ -10,19 +10,20 @@ add_task(async function() {
   await startCustomizing();
   CustomizableUI.addWidgetToArea("spring", "nav-bar", 5);
   await gCustomizeMode.reset();
   let springs = document.querySelectorAll("#nav-bar toolbarspring");
   let lastSpring = springs[springs.length - 1];
   let expectedPlacements = CustomizableUI.getWidgetIdsInArea("nav-bar");
   info("Placements before drag: " + expectedPlacements.join(","));
   let lastItem = document.getElementById(expectedPlacements[expectedPlacements.length - 1]);
-  simulateItemDrag(lastSpring, lastItem);
+  await waitForElementShown(lastItem);
+  simulateItemDrag(lastSpring, lastItem, "end");
   expectedPlacements.splice(expectedPlacements.indexOf(lastSpring.id), 1);
-  expectedPlacements.splice(expectedPlacements.length - 1, 0, lastSpring.id);
+  expectedPlacements.push(lastSpring.id);
   let actualPlacements = CustomizableUI.getWidgetIdsInArea("nav-bar");
   // Log these separately because Assert.deepEqual truncates the stringified versions...
   info("Actual placements: " + actualPlacements.join(","));
   info("Expected placements: " + expectedPlacements.join(","));
   Assert.deepEqual(expectedPlacements, actualPlacements, "Should be able to move spring");
   await gCustomizeMode.reset();
   await endCustomizing();
 });
--- a/browser/components/customizableui/test/head.js
+++ b/browser/components/customizableui/test/head.js
@@ -164,18 +164,32 @@ function todoAssertAreaPlacements(areaId
   todo(isPassing, "The area placements for " + areaId +
                   " should equal the expected placements.");
 }
 
 function getAreaWidgetIds(areaId) {
   return CustomizableUI.getWidgetIdsInArea(areaId);
 }
 
-function simulateItemDrag(aToDrag, aTarget) {
-  synthesizeDrop(aToDrag.parentNode, aTarget);
+function simulateItemDrag(aToDrag, aTarget, aEvent = {}) {
+  let ev = aEvent;
+  if (ev == "end" || ev == "start") {
+    let win = aTarget.ownerGlobal;
+    win.QueryInterface(Ci.nsIInterfaceRequestor);
+    const dwu = win.getInterface(Ci.nsIDOMWindowUtils);
+    let bounds = dwu.getBoundsWithoutFlushing(aTarget);
+    if (ev == "end") {
+      ev = {clientX: bounds.right - 2, clientY: bounds.bottom - 2};
+    } else {
+      ev = {clientX: bounds.left + 2, clientY: bounds.top + 2};
+    }
+  }
+  ev._domDispatchOnly = true;
+  synthesizeDrop(aToDrag.parentNode, aTarget, null, null,
+                 aToDrag.ownerGlobal, aTarget.ownerGlobal, ev);
 }
 
 function endCustomizing(aWindow = window) {
   if (aWindow.document.documentElement.getAttribute("customizing") != "true") {
     return true;
   }
   return new Promise(resolve => {
     function onCustomizationEnds() {
@@ -492,17 +506,21 @@ function checkContextMenu(aContextMenu, 
       is(menuItemDisabled, !aExpectedEntries[i][1], "disabled state for " + selector);
     } catch (e) {
       ok(false, "Exception when checking context menu: " + e);
     }
   }
 }
 
 function waitForOverflowButtonShown(win = window) {
+  let ov = win.document.getElementById("nav-bar-overflow-button");
+  let icon = win.document.getAnonymousElementByAttribute(ov, "class", "toolbarbutton-icon");
+  return waitForElementShown(icon);
+}
+function waitForElementShown(element) {
+  let win = element.ownerGlobal;
   let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
   return BrowserTestUtils.waitForCondition(() => {
     info("Waiting for overflow button to have non-0 size");
-    let ov = win.document.getElementById("nav-bar-overflow-button");
-    let icon = win.document.getAnonymousElementByAttribute(ov, "class", "toolbarbutton-icon");
-    let bounds = dwu.getBoundsWithoutFlushing(icon);
+    let bounds = dwu.getBoundsWithoutFlushing(element);
     return bounds.width > 0 && bounds.height > 0;
   });
 }