diff --git a/browser/extensions/formautofill/test/browser/head.js b/browser/extensions/formautofill/test/browser/head.js index 9f4cc6dacc6c..8de8060ef9f4 100644 --- a/browser/extensions/formautofill/test/browser/head.js +++ b/browser/extensions/formautofill/test/browser/head.js @@ -590,7 +590,7 @@ add_task(function setup() { OSKeyStoreTestUtils.setup(); }); -registerCleanupFunction(removeAllRecords); registerCleanupFunction(async () => { + await removeAllRecords(); await OSKeyStoreTestUtils.cleanup(); }); diff --git a/browser/extensions/formautofill/test/fixtures/third_party/DirectAsda/Payment.html b/browser/extensions/formautofill/test/fixtures/third_party/DirectAsda/Payment.html new file mode 100644 index 000000000000..5a5b066f509a --- /dev/null +++ b/browser/extensions/formautofill/test/fixtures/third_party/DirectAsda/Payment.html @@ -0,0 +1,90 @@ + + + + + + + + Direct.asda.com + + + +
+
+
+
Please enter a card number +
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + ? + + +
+
+
+
+
+
+
+
+
+
+
+
/ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + diff --git a/browser/extensions/formautofill/test/fixtures/third_party/GlobalDirectAsda/Payment.html b/browser/extensions/formautofill/test/fixtures/third_party/GlobalDirectAsda/Payment.html new file mode 100644 index 000000000000..7eee1b121521 --- /dev/null +++ b/browser/extensions/formautofill/test/fixtures/third_party/GlobalDirectAsda/Payment.html @@ -0,0 +1,154 @@ + + + + + + + + Global.direct.asda.com + + + +
+
+
+
+ + +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
Month
+
+
+ +
+
+
+
Year
+
+
+
+
+
+ +
+ +
+ + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/browser/extensions/formautofill/test/mochitest/creditCard/mochitest.ini b/browser/extensions/formautofill/test/mochitest/creditCard/mochitest.ini index 9b1df537e5d7..d7a7ea2fd884 100644 --- a/browser/extensions/formautofill/test/mochitest/creditCard/mochitest.ini +++ b/browser/extensions/formautofill/test/mochitest/creditCard/mochitest.ini @@ -16,6 +16,8 @@ skip-if = xorigin scheme=https [test_clear_form.html] scheme=https +[test_clear_form_expiry_select_elements.html] +scheme=https [test_creditcard_autocomplete_off.html] scheme=https [test_preview_highlight_with_multiple_cc_number_fields.html] diff --git a/browser/extensions/formautofill/test/mochitest/creditCard/test_clear_form_expiry_select_elements.html b/browser/extensions/formautofill/test/mochitest/creditCard/test_clear_form_expiry_select_elements.html new file mode 100644 index 000000000000..4fc989a36ece --- /dev/null +++ b/browser/extensions/formautofill/test/mochitest/creditCard/test_clear_form_expiry_select_elements.html @@ -0,0 +1,211 @@ + + + + + Test form autofill - clear form button with select elements + + + + + + + +Form autofill test: clear form button with select elements. + + + +

+ +
+ +
+

This is a basic form.

+

+

+

+

+ +

+

+ +

+ +

+

+
+ +
+ +

+
+
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_DirectAsda.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_DirectAsda.js
new file mode 100644
index 000000000000..32116315f9f4
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_DirectAsda.js
@@ -0,0 +1,42 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest(
+  [
+    {
+      fixturePath: "Payment.html",
+      expectedResult: [
+        [
+          [
+            {
+              section: "",
+              addressType: "",
+              contactType: "",
+              fieldName: "cc-number",
+            },
+            {
+              section: "",
+              addressType: "",
+              contactType: "",
+              fieldName: "cc-name"
+            },
+            {
+              section: "",
+              addressType: "",
+              contactType: "",
+              fieldName: "cc-exp-month"
+            },
+            {
+              section: "",
+              addressType: "",
+              contactType: "",
+              fieldName: "cc-exp-year"
+            },
+          ],
+        ],
+      ],
+    },
+  ],
+  "../../../fixtures/third_party/DirectAsda/"
+)
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_GlobalDirectAsda.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_GlobalDirectAsda.js
new file mode 100644
index 000000000000..f6d6cf423c55
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_GlobalDirectAsda.js
@@ -0,0 +1,36 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest(
+  [
+    {
+      fixturePath: "Payment.html",
+      expectedResult: [
+        [
+          [
+            {
+              section: "",
+              addressType: "",
+              contactType: "",
+              fieldName: "cc-number",
+            },
+            {
+              section: "",
+              addressType: "",
+              contactType: "",
+              fieldName: "cc-exp-month"
+            },
+            {
+              section: "",
+              addressType: "",
+              contactType: "",
+              fieldName: "cc-exp-year"
+            },
+          ],
+        ],
+      ],
+    },
+  ],
+  "../../../fixtures/third_party/GlobalDirectAsda/"
+)
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/xpcshell.ini b/browser/extensions/formautofill/test/unit/heuristics/third_party/xpcshell.ini
index 91f4efe1ded4..c4fae041171d 100644
--- a/browser/extensions/formautofill/test/unit/heuristics/third_party/xpcshell.ini
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/xpcshell.ini
@@ -12,9 +12,14 @@ skip-if = (os == "linux") && ccov # bug 1614100
 skip-if = (os == "linux") && ccov # bug 1614100
 [test_CostCo.js]
 skip-if = (os == "linux") && ccov # bug 1614100
