Bug 1400760 - [Form Autofill] Don't popup credit card dropdown if only cc-number field is identified and without @autocomplete. r=seanlee draft
authorLuke Chang <lchang@mozilla.com>
Mon, 09 Oct 2017 16:22:37 +0800
changeset 681385 789977243ede2ab1986c67cfb2d8244a36c924cb
parent 681384 ca068118abc506b1a1753b754fa8521fd4f3c57f
child 736129 74d6b46f74a363419df190cd5fcc37b4f1eb3f6a
push id84808
push userbmo:lchang@mozilla.com
push dateTue, 17 Oct 2017 07:30:35 +0000
reviewersseanlee
bugs1400760
milestone58.0a1
Bug 1400760 - [Form Autofill] Don't popup credit card dropdown if only cc-number field is identified and without @autocomplete. r=seanlee MozReview-Commit-ID: JGoRLx2WEBG
browser/extensions/formautofill/FormAutofillHandler.jsm
browser/extensions/formautofill/test/unit/test_collectFormFields.js
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -149,33 +149,56 @@ FormAutofillHandler.prototype = {
 
     if (this.address.fieldDetails.length < FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD) {
       log.debug("Ignoring address related fields since it has only",
                 this.address.fieldDetails.length,
                 "field(s)");
       this.address.fieldDetails = [];
     }
 
-    if (!this.creditCard.fieldDetails.some(i => i.fieldName == "cc-number")) {
-      log.debug("Ignoring credit card related fields since it's without credit card number field");
+    if (!this._isValidCreditCardForm(this.creditCard.fieldDetails)) {
+      log.debug("Invalid credit card form");
       this.creditCard.fieldDetails = [];
     }
+
     let validDetails = Array.of(...(this.address.fieldDetails),
                                 ...(this.creditCard.fieldDetails));
     for (let detail of validDetails) {
       let input = detail.elementWeakRef.get();
       if (!input) {
         continue;
       }
       input.addEventListener("input", this);
     }
 
     return validDetails;
   },
 
+  _isValidCreditCardForm(fieldDetails) {
+    let ccNumberReason = "";
+    let hasCCNumber = false;
+    let hasExpiryDate = false;
+
+    for (let detail of fieldDetails) {
+      switch (detail.fieldName) {
+        case "cc-number":
+          hasCCNumber = true;
+          ccNumberReason = detail._reason;
+          break;
+        case "cc-exp":
+        case "cc-exp-month":
+        case "cc-exp-year":
+          hasExpiryDate = true;
+          break;
+      }
+    }
+
+    return hasCCNumber && (ccNumberReason == "autocomplete" || hasExpiryDate);
+  },
+
   getFieldDetailByName(fieldName) {
     return this.fieldDetails.find(detail => detail.fieldName == fieldName);
   },
 
   getFieldDetailByElement(element) {
     return this.fieldDetails.find(
       detail => detail.elementWeakRef.get() == element
     );
--- a/browser/extensions/formautofill/test/unit/test_collectFormFields.js
+++ b/browser/extensions/formautofill/test/unit/test_collectFormFields.js
@@ -154,29 +154,104 @@ const TESTCASES = [
     validFieldDetails: [
       {"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": "cc-number"},
     ],
   },
   {
-    description: "It's an invalid address and credit form.",
+    description: "An invalid address form due to less than 3 fields.",
     document: `<form>
                <input id="given-name" autocomplete="shipping given-name">
                <input autocomplete="shipping address-level2">
+               </form>`,
+    addressFieldDetails: [],
+    creditCardFieldDetails: [],
+    validFieldDetails: [],
+  },
+  {
+    description: "An invalid credit card form due to omitted cc-number.",
+    document: `<form>
                <input id="cc-name" autocomplete="cc-name">
                <input id="cc-exp-month" autocomplete="cc-exp-month">
                <input id="cc-exp-year" autocomplete="cc-exp-year">
                </form>`,
     addressFieldDetails: [],
     creditCardFieldDetails: [],
     validFieldDetails: [],
   },
   {
+    description: "An invalid credit card form due to non-autocomplete-attr cc-number and omitted cc-exp-*.",
+    document: `<form>
+               <input id="cc-name" autocomplete="cc-name">
+               <input id="cc-number" name="card-number">
+               </form>`,
+    addressFieldDetails: [],
+    creditCardFieldDetails: [],
+    validFieldDetails: [],
+  },
+  {
+    description: "A valid credit card form with autocomplete-attr cc-number only.",
+    document: `<form>
+               <input id="cc-number" autocomplete="cc-number">
+               </form>`,
+    addressFieldDetails: [],
+    creditCardFieldDetails: [
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+    ],
+    validFieldDetails: [
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+    ],
+  },
+  {
+    description: "A valid credit card form with non-autocomplete-attr cc-number and cc-exp.",
+    document: `<form>
+               <input id="cc-number" name="card-number">
+               <input id="cc-exp" autocomplete="cc-exp">
+               </form>`,
+    addressFieldDetails: [],
+    creditCardFieldDetails: [
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp"},
+    ],
+    validFieldDetails: [
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp"},
+    ],
+    ids: [
+      "cc-number",
+      "cc-exp",
+    ],
+  },
+  {
+    description: "A valid credit card form with non-autocomplete-attr cc-number and cc-exp-month/cc-exp-year.",
+    document: `<form>
+               <input id="cc-number" name="card-number">
+               <input id="cc-exp-month" autocomplete="cc-exp-month">
+               <input id="cc-exp-year" autocomplete="cc-exp-year">
+               </form>`,
+    addressFieldDetails: [],
+    creditCardFieldDetails: [
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+    ],
+    validFieldDetails: [
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+      {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+    ],
+    ids: [
+      "cc-number",
+      "cc-exp-month",
+      "cc-exp-year",
+    ],
+  },
+  {
     description: "Three sets of adjacent phone number fields",
     document: `<form>
                  <input id="shippingAC" name="phone" maxlength="3">
                  <input id="shippingPrefix" name="phone" maxlength="3">
                  <input id="shippingSuffix" name="phone" maxlength="4">
                  <input id="shippingTelExt" name="extension">
 
                  <input id="billingAC" name="phone" maxlength="3">