--- a/browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html
+++ b/browser/extensions/formautofill/test/mochitest/test_basic_autocomplete_form.html
@@ -19,20 +19,22 @@ Form autofill test: simple form address
"use strict";
let expectingPopup = null;
let MOCK_STORAGE = [{
organization: "Sesame Street",
"street-address": "123 Sesame Street.",
tel: "1-345-345-3456",
+ country: "US",
}, {
organization: "Mozilla",
"street-address": "331 E. Evelyn Avenue",
tel: "1-650-903-0800",
+ country: "US",
}];
function expectPopup() {
info("expecting a popup");
return new Promise(resolve => {
expectingPopup = resolve;
});
}
@@ -80,17 +82,17 @@ function checkFormFilled(address) {
async function setupAddressStorage() {
await addAddress(MOCK_STORAGE[0]);
await addAddress(MOCK_STORAGE[1]);
}
async function setupFormHistory() {
await updateFormHistory([
{op: "add", fieldname: "tel", value: "1-234-567-890"},
- {op: "add", fieldname: "country", value: "US"},
+ {op: "add", fieldname: "email", value: "foo@mozilla.com"},
]);
}
// Form with history only.
add_task(async function history_only_menu_checking() {
await setupFormHistory();
setInput("#tel", "");
@@ -122,20 +124,20 @@ add_task(async function check_menu_when_
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("#country", "");
+ setInput("#email", "");
doKey("down");
await expectPopup();
- checkMenuEntries(["US"]);
+ checkMenuEntries(["foo@mozilla.com"]);
});
// Autofill the address from dropdown menu.
add_task(async function check_fields_after_form_autofill() {
setInput("#organization", "Moz");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
@@ -161,16 +163,20 @@ registerPopupShownListener(popupShownLis
<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>
<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>
+ <p><label>email: <input id="email" name="email" autocomplete="email" type="text"></label></p>
+ <p><label>country: <select id="country" name="country" autocomplete="country">
+ <option/>
+ <option value="US">United States</option>
+ </label></p>
</form>
</div>
<pre id="test"></pre>
</body>
</html>
--- a/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
+++ b/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
@@ -23,17 +23,20 @@ const TESTCASES = [
},
},
{
description: "Form with autocomplete properties and 1 token",
document: `<form><input id="given-name" autocomplete="given-name">
<input id="family-name" autocomplete="family-name">
<input id="street-addr" autocomplete="street-address">
<input id="city" autocomplete="address-level2">
- <select id="country" autocomplete="country"></select>
+ <select id="country" autocomplete="country">
+ <option/>
+ <option value="US">United States</option>
+ </select>
<input id="email" autocomplete="email">
<input id="tel" autocomplete="tel"></form>`,
fieldDetails: [
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name", "element": {}},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name", "element": {}},
{"section": "", "addressType": "", "contactType": "", "fieldName": "street-address", "element": {}},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2", "element": {}},
{"section": "", "addressType": "", "contactType": "", "fieldName": "country", "element": {}},
@@ -57,17 +60,20 @@ const TESTCASES = [
},
},
{
description: "Form with autocomplete properties and 2 tokens",
document: `<form><input id="given-name" autocomplete="shipping given-name">
<input id="family-name" autocomplete="shipping family-name">
<input id="street-addr" autocomplete="shipping street-address">
<input id="city" autocomplete="shipping address-level2">
- <select id="country" autocomplete="shipping country"></select>
+ <select id="country" autocomplete="shipping country">
+ <option/>
+ <option value="US">United States</option>
+ </select>
<input id='email' autocomplete="shipping email">
<input id="tel" autocomplete="shipping tel"></form>`,
fieldDetails: [
{"section": "", "addressType": "shipping", "contactType": "", "fieldName": "given-name", "element": {}},
{"section": "", "addressType": "shipping", "contactType": "", "fieldName": "family-name", "element": {}},
{"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address", "element": {}},
{"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2", "element": {}},
{"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
@@ -154,54 +160,158 @@ const TESTCASES = [
expectedResult: {
"street-addr": "",
"city": "",
"country": "",
"email": "foo@mozilla.com",
"tel": "1234567",
},
},
+ {
+ description: "Form with autocomplete select elements and matching option values",
+ document: `<form>
+ <select id="country" autocomplete="shipping country">
+ <option value=""></option>
+ <option value="US">United States</option>
+ </select>
+ <select id="state" autocomplete="shipping address-level1">
+ <option value=""></option>
+ <option value="CA">California</option>
+ <option value="WA">Washington</option>
+ </select>
+ </form>`,
+ fieldDetails: [
+ {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
+ {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level1", "element": {}},
+ ],
+ profileData: {
+ "guid": "123",
+ "country": "US",
+ "address-level1": "CA",
+ },
+ expectedResult: {
+ "country": "US",
+ "state": "CA",
+ },
+ },
+ {
+ description: "Form with autocomplete select elements and matching option texts",
+ document: `<form>
+ <select id="country" autocomplete="shipping country">
+ <option value=""></option>
+ <option value="US">United States</option>
+ </select>
+ <select id="state" autocomplete="shipping address-level1">
+ <option value=""></option>
+ <option value="CA">California</option>
+ <option value="WA">Washington</option>
+ </select>
+ </form>`,
+ fieldDetails: [
+ {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
+ {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level1", "element": {}},
+ ],
+ profileData: {
+ "guid": "123",
+ "country": "United States",
+ "address-level1": "California",
+ },
+ expectedResult: {
+ "country": "US",
+ "state": "CA",
+ },
+ },
];
-for (let tc of TESTCASES) {
- (function() {
- let testcase = tc;
- add_task(async function() {
- do_print("Starting testcase: " + testcase.description);
+const TESTCASES_INPUT_UNCHANGED = [
+ {
+ description: "Form with autocomplete select elements; with default and no matching options",
+ document: `<form>
+ <select id="country" autocomplete="shipping country">
+ <option value="US">United States</option>
+ </select>
+ <select id="state" autocomplete="shipping address-level1">
+ <option value=""></option>
+ <option value="CA">California</option>
+ <option value="WA">Washington</option>
+ </select>
+ </form>`,
+ fieldDetails: [
+ {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
+ {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level1", "element": {}},
+ ],
+ profileData: {
+ "guid": "123",
+ "country": "US",
+ "address-level1": "unknown state",
+ },
+ expectedResult: {
+ "country": "US",
+ "state": "",
+ },
+ },
+];
- let doc = MockDocument.createTestDocument("http://localhost:8080/test/",
- testcase.document);
- let form = doc.querySelector("form");
- let handler = new FormAutofillHandler(form);
- let onChangePromises = [];
+function do_test(testcases, testFn) {
+ for (let tc of testcases) {
+ (function() {
+ let testcase = tc;
+ add_task(async function() {
+ do_print("Starting testcase: " + testcase.description);
+
+ let doc = MockDocument.createTestDocument("http://localhost:8080/test/",
+ testcase.document);
+ let form = doc.querySelector("form");
+ let handler = new FormAutofillHandler(form);
+ let promises = [];
- handler.fieldDetails = testcase.fieldDetails;
- handler.fieldDetails.forEach((field, index) => {
- let element = doc.querySelectorAll("input, select")[index];
- field.elementWeakRef = Cu.getWeakReference(element);
- if (element instanceof Ci.nsIDOMHTMLSelectElement) {
- // TODO: Bug 1364823 should remove the condition and handle filling
- // value in <select>
- return;
- }
- if (!testcase.profileData[field.fieldName]) {
- // Avoid waiting for `change` event of a input with a blank value to
- // be filled.
- return;
- }
- onChangePromises.push(new Promise(resolve => {
- element.addEventListener("change", () => {
- let id = element.id;
- Assert.equal(element.value, testcase.expectedResult[id],
- "Check the " + id + " fields were filled with correct data");
- resolve();
- }, {once: true});
- }));
+ handler.fieldDetails = testcase.fieldDetails;
+ handler.fieldDetails.forEach((field, index) => {
+ let element = doc.querySelectorAll("input, select")[index];
+ field.elementWeakRef = Cu.getWeakReference(element);
+ if (!testcase.profileData[field.fieldName]) {
+ // Avoid waiting for `change` event of a input with a blank value to
+ // be filled.
+ return;
+ }
+ promises.push(testFn(testcase, element));
+ });
+
+ handler.autofillFormFields(testcase.profileData);
+ Assert.equal(handler.filledProfileGUID, testcase.profileData.guid,
+ "Check if filledProfileGUID is set correctly");
+ await Promise.all(promises);
});
+ })();
+ }
+}
- handler.autofillFormFields(testcase.profileData);
+do_test(TESTCASES, (testcase, element) => {
+ return new Promise(resolve => {
+ element.addEventListener("change", () => {
+ let id = element.id;
+ Assert.equal(element.value, testcase.expectedResult[id],
+ "Check the " + id + " field was filled with correct data");
+ resolve();
+ }, {once: true});
+ });
+});
- Assert.equal(handler.filledProfileGUID, testcase.profileData.guid,
- "Check if filledProfileGUID is set correctly");
- await Promise.all(onChangePromises);
- });
- })();
-}
+do_test(TESTCASES_INPUT_UNCHANGED, (testcase, element) => {
+ return new Promise((resolve, reject) => {
+ // Make sure no change or input event is fired when no change occurs.
+ let cleaner;
+ let timer = setTimeout(() => {
+ let id = element.id;
+ element.removeEventListener("change", cleaner);
+ element.removeEventListener("input", cleaner);
+ Assert.equal(element.value, testcase.expectedResult[id],
+ "Check no value is changed on the " + id + " field");
+ resolve();
+ }, 1000);
+ cleaner = event => {
+ clearTimeout(timer);
+ reject(`${event.type} event should not fire`);
+ };
+ element.addEventListener("change", cleaner);
+ element.addEventListener("input", cleaner);
+ });
+});