--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -444,20 +444,18 @@ var FormAutofillContent = {
if (!this.savedFieldNames) {
this.log.debug("identifyAutofillFields: savedFieldNames are not known yet");
Services.cpmm.sendAsyncMessage("FormAutofill:InitStorage");
}
let forms = [];
// Collects root forms from inputs.
- for (let field of doc.getElementsByTagName("input")) {
- // We only consider text-like fields for now until we support radio and
- // checkbox buttons in the future.
- if (!field.mozIsTextField(true)) {
+ for (let field of FormAutofillUtils.autofillFieldSelector(doc)) {
+ if (!FormAutofillUtils.isFieldEligibleForAutofill(field)) {
continue;
}
// For now skip consider fields in forms we've already seen before even
// if the specific field wasn't seen before. Ideally whether the field is
// already in the handler's form details would be considered.
if (this.getFormHandler(field)) {
continue;
@@ -486,17 +484,19 @@ var FormAutofillContent = {
this.log.debug("Adding form handler to _formsDetails:", formHandler);
formHandler.fieldDetails.forEach(detail =>
this._markAsAutofillField(detail.elementWeakRef.get())
);
});
},
_markAsAutofillField(field) {
- if (!field) {
+ // Since Form Autofill popup is only for input element, any non-Input
+ // element should be excluded here.
+ if (!field || !(field instanceof Ci.nsIDOMHTMLInputElement)) {
return;
}
formFillController.markAsAutofillField(field);
},
_previewProfile(doc) {
let selectedIndex = ProfileAutocomplete._getSelectedIndex(doc.ownerGlobal);
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -86,17 +86,18 @@ FormAutofillHandler.prototype = {
// 3. the invalid value set
let element = fieldDetail.elementWeakRef.get();
if (!element || element === focusedInput || element.value) {
continue;
}
let value = profile[fieldDetail.fieldName];
- if (value) {
+ // TODO: Bug 1364823 is implemeting the value filling of select element.
+ if (element instanceof Ci.nsIDOMHTMLInputElement && value) {
element.setUserInput(value);
}
}
},
/**
* Populates result to the preview layers with given profile.
*
--- a/browser/extensions/formautofill/FormAutofillHeuristics.jsm
+++ b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
@@ -132,19 +132,17 @@ this.FormAutofillHeuristics = {
result.fieldName = fieldName;
return result;
}
}
return null;
},
getInfo(element, fieldDetails) {
- if (!(element instanceof Ci.nsIDOMHTMLInputElement) ||
- !["text", "email", "tel", "number"].includes(element.type) ||
- element.autocomplete == "off") {
+ if (!FormAutofillUtils.isFieldEligibleForAutofill(element)) {
return null;
}
let info = element.getAutocompleteInfo();
// An input[autocomplete="on"] will not be early return here since it stll
// needs to find the field name.
if (info && info.fieldName && info.fieldName != "on") {
return info;
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -57,16 +57,20 @@ this.FormAutofillUtils = {
let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
return new ConsoleAPI({
maxLogLevelPref: "extensions.formautofill.loglevel",
prefix: logPrefix,
});
});
},
+ autofillFieldSelector(doc) {
+ return doc.querySelectorAll("input, select");
+ },
+
ALLOWED_TYPES: ["text", "email", "tel", "number"],
isFieldEligibleForAutofill(element) {
if (element.autocomplete == "off") {
return false;
}
if (element instanceof Ci.nsIDOMHTMLInputElement) {
// `element.type` can be recognized as `text`, if it's missing or invalid.
--- a/browser/extensions/formautofill/content/FormAutofillFrameScript.js
+++ b/browser/extensions/formautofill/content/FormAutofillFrameScript.js
@@ -10,16 +10,17 @@
/* eslint-env mozilla/frame-script */
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://formautofill/FormAutofillContent.jsm");
+Cu.import("resource://formautofill/FormAutofillUtils.jsm");
/**
* Handles content's interactions for the frame.
*
* NOTE: Declares it by "var" to make it accessible in unit tests.
*/
var FormAutofillFrameScript = {
init() {
@@ -35,17 +36,17 @@ var FormAutofillFrameScript = {
if (!Services.prefs.getBoolPref("extensions.formautofill.addresses.enabled")) {
return;
}
switch (evt.type) {
case "focusin": {
let element = evt.target;
- if (!(element instanceof Ci.nsIDOMHTMLInputElement)) {
+ if (!FormAutofillUtils.isFieldEligibleForAutofill(element)) {
return;
}
FormAutofillContent.identifyAutofillFields(element.ownerDocument);
break;
}
}
},
--- a/browser/extensions/formautofill/test/fixtures/autocomplete_basic.html
+++ b/browser/extensions/formautofill/test/fixtures/autocomplete_basic.html
@@ -20,20 +20,20 @@
</form>
<form id="formB">
<p><label>Organization: <input type="text" /></label></p>
<p><label><input type="text" id="B_address-line1" /></label></p>
<p><label><input type="text" name="address-line2" /></label></p>
<p><label><input type="text" id="B_address-line3" name="address-line3" /></label></p>
<p><label>City: <input type="text" name="address-level2" /></label></p>
- <p><label>State: <input type="text" id="B_address-level1" /></label></p>
+ <p><label>State: <select id="B_address-level1" ></select></label></p>
<p><input type="text" id="B_postal-code" name="postal-code" /></p>
- <p><label>Country: <input type="text" id="B_country" name="country" /></label></p>
- <p><label>Telephone: <input type="text" id="B_tel" name="tel" /></label></p>
+ <p><label>Country: <select multiple id="B_country" name="country" ></select></label></p>
+ <p><label>Telephone: <input id="B_tel" name="tel" /></label></p>
<p><label>Email: <input type="text" id="B_email" name="email" /></label></p>
<p><input type="submit" /></p>
<p><button type="reset">Reset</button></p>
</form>
</body>
</html>
--- a/browser/extensions/formautofill/test/unit/head.js
+++ b/browser/extensions/formautofill/test/unit/head.js
@@ -77,33 +77,30 @@ function getTempFile(leafName) {
});
return file;
}
function runHeuristicsTest(patterns, fixturePathPrefix) {
Cu.import("resource://gre/modules/FormLikeFactory.jsm");
Cu.import("resource://formautofill/FormAutofillHeuristics.jsm");
+ Cu.import("resource://formautofill/FormAutofillUtils.jsm");
- // TODO: "select" and "textarea" will be included eventually.
- const QUERY_STRING = ["input"];
patterns.forEach(testPattern => {
add_task(function* () {
do_print("Starting test fixture: " + testPattern.fixturePath);
let file = do_get_file(fixturePathPrefix + testPattern.fixturePath);
let doc = MockDocument.createTestDocumentFromFile("http://localhost:8080/test/", file);
let forms = [];
- for (let query of QUERY_STRING) {
- for (let field of doc.querySelectorAll(query)) {
- let formLike = FormLikeFactory.createFromField(field);
- if (!forms.some(form => form.rootElement === formLike.rootElement)) {
- forms.push(formLike);
- }
+ for (let field of FormAutofillUtils.autofillFieldSelector(doc)) {
+ let formLike = FormLikeFactory.createFromField(field);
+ if (!forms.some(form => form.rootElement === formLike.rootElement)) {
+ forms.push(formLike);
}
}
Assert.equal(forms.length, testPattern.expectedResult.length, "Expected form count.");
forms.forEach((form, formIndex) => {
let formInfo = FormAutofillHeuristics.getFormInfo(form);
do_print("FieldName Prediction Results: " + formInfo.map(i => i.fieldName));
@@ -116,15 +113,17 @@ function runHeuristicsTest(patterns, fix
});
});
});
}
add_task(function* head_initialize() {
Services.prefs.setBoolPref("extensions.formautofill.experimental", true);
Services.prefs.setBoolPref("extensions.formautofill.heuristics.enabled", true);
+ Services.prefs.setBoolPref("dom.forms.autocomplete.experimental", true);
// Clean up after every test.
do_register_cleanup(function head_cleanup() {
Services.prefs.clearUserPref("extensions.formautofill.experimental");
Services.prefs.clearUserPref("extensions.formautofill.heuristics.enabled");
+ Services.prefs.clearUserPref("dom.forms.autocomplete.experimental");
});
});
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_BestBuy.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_BestBuy.js
@@ -7,17 +7,17 @@ runHeuristicsTest([
fixturePath: "Checkout_ShippingAddress.html",
expectedResult: [
[], // Search form
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO:select,state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
],
[ // Sign up
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
],
[ // unknown
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
@@ -30,17 +30,17 @@ runHeuristicsTest([
[ // Sign up
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
],
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO:select,state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
],
[
// unknown
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
],
],
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CDW.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CDW.js
@@ -8,34 +8,34 @@ runHeuristicsTest([
expectedResult: [
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select,state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
],
[],
],
}, {
fixturePath: "Checkout_BillingPaymentInfo.html",
expectedResult: [
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select,state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
],
[
/* TODO: Credit Card
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CostCo.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CostCo.js
@@ -8,35 +8,35 @@ runHeuristicsTest([
expectedResult: [
[],
[],
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "additional-name"}, // middle-name initial
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select,country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select,state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
],
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "additional-name"}, // middle-name initial
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select,country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select,state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
],
[],
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
],
@@ -58,35 +58,35 @@ runHeuristicsTest([
[],
[],
[],
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "additional-name"}, // middle-name initial
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select, country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
],
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "additional-name"}, // middle-name initial
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select, country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
],
[],
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
],
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_HomeDepot.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_HomeDepot.js
@@ -8,16 +8,17 @@ runHeuristicsTest([
expectedResult: [
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "billing", "contactType": "", "fieldName": "street-address"}, // <select>
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
],
],
}, {
fixturePath: "SignIn.html",
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Macys.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Macys.js
@@ -6,18 +6,18 @@ runHeuristicsTest([
{
fixturePath: "Checkout_ShippingAddress.html",
expectedResult: [
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
- {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // select
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
],
[
/*
*/
],
],
@@ -32,18 +32,18 @@ runHeuristicsTest([
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"}, // ac-off
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"}, // ac-off
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"}, // ac-off
*/
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
- {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // select
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
],
[],
],
}, {
fixturePath: "SignIn.html",
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_NewEgg.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_NewEgg.js
@@ -4,21 +4,21 @@
runHeuristicsTest([
{
fixturePath: "ShippingInfo.html",
expectedResult: [
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select, country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
],
[],
],
}, {
fixturePath: "BillingInfo.html",
@@ -29,21 +29,21 @@ runHeuristicsTest([
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
*/
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select, country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"}, // TODO
// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // TODO
// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"}, // TODO
// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"}, // TODO
],
[],
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_OfficeDepot.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_OfficeDepot.js
@@ -9,17 +9,17 @@ runHeuristicsTest([
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
// TODO: telphone relative fields should be fixed:
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-area-code"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-local-prefix"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-local-suffix"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
@@ -35,17 +35,17 @@ runHeuristicsTest([
// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
// TODO: telphone relative fields should be fixed:
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-area-code"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-local-prefix"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-local-suffix"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Sears.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Sears.js
@@ -13,17 +13,17 @@ runHeuristicsTest([
],
[ // check-out, ac-off
/*
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
*/
],
[ // ac-off
/*
@@ -59,18 +59,18 @@ runHeuristicsTest([
// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
],
[ // Another billing address
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
- {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
],
[ // check out
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: Wrong. This is for Driver's license.
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Walmart.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Walmart.js
@@ -26,18 +26,18 @@ runHeuristicsTest([
fixturePath: "Payment.html",
expectedResult: [
[
],
[
{"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "cc-number"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+ {"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+ {"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
{"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "tel"},
],
],
}, {
fixturePath: "Shipping.html",
expectedResult: [
[
@@ -47,15 +47,15 @@ runHeuristicsTest([
],
[
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
-// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
],
],
},
], "../../../fixtures/third_party/Walmart/");
--- a/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
+++ b/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
@@ -5,17 +5,17 @@
"use strict";
Cu.import("resource://formautofill/FormAutofillHandler.jsm");
const TESTCASES = [
{
description: "Form without autocomplete property",
document: `<form><input id="given-name"><input id="family-name">
- <input id="street-addr"><input id="city"><input id="country">
+ <input id="street-addr"><input id="city"><select id="country"></select>
<input id='email'><input id="tel"></form>`,
fieldDetails: [],
profileData: {},
expectedResult: {
"street-addr": "",
"city": "",
"country": "",
"email": "",
@@ -23,17 +23,17 @@ 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">
- <input id="country" autocomplete="country">
+ <select id="country" autocomplete="country"></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 +57,17 @@ 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">
- <input id="country" autocomplete="shipping country">
+ <select id="country" autocomplete="shipping country"></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": {}},
@@ -170,18 +170,23 @@ for (let tc of TESTCASES) {
let doc = MockDocument.createTestDocument("http://localhost:8080/test/",
testcase.document);
let form = doc.querySelector("form");
let handler = new FormAutofillHandler(form);
let onChangePromises = [];
handler.fieldDetails = testcase.fieldDetails;
handler.fieldDetails.forEach((field, index) => {
- let element = doc.querySelectorAll("input")[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;
--- a/browser/extensions/formautofill/test/unit/test_collectFormFields.js
+++ b/browser/extensions/formautofill/test/unit/test_collectFormFields.js
@@ -5,17 +5,17 @@
"use strict";
Cu.import("resource://formautofill/FormAutofillHandler.jsm");
const TESTCASES = [
{
description: "Form without autocomplete property",
document: `<form><input id="given-name"><input id="family-name">
- <input id="street-addr"><input id="city"><input id="country">
+ <input id="street-addr"><input id="city"><select id="country"></select>
<input id='email'><input id="tel"></form>`,
fieldDetails: [
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
@@ -24,17 +24,17 @@ const TESTCASES = [
ids: ["given-name", "family-name", "street-addr", "city", "country", "email", "tel"],
},
{
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">
- <input id="country" autocomplete="country">
+ <select id="country" autocomplete="country"></select>
<input id="email" autocomplete="email">
<input id="tel" autocomplete="tel"></form>`,
fieldDetails: [
{"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
@@ -61,18 +61,18 @@ const TESTCASES = [
{"section": "", "addressType": "shipping", "contactType": "", "fieldName": "tel"},
],
},
{
description: "Form with autocomplete properties and profile is partly matched",
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">
- <input id="country" autocomplete="shipping country">
+ <input autocomplete="shipping address-level2">
+ <select autocomplete="shipping country"></select>
<input id='email' autocomplete="shipping email">
<input id="tel" autocomplete="shipping tel"></form>`,
fieldDetails: [
{"section": "", "addressType": "shipping", "contactType": "", "fieldName": "given-name"},
{"section": "", "addressType": "shipping", "contactType": "", "fieldName": "family-name"},
{"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address"},
{"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2"},
{"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country"},
@@ -92,17 +92,17 @@ for (let tc of TESTCASES) {
testcase.document);
let form = doc.querySelector("form");
testcase.fieldDetails.forEach((detail, index) => {
let elementRef;
if (testcase.ids && testcase.ids[index]) {
elementRef = doc.getElementById(testcase.ids[index]);
} else {
- elementRef = doc.querySelector("input[autocomplete*='" + detail.fieldName + "']");
+ elementRef = doc.querySelector("*[autocomplete*='" + detail.fieldName + "']");
}
detail.elementWeakRef = Cu.getWeakReference(elementRef);
});
let handler = new FormAutofillHandler(form);
handler.collectFormFields();
handler.fieldDetails.forEach((detail, index) => {
--- a/browser/extensions/formautofill/test/unit/test_getFormInputDetails.js
+++ b/browser/extensions/formautofill/test/unit/test_getFormInputDetails.js
@@ -3,50 +3,50 @@
Cu.import("resource://formautofill/FormAutofillContent.jsm");
const TESTCASES = [
{
description: "Form containing 5 fields with autocomplete attribute.",
document: `<form id="form1">
<input id="street-addr" autocomplete="street-address">
<input id="city" autocomplete="address-level2">
- <input id="country" autocomplete="country">
+ <select id="country" autocomplete="country"></select>
<input id="email" autocomplete="email">
<input id="tel" autocomplete="tel">
</form>`,
- targetInput: ["street-addr", "country"],
+ targetInput: ["street-addr", "email"],
expectedResult: [{
input: {"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
formId: "form1",
form: [
{"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
],
},
{
- input: {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
+ input: {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
formId: "form1",
form: [
{"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
{"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
],
}],
},
{
description: "2 forms that are able to be auto filled",
document: `<form id="form2">
<input id="home-addr" autocomplete="street-address">
<input id="city" autocomplete="address-level2">
- <input id="country" autocomplete="country">
+ <select id="country" autocomplete="country"></select>
</form>
<form id="form3">
<input id="office-addr" autocomplete="street-address">
<input id="email" autocomplete="email">
<input id="tel" autocomplete="tel">
</form>`,
targetInput: ["home-addr", "office-addr"],
expectedResult: [{
@@ -93,19 +93,19 @@ TESTCASES.forEach(testcase => {
// `getInputDetails` contains the same input element.
testcase.expectedResult[i].input.elementWeakRef = Cu.getWeakReference(input);
inputDetailAssertion(FormAutofillContent.getInputDetails(input),
testcase.expectedResult[i].input);
let formDetails = testcase.expectedResult[i].form;
for (let formDetail of formDetails) {
- // Compose a query string to get the exact reference of the input
- // element, e.g. #form1 > input[autocomplete="street-address"]
- let queryString = "#" + testcase.expectedResult[i].formId + " > input[autocomplete=" + formDetail.fieldName + "]";
+ // Compose a query string to get the exact reference of <input>/<select>
+ // element, e.g. #form1 > *[autocomplete="street-address"]
+ let queryString = "#" + testcase.expectedResult[i].formId + " > *[autocomplete=" + formDetail.fieldName + "]";
formDetail.elementWeakRef = Cu.getWeakReference(doc.querySelector(queryString));
}
FormAutofillContent.getFormDetails(input).forEach((detail, index) => {
inputDetailAssertion(detail, formDetails[index]);
});
}
});
--- a/browser/extensions/formautofill/test/unit/test_getInfo.js
+++ b/browser/extensions/formautofill/test/unit/test_getInfo.js
@@ -64,16 +64,43 @@ const TESTCASES = [
expectedReturnValue: {
fieldName: "email",
section: "",
addressType: "",
contactType: "",
},
},
{
+ description: "Select element in a label element",
+ document: `<form>
+ <label> State
+ <select id="targetElement"></select>
+ </label>
+ </form>`,
+ elementId: "targetElement",
+ expectedReturnValue: {
+ fieldName: "address-level1",
+ section: "",
+ addressType: "",
+ contactType: "",
+ },
+ },
+ {
+ description: "A select element without a form wrapped",
+ document: `<label for="targetElement">State</label>
+ <select id="targetElement"></select>`,
+ elementId: "targetElement",
+ expectedReturnValue: {
+ fieldName: "address-level1",
+ section: "",
+ addressType: "",
+ contactType: "",
+ },
+ },
+ {
description: "2 address line inputs",
document: `<label for="targetElement">street</label>
<input id="targetElement" type="text">`,
elementId: "targetElement",
fieldDetails: [{fieldName: "address-line1"}],
expectedReturnValue: {
fieldName: "address-line2",
section: "",