Bug 1392528 - Ignore autocomplete="off" attribute for Credit Card related fields. r=MattN
authorSean Lee <selee@mozilla.com>
Tue, 05 Sep 2017 16:42:38 +0800
changeset 429400 1c952f67044fbdf55e0a0953d5ba2869e0e940bd
parent 429399 d032ead9b6db3d5332255059ce6555b1e79fec0d
child 429401 776e69666d0c6767b90dc0205eb2ad775ab730f3
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1392528
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1392528 - Ignore autocomplete="off" attribute for Credit Card related fields. r=MattN MozReview-Commit-ID: BMdySEURsr8
browser/extensions/formautofill/FormAutofillHeuristics.jsm
browser/extensions/formautofill/FormAutofillUtils.jsm
browser/extensions/formautofill/test/unit/heuristics/third_party/test_CDW.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_CostCo.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_Macys.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_NewEgg.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_QVC.js
browser/extensions/formautofill/test/unit/heuristics/third_party/test_Staples.js
browser/extensions/formautofill/test/unit/test_isFieldEligibleForAutofill.js
--- a/browser/extensions/formautofill/FormAutofillHeuristics.jsm
+++ b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
@@ -404,17 +404,17 @@ this.FormAutofillHeuristics = {
    *        the elements in this form to be predicted the field info.
    * @param {boolean} allowDuplicates
    *        true to remain any duplicated field details otherwise to remove the
    *        duplicated ones.
    * @returns {Array<Object>}
    *        all field details in the form.
    */
   getFormInfo(form, allowDuplicates = false) {
-    if (form.autocomplete == "off" || form.elements.length <= 0) {
+    if (form.elements.length <= 0) {
       return [];
     }
 
     let fieldScanner = new FieldScanner(form.elements);
     while (!fieldScanner.parsingFinished) {
       let parsedPhoneFields = this._parsePhoneFields(fieldScanner);
       let parsedAddressFields = this._parseAddressFields(fieldScanner);
 
@@ -437,39 +437,49 @@ this.FormAutofillHeuristics = {
   getInfo(element) {
     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") {
+    if (info && info.fieldName && info.fieldName != "on" && info.fieldName != "off") {
       info._reason = "autocomplete";
       return info;
     }
 
     if (!this._prefEnabled) {
       return null;
     }
 
+    let isAutoCompleteOff = element.autocomplete == "off" ||
+      (element.form && element.form.autocomplete == "off");
+
     // "email" type of input is accurate for heuristics to determine its Email
     // field or not. However, "tel" type is used for ZIP code for some web site
     // (e.g. HomeDepot, BestBuy), so "tel" type should be not used for "tel"
     // prediction.
-    if (element.type == "email") {
+    if (element.type == "email" && !isAutoCompleteOff) {
       return {
         fieldName: "email",
         section: "",
         addressType: "",
         contactType: "",
       };
     }
 
-    let regexps = Object.keys(this.RULES);
+    const FIELDNAMES_IGNORING_AUTOCOMPLETE_OFF = [
+      "cc-name",
+      "cc-number",
+      "cc-exp-month",
+      "cc-exp-year",
+      "cc-exp",
+    ];
+    let regexps = isAutoCompleteOff ? FIELDNAMES_IGNORING_AUTOCOMPLETE_OFF : Object.keys(this.RULES);
 
     let labelStrings;
     let getElementStrings = {};
     getElementStrings[Symbol.iterator] = function* () {
       yield element.id;
       yield element.name;
       if (!labelStrings) {
         labelStrings = [];
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -162,20 +162,16 @@ this.FormAutofillUtils = {
   },
 
   autofillFieldSelector(doc) {
     return doc.querySelectorAll("input, select");
   },
 
   ALLOWED_TYPES: ["text", "email", "tel", "number"],
   isFieldEligibleForAutofill(element) {
-    if (element.autocomplete == "off") {
-      return false;
-    }
-
     let tagName = element.tagName;
     if (tagName == "INPUT") {
       // `element.type` can be recognized as `text`, if it's missing or invalid.
       if (!this.ALLOWED_TYPES.includes(element.type)) {
         return false;
       }
     } else if (tagName != "SELECT") {
       return false;
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CDW.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CDW.js
@@ -37,17 +37,17 @@ runHeuristicsTest([
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
 
         // FIXME: bug 1392932 - misdetect ZIP ext string
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
 
         // FIXME: bug 1392940 - the below element can not match to "cc-exp-year" regexp directly.
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
 
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
       ],
       [],
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CostCo.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CostCo.js
@@ -42,26 +42,28 @@ runHeuristicsTest([
       ],
       [],
     ],
   }, {
     fixturePath: "Payment.html",
     expectedResult: [
       [
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
 
         // FIXME: bug 1392940 - the below element can not match to "cc-exp-year" regexp directly.
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
 
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"}, // ac-off
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"}, // ac-off
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"}, // ac-off
       ],
-      [],
+      [
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
+      ],
       [],
       [],
       [
         {"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"},
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Macys.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Macys.js
@@ -20,24 +20,22 @@ runHeuristicsTest([
 /*
 */
       ],
     ],
   }, {
     fixturePath: "Checkout_Payment.html",
     expectedResult: [
       [
- /*
-        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"}, // ac-off
+//      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"}, // ac-off
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"}, // ac-off
         {"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": "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"}, // city
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_NewEgg.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_NewEgg.js
@@ -20,38 +20,38 @@ runHeuristicsTest([
       ],
       [],
     ],
   }, {
     fixturePath: "BillingInfo.html",
     expectedResult: [
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
+        {"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"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // state
         {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
       ],
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
+        {"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-name"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
       ],
     ],
   }, {
     fixturePath: "Login.html",
     expectedResult: [
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_QVC.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_QVC.js
@@ -8,23 +8,23 @@ runHeuristicsTest([
     expectedResult: [
       [
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"}, // ac-off
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-month"}, // select
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-day"}, // select
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-year"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"},
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
 
         // FIXME: bug 1392947 - this is a compound cc-exp field rather than the
         // separated ones below. the birthday fields are misdetected as
         // cc-exp-year and cc-exp-month.
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
 
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
       ],
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
     ],
@@ -33,23 +33,23 @@ runHeuristicsTest([
     expectedResult: [
       [
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"}, // ac-off
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-month"}, // select
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-day"}, // select
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-year"}, // select
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"}, // select
-//      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, ac-off
 
         // FIXME: bug 1392947 - this is a compound cc-exp field rather than the
         // separated ones below. the birthday fields are misdetected as
         // cc-exp-year and cc-exp-month.
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp"}, // select
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
 
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
       ],
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
       ],
     ],
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Staples.js
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Staples.js
@@ -27,25 +27,34 @@ runHeuristicsTest([
         {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
         {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
       ],
     ],
   }, {
     fixturePath: "PaymentBilling.html",
     expectedResult: [
-      [],
+      [
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+
+        // FIXME: bug 1392940 - Since any credit card fields should be
+        // recognized no matter it's autocomplete="off" or not. This field
+        // "cc-exp-month" should be fixed as "cc-exp".
+        {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+//      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
+      ],
     ],
   }, {
     fixturePath: "PaymentBilling_ac_on.html",
     expectedResult: [
       [
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
 
-        // Since this is a custom fixture with force autocomplete="on", we can
-        // fix this later even this should be detected as cc-exp.
+        // FIXME: bug 1392940 - Since any credit card fields should be
+        // recognized no matter it's autocomplete="off" or not. This field
+        // "cc-exp-month" should be fixed as "cc-exp".
         {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
 //      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
       ],
     ],
   },
 ], "../../../fixtures/third_party/Staples/");
 
--- a/browser/extensions/formautofill/test/unit/test_isFieldEligibleForAutofill.js
+++ b/browser/extensions/formautofill/test/unit/test_isFieldEligibleForAutofill.js
@@ -26,32 +26,32 @@ const TESTCASES = [
   {
     document: `<input id="targetElement" type="radio">`,
     fieldId: "targetElement",
     expectedResult: false,
   },
   {
     document: `<input id="targetElement" type="text" autocomplete="off">`,
     fieldId: "targetElement",
-    expectedResult: false,
+    expectedResult: true,
   },
   {
     document: `<input id="targetElement">`,
     fieldId: "targetElement",
     expectedResult: true,
   },
   {
     document: `<input id="targetElement" type="unknown">`,
     fieldId: "targetElement",
     expectedResult: true,
   },
   {
     document: `<select id="targetElement" autocomplete="off"></select>`,
     fieldId: "targetElement",
-    expectedResult: false,
+    expectedResult: true,
   },
   {
     document: `<select id="targetElement"></select>`,
     fieldId: "targetElement",
     expectedResult: true,
   },
   {
     document: `<select id="targetElement" multiple></select>`,