Bug 1278158 - Allowing filling login forms with an inputElement but without loginFormForFill. r=MattN a=gchang
authorSaad Quadri <saad@saadquadri.com>
Wed, 27 Jul 2016 13:19:53 -0700
changeset 342054 b76912ba6b66e7e34117d909d55cf07c5afdae1b
parent 342053 f430f9a12c98a00bfb0edce37947614e0a2b83cc
child 342055 01e60d85a78c0266d2bfbde530f91a2c6c54fecc
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN, gchang
bugs1278158
milestone49.0a2
Bug 1278158 - Allowing filling login forms with an inputElement but without loginFormForFill. r=MattN a=gchang MozReview-Commit-ID: 2aZCvMpH1eH
toolkit/components/passwordmgr/LoginManagerContent.jsm
toolkit/components/passwordmgr/test/browser/browser.ini
toolkit/components/passwordmgr/test/browser/browser_context_menu.js
toolkit/components/passwordmgr/test/browser/browser_context_menu_iframe.js
toolkit/components/passwordmgr/test/browser/form_basic_iframe.html
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -465,17 +465,17 @@ var LoginManagerContent = {
    *          recipes:
    *            Fill recipes transmitted together with the original message.
    *          inputElement:
    *            Optional input password element from the form we want to fill.
    *        }
    */
   fillForm({ topDocument, loginFormOrigin, loginsFound, recipes, inputElement }) {
     let topState = this.stateForDocument(topDocument);
-    if (!topState.loginFormForFill) {
+    if (!inputElement && !topState.loginFormForFill) {
       log("fillForm: There is no login form anymore. The form may have been",
           "removed or the document may have changed.");
       return;
     }
     if (LoginUtils._getPasswordOrigin(topDocument.documentURI) != loginFormOrigin) {
       if (!inputElement ||
           LoginUtils._getPasswordOrigin(inputElement.ownerDocument.documentURI) != loginFormOrigin) {
         log("fillForm: The requested origin doesn't match the one form the",
--- a/toolkit/components/passwordmgr/test/browser/browser.ini
+++ b/toolkit/components/passwordmgr/test/browser/browser.ini
@@ -1,13 +1,14 @@
 [DEFAULT]
 support-files =
   ../formsubmit.sjs
   authenticate.sjs
   form_basic.html
+  form_basic_iframe.html
   formless_basic.html
   form_same_origin_action.html
   form_cross_origin_insecure_action.html
   form_cross_origin_secure_action.html
   head.js
   insecure_test.html
   insecure_test_subframe.html
   multiple_forms.html
@@ -42,17 +43,18 @@ support-files =
 [browser_hasInsecureLoginForms.js]
 [browser_hasInsecureLoginForms_streamConverter.js]
 [browser_insecurePasswordWarning.js]
 [browser_notifications.js]
 [browser_notifications_2.js]
 [browser_passwordmgr_editing.js]
 skip-if = os == "linux"
 [browser_context_menu.js]
-subsuite = clipboard
+skip-if = e10s
+[browser_context_menu_iframe.js]
 skip-if = e10s
 [browser_passwordmgr_contextmenu.js]
 subsuite = clipboard
 [browser_passwordmgr_fields.js]
 [browser_passwordmgr_observers.js]
 [browser_passwordmgr_sort.js]
 [browser_passwordmgr_switchtab.js]
 [browser_passwordmgrdlg.js]
--- a/toolkit/components/passwordmgr/test/browser/browser_context_menu.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_context_menu.js
@@ -225,75 +225,16 @@ add_task(function* test_context_menu_use
         }
         contextMenu.hidePopup();
       }
     }
   });
 });
 
 /**
- * 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 + MULTIPLE_FORMS_PAGE_PATH,
-  }, function* (browser) {
-    let iframe = browser.contentWindow.document.getElementById("test-iframe");
-    let passwordInput = iframe.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);
-    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;
-
-    // Execute the command of the first login menuitem found at the context menu.
-    let firstLoginItem = popupMenu.getElementsByClassName("context-login-item")[0];
-    firstLoginItem.doCommand();
-
-    yield BrowserTestUtils.waitForEvent(passwordInput, "input", "Password input value changed");
-
-    // Find the used login by it's username.
-    let login = getLoginFromUsername(firstLoginItem.label);
-
-    Assert.equal(login.password, passwordInput.value, "Password filled and correct.");
-
-    Assert.equal(usernameOriginalValue,
-                 usernameInput.value,
-                 "Username value was not changed.");
-
-    let contextMenu = document.getElementById("contentAreaContextMenu");
-    contextMenu.hidePopup();
-  });
-});
-
-/**
  * Synthesize mouse clicks to open the password manager context menu popup
  * for a target password input element.
  *
  * assertCallback should return true if we should continue or else false.
  */
 function* openPasswordContextMenu(browser, passwordInput, assertCallback = null) {
   // Synthesize a right mouse click over the password input element.
   let contextMenuShownPromise = BrowserTestUtils.waitForEvent(window, "popupshown");
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/browser/browser_context_menu_iframe.js
@@ -0,0 +1,136 @@
+/*
+ * Test the password manager context menu.
+ */
+
+"use strict";
+
+const TEST_HOSTNAME = "https://example.com";
+
+// Test with a page that only has a form within an iframe, not in the top-level document
+const IFRAME_PAGE_PATH = "/browser/toolkit/components/passwordmgr/test/browser/form_basic_iframe.html";
+
+/**
+ * Initialize logins needed for the tests and disable autofill
+ * for login forms for easier testing of manual fill.
+ */
+add_task(function* test_initialize() {
+  Services.prefs.setBoolPref("signon.autofillForms", false);
+  registerCleanupFunction(() => {
+    Services.prefs.clearUserPref("signon.autofillForms");
+    Services.prefs.clearUserPref("signon.schemeUpgrades");
+  });
+  for (let login of loginList()) {
+    Services.logins.addLogin(login);
+  }
+});
+
+/**
+ * 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");
+
+    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);
+    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;
+
+    // Execute the command of the first login menuitem found at the context menu.
+    let firstLoginItem = popupMenu.getElementsByClassName("context-login-item")[0];
+    firstLoginItem.doCommand();
+
+    yield BrowserTestUtils.waitForEvent(passwordInput, "input", "Password input value changed");
+
+    // Find the used login by it's username.
+    let login = getLoginFromUsername(firstLoginItem.label);
+
+    Assert.equal(login.password, passwordInput.value, "Password filled and correct.");
+
+    Assert.equal(usernameOriginalValue,
+                 usernameInput.value,
+                 "Username value was not changed.");
+
+    let contextMenu = document.getElementById("contentAreaContextMenu");
+    contextMenu.hidePopup();
+  });
+});
+
+/**
+ * Search for a login by it's username.
+ *
+ * Only unique login/hostname combinations should be used at this test.
+ */
+function getLoginFromUsername(username) {
+  return loginList().find(login => login.username == username);
+}
+
+/**
+ * List of logins used for the test.
+ *
+ * We should only use unique usernames in this test,
+ * because we need to search logins by username. There is one duplicate u+p combo
+ * in order to test de-duping in the menu.
+ */
+function loginList() {
+  return [
+    LoginTestUtils.testData.formLogin({
+      hostname: "https://example.com",
+      formSubmitURL: "https://example.com",
+      username: "username",
+      password: "password",
+    }),
+    // Same as above but HTTP in order to test de-duping.
+    LoginTestUtils.testData.formLogin({
+      hostname: "http://example.com",
+      formSubmitURL: "http://example.com",
+      username: "username",
+      password: "password",
+    }),
+    LoginTestUtils.testData.formLogin({
+      hostname: "http://example.com",
+      formSubmitURL: "http://example.com",
+      username: "username1",
+      password: "password1",
+    }),
+    LoginTestUtils.testData.formLogin({
+      hostname: "https://example.com",
+      formSubmitURL: "https://example.com",
+      username: "username2",
+      password: "password2",
+    }),
+    LoginTestUtils.testData.formLogin({
+      hostname: "http://example.org",
+      formSubmitURL: "http://example.org",
+      username: "username-cross-origin",
+      password: "password-cross-origin",
+    }),
+  ];
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/browser/form_basic_iframe.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+</head>
+
+<body>
+    <!-- Form in an iframe -->
+    <iframe src="https://example.org/browser/toolkit/components/passwordmgr/test/browser/form_basic.html" id="test-iframe"></iframe>
+</body>
+
+</html>