Bug 1330822 - Remove CPOWs from browser_context_menu_iframe.js. r=Gijs draft
authorBlake Kaplan <mrbkap@gmail.com>
Fri, 11 Nov 2016 15:07:18 -0800
changeset 463349 5e8a882e4661052e26f65991e2b61cd65f2acf62
parent 463348 fc5158ab34dbe9fb469a7a8a171a8e30b1dbff54
child 463350 42bb8a81d3af57a1e88eacb4d65bf35459e77d3c
push id42038
push userbmo:mrbkap@mozilla.com
push dateWed, 18 Jan 2017 23:45:52 +0000
reviewersGijs
bugs1330822
milestone53.0a1
Bug 1330822 - Remove CPOWs from browser_context_menu_iframe.js. r=Gijs This was tricky because synthesizeMouse would compute the incorrect coordinates if the requested event target was in a sub-frame. With this patch, we deal correctly with sub-frames. MozReview-Commit-ID: KpUKxFXKMrl
testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
testing/mochitest/tests/SimpleTest/AsyncUtilsContent.js
toolkit/components/passwordmgr/test/browser/browser_context_menu_iframe.js
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
+++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
@@ -733,21 +733,25 @@ this.BrowserTestUtils = {
    * @param {Browser} browser
    *        Browser element, must not be null
    *
    * @returns {Promise}
    * @resolves True if the mouse event was cancelled.
    */
   synthesizeMouse(target, offsetX, offsetY, event, browser)
   {
-    return new Promise(resolve => {
+    return new Promise((resolve, reject) => {
       let mm = browser.messageManager;
       mm.addMessageListener("Test:SynthesizeMouseDone", function mouseMsg(message) {
         mm.removeMessageListener("Test:SynthesizeMouseDone", mouseMsg);
-        resolve(message.data.defaultPrevented);
+        if (message.data.hasOwnProperty("defaultPrevented")) {
+          resolve(message.data.defaultPrevented);
+        } else {
+          reject(new Error(message.data.error));
+        }
       });
 
       let cpowObject = null;
       let targetFn = null;
       if (typeof target == "function") {
         targetFn = target.toString();
         target = null;
       } else if (typeof target != "string") {
--- a/testing/mochitest/tests/SimpleTest/AsyncUtilsContent.js
+++ b/testing/mochitest/tests/SimpleTest/AsyncUtilsContent.js
@@ -32,16 +32,37 @@ addMessageListener("Test:SynthesizeMouse
   }
   else {
     target = message.objects.object;
   }
 
   let left = data.x;
   let top = data.y;
   if (target) {
+    if (target.ownerDocument !== content.document) {
+      // Account for nodes found in iframes.
+      let cur = target;
+      do {
+        let frame = cur.ownerDocument.defaultView.frameElement;
+        let rect = frame.getBoundingClientRect();
+
+        left += rect.left;
+        top += rect.top;
+
+        cur = frame;
+      } while (cur && cur.ownerDocument !== content.document);
+
+      // node must be in this document tree.
+      if (!cur) {
+        sendAsyncMessage("Test:SynthesizeMouseDone",
+                         { error: "target must be in the main document tree" });
+        return;
+      }
+    }
+
     let rect = target.getBoundingClientRect();
     left += rect.left;
     top += rect.top;
 
     if (data.event.centered) {
       left += rect.width / 2;
       top += rect.height / 2;
     }
--- a/toolkit/components/passwordmgr/test/browser/browser_context_menu_iframe.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_context_menu_iframe.js
@@ -28,60 +28,68 @@ add_task(function* test_initialize() {
  * Check if the password field is correctly filled when it's in an iframe.
  */
 add_task(function* test_context_menu_iframe_fill() {
   Services.prefs.setBoolPref("signon.schemeUpgrades", true);
   yield BrowserTestUtils.withNewTab({
     gBrowser,
     url: TEST_HOSTNAME + IFRAME_PAGE_PATH
   }, function* (browser) {
-    let iframe = browser.contentWindow.document.getElementById("test-iframe");
-    let passwordInput = iframe.contentDocument.getElementById("form-basic-password");
+    function getPasswordInput() {
+      let frame = content.document.getElementById("test-iframe");
+      return frame.contentDocument.getElementById("form-basic-password");
+    }
 
     let contextMenuShownPromise = BrowserTestUtils.waitForEvent(window, "popupshown");
     let eventDetails = {type: "contextmenu", button: 2};
 
     // To click at the right point we have to take into account the iframe offset.
-    let iframeRect = iframe.getBoundingClientRect();
-    let inputRect = passwordInput.getBoundingClientRect();
-    let clickPos = {
-      offsetX: iframeRect.left + inputRect.width / 2,
-      offsetY: iframeRect.top + inputRect.height / 2,
-    };
-
     // Synthesize a right mouse click over the password input element.
-    BrowserTestUtils.synthesizeMouse(passwordInput, clickPos.offsetX, clickPos.offsetY, eventDetails, browser);
+    BrowserTestUtils.synthesizeMouseAtCenter(getPasswordInput, eventDetails, browser);
     yield contextMenuShownPromise;
 
     // Synthesize a mouse click over the fill login menu header.
     let popupHeader = document.getElementById("fill-login");
     let popupShownPromise = BrowserTestUtils.waitForEvent(popupHeader, "popupshown");
     EventUtils.synthesizeMouseAtCenter(popupHeader, {});
     yield popupShownPromise;
 
     let popupMenu = document.getElementById("fill-login-popup");
 
     // Stores the original value of username
-    let usernameInput = iframe.contentDocument.getElementById("form-basic-username");
-    let usernameOriginalValue = usernameInput.value;
+    function promiseFrameInputValue(name) {
+      return ContentTask.spawn(browser, name, function(inputname) {
+        let iframe = content.document.getElementById("test-iframe");
+        let input = iframe.contentDocument.getElementById(inputname);
+        return input.value;
+      });
+    }
+    let usernameOriginalValue = yield promiseFrameInputValue("form-basic-username");
 
     // Execute the command of the first login menuitem found at the context menu.
+    let passwordChangedPromise = ContentTask.spawn(browser, null, function* () {
+      let frame = content.document.getElementById("test-iframe");
+      let passwordInput = frame.contentDocument.getElementById("form-basic-password");
+      yield ContentTaskUtils.waitForEvent(passwordInput, "input");
+    });
+
     let firstLoginItem = popupMenu.getElementsByClassName("context-login-item")[0];
     firstLoginItem.doCommand();
 
-    yield BrowserTestUtils.waitForEvent(passwordInput, "input", "Password input value changed");
+    yield passwordChangedPromise;
 
     // Find the used login by it's username.
     let login = getLoginFromUsername(firstLoginItem.label);
-
-    Assert.equal(login.password, passwordInput.value, "Password filled and correct.");
+    let passwordValue = yield promiseFrameInputValue("form-basic-password");
+    is(login.password, passwordValue, "Password filled and correct.");
 
-    Assert.equal(usernameOriginalValue,
-                 usernameInput.value,
-                 "Username value was not changed.");
+    let usernameNewValue = yield promiseFrameInputValue("form-basic-username");
+    is(usernameOriginalValue,
+       usernameNewValue,
+       "Username value was not changed.");
 
     let contextMenu = document.getElementById("contentAreaContextMenu");
     contextMenu.hidePopup();
   });
 });
 
 /**
  * Search for a login by it's username.