+[test_DirectAsda.js]
+skip-if = (os == "linux") && ccov # bug 1614100
+[test_GlobalDirectAsda.js]
+skip-if = (os == "linux") && ccov # bug 1614100
 [test_HomeDepot.js]
 skip-if = (os == "linux") && ccov # bug 1614100
 [test_Lufthansa.js]
+skip-if = (os == "linux") && ccov # bug 1614100
 [test_Macys.js]
 skip-if = (os == "linux") && ccov # bug 1614100
 [test_NewEgg.js]
diff --git a/browser/extensions/formautofill/test/unit/test_autofillFormFields.js b/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
index 0afb68a0d083..63e212a53c26 100644
--- a/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
+++ b/browser/extensions/formautofill/test/unit/test_autofillFormFields.js
@@ -304,7 +304,7 @@ const TESTCASES = [
   },
   {
     description:
-      "Fill credit card fields in a form without a placeholder on expiration month input field",
+      "Fill credit card fields in a form without a placeholder on expiration month and expiration year input fields",
     document: `
@@ -327,6 +327,31 @@ const TESTCASES = [ "cc-exp-year": "25", }, }, + { + description: + "Fill credit card fields in a form with a placeholder on expiration year input field", + document: ` + + + + +
+ `, + focusedInputId: "cc-number", + profileData: { + guid: "123", + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": 6, + "cc-exp-year": 2025, + }, + expectedResult: { + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": "6", + "cc-exp-year": "25", + }, + }, { description: "Form with hidden input and visible input that share the same autocomplete attribute", @@ -462,6 +487,31 @@ const TESTCASES = [ "cc-exp-year2": "", }, }, + { + description: + "Fill credit card fields in a form with placeholders on month and year and these inputs are type=tel", + document: `
+ + + + +
+ `, + focusedInputId: "cardHolder", + profileData: { + guid: "123", + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": 6, + "cc-exp-year": 2025, + }, + expectedResult: { + cardHolder: "test name", + cardNumber: "4111111111111111", + month: "06", + year: "25", + }, + }, ]; const TESTCASES_INPUT_UNCHANGED = [ @@ -753,11 +803,20 @@ function do_test(testcases, testFn) { let decryptHelper = async (cipherText, reauth) => { return OSKeyStore.decrypt(cipherText, false); }; - handler.collectFormFields(); let focusedInput = doc.getElementById(testcase.focusedInputId); - handler.focusedInput = focusedInput; + try { + handler.focusedInput = focusedInput; + } catch (e) { + if (e.message.includes("WeakMap key must be an object")) { + throw new Error( + `Couldn't find the focusedInputId in the current form! Make sure focusedInputId exists in your test form! testcase description:${testcase.description}` + ); + } else { + throw e; + } + } for (let section of handler.sections) { section._decrypt = decryptHelper; diff --git a/browser/extensions/formautofill/test/unit/test_getAdaptedProfiles.js b/browser/extensions/formautofill/test/unit/test_getAdaptedProfiles.js index 58f37aaa5586..eecf8b38b48c 100644 --- a/browser/extensions/formautofill/test/unit/test_getAdaptedProfiles.js +++ b/browser/extensions/formautofill/test/unit/test_getAdaptedProfiles.js @@ -49,6 +49,10 @@ const getCCExpMonthFormatted = () => { return DEFAULT_CREDITCARD_RECORD["cc-exp-month"].toString().padStart(2, "0"); }; +const getCCExpYearFormatted = () => { + return DEFAULT_CREDITCARD_RECORD["cc-exp-year"].toString().substring(2); +}; + const TESTCASES = [ { description: "Address form with street-address", @@ -1076,6 +1080,7 @@ const TESTCASES = [ document: `
+
`, profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)], expectedResult: [ @@ -1084,6 +1089,20 @@ const TESTCASES = [ }), ], }, + { + description: "Use placeholder to adjust cc-exp-year field [yy].", + document: `
+ + + +
`, + profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)], + expectedResult: [ + Object.assign({}, DEFAULT_CREDITCARD_RECORD, { + "cc-exp-year-formatted": getCCExpYearFormatted(), + }), + ], + }, { description: "Test maxlength=2 on numeric fields.", document: `
diff --git a/browser/extensions/formautofill/test/unit/test_getAdaptedProfiles_locales.js b/browser/extensions/formautofill/test/unit/test_getAdaptedProfiles_locales.js index 1a971c83de26..d2428c8ef22e 100644 --- a/browser/extensions/formautofill/test/unit/test_getAdaptedProfiles_locales.js +++ b/browser/extensions/formautofill/test/unit/test_getAdaptedProfiles_locales.js @@ -22,6 +22,10 @@ const DEFAULT_CREDITCARD_RECORD = { "cc-exp": "2025-01", }; +const getCCExpYearFormatted = () => { + return DEFAULT_CREDITCARD_RECORD["cc-exp-year"].toString().substring(2); +}; + const FR_TESTCASES = [ { description: "Use placeholder to adjust cc-exp format [mm/aa].", @@ -89,6 +93,20 @@ const FR_TESTCASES = [ }), ], }, + { + description: "Use placeholder to adjust cc-exp-year field [aa].", + document: ` + + + +
`, + profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)], + expectedResult: [ + Object.assign({}, DEFAULT_CREDITCARD_RECORD, { + "cc-exp-year-formatted": getCCExpYearFormatted(), + }), + ], + }, ]; const DE_TESTCASES = [ @@ -191,6 +209,20 @@ const DE_TESTCASES = [ }), ], }, + { + description: "Use placeholder to adjust cc-exp-year field [jj].", + document: `
+ + + +
`, + profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)], + expectedResult: [ + Object.assign({}, DEFAULT_CREDITCARD_RECORD, { + "cc-exp-year-formatted": getCCExpYearFormatted(), + }), + ], + }, ]; const TESTCASES = [FR_TESTCASES, DE_TESTCASES]; diff --git a/toolkit/components/formautofill/FormAutofillHandler.jsm b/toolkit/components/formautofill/FormAutofillHandler.jsm index b7f95bd92205..054821507c65 100644 --- a/toolkit/components/formautofill/FormAutofillHandler.jsm +++ b/toolkit/components/formautofill/FormAutofillHandler.jsm @@ -422,7 +422,10 @@ class FormAutofillSection { for (let fieldDetail of this.fieldDetails) { let element = fieldDetail.elementWeakRef.get(); - let value = profile[fieldDetail.fieldName] || ""; + let value = + profile[`${fieldDetail.fieldName}-formatted`] || + profile[fieldDetail.fieldName] || + ""; // Skip the field that is null if (!element) { @@ -732,6 +735,12 @@ class FormAutofillSection { option.hasAttribute("selected") ); element.value = selected ? selected.value : element.options[0].value; + element.dispatchEvent( + new element.ownerGlobal.Event("input", { bubbles: true }) + ); + element.dispatchEvent( + new element.ownerGlobal.Event("change", { bubbles: true }) + ); } } @@ -1071,7 +1080,14 @@ class FormAutofillCreditCardSection extends FormAutofillSection { ); } - creditCardExpDateTransformer(profile) { + /** + * Handles credit card expiry date transformation when + * the expiry date exists in a cc-exp field. + * + * @param {object} profile + * @memberof FormAutofillCreditCardSection + */ + creditCardExpiryDateTransformer(profile) { if (!profile["cc-exp"]) { return; } @@ -1145,23 +1161,31 @@ class FormAutofillCreditCardSection extends FormAutofillSection { } } - creditCardExpMonthTransformer(profile) { - if (!profile["cc-exp-month"]) { - return; - } - - let detail = this.getFieldDetailByName("cc-exp-month"); - if (!detail) { - return; - } - - let element = detail.elementWeakRef.get(); - + /** + * Handles credit card expiry date transformation when the expiry date exists in + * the separate cc-exp-month and cc-exp-year fields + * + * @param {object} profile + * @memberof FormAutofillCreditCardSection + */ + creditCardExpMonthAndYearTransformer(profile) { + const getInputElementByField = (field, self) => { + if (!field) { + return null; + } + let detail = self.getFieldDetailByName(field); + if (!detail) { + return null; + } + let element = detail.elementWeakRef.get(); + return element.tagName === "INPUT" ? element : null; + }; + let month = getInputElementByField("cc-exp-month", this); // If the expiration month element is an input, // then we examine any placeholder to see if we should format the expiration month // as a zero padded string in order to autofill correctly. - if (element.tagName === "INPUT") { - let placeholder = element.placeholder; + if (month) { + let placeholder = month.placeholder; // Checks for 'MM' placeholder and converts the month to a two digit string. let result = /(?