Bug 1364818 - [Form Autofill] popup won't apply to an auto-focused input until it's refocused. r=MattN
MozReview-Commit-ID: H3CZEFzAJm6
--- a/browser/extensions/formautofill/content/FormAutofillFrameScript.js
+++ b/browser/extensions/formautofill/content/FormAutofillFrameScript.js
@@ -36,20 +36,30 @@ var FormAutofillFrameScript = {
if (!Services.prefs.getBoolPref("extensions.formautofill.addresses.enabled")) {
return;
}
switch (evt.type) {
case "focusin": {
let element = evt.target;
+ let doc = element.ownerDocument;
+
if (!FormAutofillUtils.isFieldEligibleForAutofill(element)) {
return;
}
- FormAutofillContent.identifyAutofillFields(element.ownerDocument);
+
+ let doIdentifyAutofillFields =
+ () => setTimeout(() => FormAutofillContent.identifyAutofillFields(doc));
+
+ if (doc.readyState === "loading") {
+ doc.addEventListener("DOMContentLoaded", doIdentifyAutofillFields, {once: true});
+ } else {
+ doIdentifyAutofillFields();
+ }
break;
}
}
},
receiveMessage(message) {
if (!Services.prefs.getBoolPref("extensions.formautofill.addresses.enabled")) {
return;
--- a/browser/extensions/formautofill/test/mochitest/formautofill_common.js
+++ b/browser/extensions/formautofill/test/mochitest/formautofill_common.js
@@ -5,16 +5,24 @@
"use strict";
let formFillChromeScript;
function setInput(selector, value) {
let input = document.querySelector("input" + selector);
input.value = value;
input.focus();
+
+ // "identifyAutofillFields" is invoked asynchronously in "focusin" event. We
+ // should make sure fields are ready for popup before doing tests.
+ //
+ // TODO: "setTimeout" is used here temporarily because there's no event to
+ // notify us of the state of "identifyAutofillFields" for now. We should
+ // figure out a better way after the heuristics land.
+ return new Promise(resolve => setTimeout(resolve));
}
function checkMenuEntries(expectedValues) {
let actualValues = getMenuEntries();
is(actualValues.length, expectedValues.length, " Checking length of expected menu");
for (let i = 0; i < expectedValues.length; i++) {
is(actualValues[i], expectedValues[i], " Checking menu entry #" + i);
--- a/browser/extensions/formautofill/test/mochitest/formautofill_parent_utils.js
+++ b/browser/extensions/formautofill/test/mochitest/formautofill_parent_utils.js
@@ -38,17 +38,16 @@ var ParentUtils = {
},
cleanup() {
Services.obs.removeObserver(this, "formautofill-storage-changed");
this.cleanUpAddress();
},
};
-ParentUtils.cleanUpAddress();
Services.obs.addObserver(ParentUtils, "formautofill-storage-changed");
addMessageListener("FormAutofillTest:AddAddress", (msg) => {
ParentUtils.updateAddress("add", "FormAutofill:SaveAddress", msg, "FormAutofillTest:AddressAdded");
});
addMessageListener("FormAutofillTest:RemoveAddress", (msg) => {
ParentUtils.updateAddress("remove", "FormAutofill:RemoveAddress", msg, "FormAutofillTest:AddressRemoved");
--- a/browser/extensions/formautofill/test/mochitest/mochitest.ini
+++ b/browser/extensions/formautofill/test/mochitest/mochitest.ini
@@ -1,9 +1,9 @@
[DEFAULT]
support-files =
../../../../../toolkit/components/satchel/test/satchel_common.js
../../../../../toolkit/components/satchel/test/parent_utils.js
formautofill_common.js
formautofill_parent_utils.js
+[test_autofocus_form.html]
[test_basic_autocomplete_form.html]
-
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/test/mochitest/test_autofocus_form.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test basic autofill</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+ <script type="text/javascript" src="formautofill_common.js"></script>
+ <script type="text/javascript" src="satchel_common.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+Form autofill test: autocomplete on an autofocus form
+
+<script>
+/* import-globals-from ../../../../../testing/mochitest/tests/SimpleTest/SpawnTask.js */
+/* import-globals-from ../../../../../toolkit/components/satchel/test/satchel_common.js */
+/* import-globals-from formautofill_common.js */
+
+"use strict";
+
+let expectingPopup = null;
+let MOCK_STORAGE = [{
+ organization: "Sesame Street",
+ "street-address": "123 Sesame Street.",
+ tel: "1-345-345-3456",
+}, {
+ organization: "Mozilla",
+ "street-address": "331 E. Evelyn Avenue",
+ tel: "1-650-903-0800",
+}];
+
+function expectPopup() {
+ info("expecting a popup");
+ return new Promise(resolve => {
+ expectingPopup = resolve;
+ });
+}
+
+function popupShownListener() {
+ info("popup shown for test ");
+ if (expectingPopup) {
+ expectingPopup();
+ expectingPopup = null;
+ }
+}
+
+async function setupAddressStorage() {
+ await addAddress(MOCK_STORAGE[0]);
+ await addAddress(MOCK_STORAGE[1]);
+}
+
+add_task(async function check_autocomplete_on_autofocus_field() {
+ await setupAddressStorage();
+ doKey("down");
+ await expectPopup();
+ checkMenuEntries(MOCK_STORAGE.map(address =>
+ JSON.stringify({primary: address.organization, secondary: address["street-address"]})
+ ));
+});
+
+registerPopupShownListener(popupShownListener);
+
+</script>
+
+<p id="display"></p>
+
+<div id="content">
+
+ <form id="form1">
+ <p>This is a basic form.</p>
+ <p><label>organization: <input id="organization" name="organization" autocomplete="organization" type="text"></label></p>
+ <script>
+ // Focuses the input before DOMContentLoaded
+ document.getElementById("organization").focus();
+ </script>
+ <p><label>streetAddress: <input id="street-address" name="street-address" autocomplete="street-address" type="text"></label></p>
+ <p><label>tel: <input id="tel" name="tel" autocomplete="tel" type="text"></label></p>
+ <p><label>country: <input id="country" name="country" autocomplete="country" type="text"></label></p>
+ </form>
+
+</div>
+
+<pre id="test"></pre>
+</body>
+</html>
--- a/browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html
+++ b/browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html
@@ -90,71 +90,71 @@ async function setupFormHistory() {
{op: "add", fieldname: "email", value: "foo@mozilla.com"},
]);
}
// Form with history only.
add_task(async function history_only_menu_checking() {
await setupFormHistory();
- setInput("#tel", "");
+ await setInput("#tel", "");
doKey("down");
await expectPopup();
checkMenuEntries(["1-234-567-890"]);
});
// Form with both history and address storage.
add_task(async function check_menu_when_both_existed() {
await setupAddressStorage();
- setInput("#organization", "");
+ await setInput("#organization", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address.organization, secondary: address["street-address"]})
));
- setInput("#street-address", "");
+ await setInput("#street-address", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address["street-address"], secondary: address.organization})
));
- setInput("#tel", "");
+ await setInput("#tel", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address.tel, secondary: address["street-address"]})
));
});
// Display history search result if no matched data in addresses.
add_task(async function check_fallback_for_mismatched_field() {
- setInput("#email", "");
+ await setInput("#email", "");
doKey("down");
await expectPopup();
checkMenuEntries(["foo@mozilla.com"]);
});
// Autofill the address from dropdown menu.
add_task(async function check_fields_after_form_autofill() {
- setInput("#organization", "Moz");
+ await setInput("#organization", "Moz");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address.organization, secondary: address["street-address"]})
).slice(1));
doKey("down");
await checkFormFilled(MOCK_STORAGE[1]);
});
// Fallback to history search after autofill address.
add_task(async function check_fallback_after_form_autofill() {
- setInput("#tel", "");
+ await setInput("#tel", "");
doKey("down");
await expectPopup();
checkMenuEntries(["1-234-567-890"]);
});
registerPopupShownListener(popupShownListener);
</script>