From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../test/unit/test_autofillFormFields.js | 1078 ++++++++++++++++++++ 1 file changed, 1078 insertions(+) create mode 100644 browser/extensions/formautofill/test/unit/test_autofillFormFields.js (limited to 'browser/extensions/formautofill/test/unit/test_autofillFormFields.js') diff --git a/browser/extensions/formautofill/test/unit/test_autofillFormFields.js b/browser/extensions/formautofill/test/unit/test_autofillFormFields.js new file mode 100644 index 0000000000..70de21cfe5 --- /dev/null +++ b/browser/extensions/formautofill/test/unit/test_autofillFormFields.js @@ -0,0 +1,1078 @@ +/* + * Test for form auto fill content helper fill all inputs function. + */ +/* eslint-disable mozilla/no-arbitrary-setTimeout */ + +"use strict"; + +const { setTimeout, clearTimeout } = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" +); +const { OSKeyStore } = ChromeUtils.importESModule( + "resource://gre/modules/OSKeyStore.sys.mjs" +); + +const TESTCASES = [ + { + description: "Form without autocomplete property", + document: `
+ +
`, + focusedInputId: "given-name", + profileData: {}, + expectedResult: { + "street-addr": "", + city: "", + country: "", + email: "", + tel: "", + }, + }, + { + description: "Form with autocomplete properties and 1 token", + document: `
+ + + + + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + "street-address": "2 Harrison St line2", + "-moz-street-address-one-line": "2 Harrison St line2", + "address-level2": "San Francisco", + country: "US", + email: "foo@mozilla.com", + tel: "1234567", + }, + expectedResult: { + "street-addr": "2 Harrison St line2", + city: "San Francisco", + country: "US", + email: "foo@mozilla.com", + tel: "1234567", + }, + }, + { + description: "Form with autocomplete properties and 2 tokens", + document: `
+ + + + + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + "street-address": "2 Harrison St", + "address-level2": "San Francisco", + country: "US", + email: "foo@mozilla.com", + tel: "1234567", + }, + expectedResult: { + "street-addr": "2 Harrison St", + city: "San Francisco", + country: "US", + email: "foo@mozilla.com", + tel: "1234567", + }, + }, + { + description: + "Form with autocomplete properties and profile is partly matched", + document: `
+ + + + + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + "street-address": "2 Harrison St", + "address-level2": "San Francisco", + country: "US", + email: "", + tel: "", + }, + expectedResult: { + "street-addr": "2 Harrison St", + city: "San Francisco", + country: "US", + email: "", + tel: "", + }, + }, + { + description: "Form with autocomplete properties but mismatched", + document: `
+ + + + + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + "street-address": "", + "address-level2": "", + country: "", + email: "foo@mozilla.com", + tel: "1234567", + }, + expectedResult: { + "street-addr": "", + city: "", + country: "", + email: "foo@mozilla.com", + tel: "1234567", + }, + }, + { + description: `Form with elements that have autocomplete set to "off"`, + document: `
+ + + + + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + "given-name": "John", + "family-name": "Doe", + "street-address": "2 Harrison St", + country: "US", + organization: "Test organization", + }, + expectedResult: { + "given-name": "John", + "family-name": "Doe", + "street-address": "2 Harrison St", + organization: "Test organization", + country: "US", + }, + }, + { + description: `Form with autocomplete set to "off" and no autocomplete attribute on the form's elements`, + document: `
+ + + + + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + "given-name": "John", + "family-name": "Doe", + "street-address": "2 Harrison St", + country: "US", + "address-level2": "Somewhere", + }, + expectedResult: { + "given-name": "John", + "family-name": "Doe", + "street-address": "2 Harrison St", + city: "Somewhere", + country: "US", + }, + }, + { + description: + "Form with autocomplete select elements and matching option values", + document: `
+ + + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + country: "US", + "address-level1": "CA", + }, + expectedResult: { + country: "US", + state: "CA", + }, + }, + { + description: + "Form with autocomplete select elements and matching option texts", + document: `
+ + + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + country: "United States", + "address-level1": "California", + }, + expectedResult: { + country: "US", + state: "CA", + }, + }, + { + description: "Form with a readonly input and non-readonly inputs", + document: `
+ + + + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + "given-name": "John", + "family-name": "Doe", + "street-address": "100 Main Street", + city: "Hamilton", + }, + expectedResult: { + "given-name": "John", + "family-name": "Doe", + "street-addr": "100 Main Street", + city: "TEST CITY", + }, + }, + { + description: "Fill address fields in a form with addr and CC fields.", + document: `
+ + + + + + + + + + + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + "street-address": "2 Harrison St line2", + "-moz-street-address-one-line": "2 Harrison St line2", + "address-level2": "San Francisco", + country: "US", + email: "foo@mozilla.com", + tel: "1234567", + }, + expectedResult: { + "street-addr": "2 Harrison St line2", + city: "San Francisco", + country: "US", + email: "foo@mozilla.com", + tel: "1234567", + "cc-number": "", + "cc-name": "", + "cc-exp-month": "", + "cc-exp-year": "", + }, + }, + { + description: + "Fill credit card fields in a form with address and CC fields.", + document: `
+ + + + + + + + + + + +
`, + focusedInputId: "cc-number", + profileData: { + guid: "123", + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": 6, + "cc-exp-year": 25, + }, + expectedResult: { + "street-addr": "", + city: "", + country: "", + email: "", + tel: "", + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": "06", + "cc-exp-year": "25", + }, + }, + { + description: + "Fill credit card fields in a form with a placeholder on expiration month input field", + document: `
+ + + + +
+ `, + focusedInputId: "cc-number", + profileData: { + guid: "123", + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": 6, + "cc-exp-year": 25, + }, + expectedResult: { + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": "06", + "cc-exp-year": "25", + }, + }, + { + description: + "Fill credit card fields in a form without a placeholder on expiration month and expiration year input fields", + document: `
+ + + + +
+ `, + focusedInputId: "cc-number", + profileData: { + guid: "123", + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": 6, + "cc-exp-year": 25, + }, + expectedResult: { + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": "06", + "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": "06", + "cc-exp-year": "25", + }, + }, + { + description: + "Form with hidden input and visible input that share the same autocomplete attribute", + document: `
+ + + + + + + + +
`, + focusedInputId: "visible-cc", + profileData: { + guid: "123", + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": 6, + "cc-exp-year": 25, + }, + expectedResult: { + guid: "123", + "visible-cc": "4111111111111111", + "visible-name": "test name", + "cc-exp-month": "06", + "cc-exp-year": "25", + "hidden-cc": undefined, + "hidden-cc-2": undefined, + "hidden-name": undefined, + "hidden-name-2": undefined, + }, + }, + { + description: + "Fill credit card fields in a form where the value property is being used as a placeholder for cardholder name", + document: `
+ + + + +
`, + focusedInputId: "cc-number", + profileData: { + guid: "123", + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": 6, + "cc-exp-year": 25, + }, + expectedResult: { + guid: "123", + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": "06", + "cc-exp-year": "25", + }, + }, + { + description: + "Fill credit card number fields in a form with multiple cc-number inputs", + document: `
+ + + + + + +
`, + focusedInputId: "cc-number1", + profileData: { + guid: "123", + "cc-number": "371449635398431", + "cc-exp-month": 6, + "cc-exp-year": 25, + }, + expectedResult: { + guid: "123", + "cc-number1": "3714", + "cc-number2": "4963", + "cc-number3": "5398", + "cc-number4": "431", + "cc-exp-month": "06", + "cc-exp-year": "25", + }, + }, + { + description: + "Fill credit card number fields in a form with multiple valid credit card sections", + document: `
+ + + + + + + + + + + + + + + + + +
+ `, + focusedInputId: "cc-number1", + profileData: { + guid: "123", + "cc-type": "mastercard", + "cc-number": "371449635398431", + "cc-exp-month": 6, + "cc-exp-year": 25, + }, + expectedResult: { + guid: "123", + "cc-type1": "mastercard", + "cc-number1": "3714", + "cc-number2": "4963", + "cc-number3": "5398", + "cc-number4": "431", + "cc-exp-month1": "06", + "cc-exp-year1": "25", + "cc-type2": "", + "cc-number-5": "", + "cc-number-6": "", + "cc-number-7": "", + "cc-number-8": "", + "cc-exp-month2": "", + "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 = [ + { + description: + "Form with autocomplete select elements; with default and no matching options", + document: `
+ + + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + country: "US", + "address-level1": "unknown state", + }, + expectedResult: { + country: "US", + state: "", + }, + }, +]; + +const TESTCASES_FILL_SELECT = [ + // US States + { + description: "Form with US states select elements", + document: `
+ + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + country: "US", + "address-level1": "CA", + }, + expectedResult: { + state: "CA", + }, + }, + { + description: + "Form with US states select elements; with lower case state key", + document: `
+ + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + country: "US", + "address-level1": "CA", + }, + expectedResult: { + state: "ca", + }, + }, + { + description: + "Form with US states select elements; with state name and extra spaces", + document: `
+ + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + country: "US", + "address-level1": " California ", + }, + expectedResult: { + state: "CA", + }, + }, + { + description: + "Form with US states select elements; with partial state key match", + document: `
+ + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + country: "US", + "address-level1": "WA", + }, + expectedResult: { + state: "US-WA", + }, + }, + + // Country + { + description: "Form with country select elements", + document: `
+ + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + country: "US", + }, + expectedResult: { + country: "US", + }, + }, + { + description: "Form with country select elements; with lower case key", + document: `
+ + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + country: "US", + }, + expectedResult: { + country: "us", + }, + }, + { + description: "Form with country select elements; with alternative name 1", + document: `
+ + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + country: "US", + }, + expectedResult: { + country: "XX", + }, + }, + { + description: "Form with country select elements; with alternative name 2", + document: `
+ + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + country: "US", + }, + expectedResult: { + country: "XX", + }, + }, + { + description: + "Form with country select elements; with partial matching value", + document: `
+ + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + country: "US", + }, + expectedResult: { + country: "XX", + }, + }, + { + description: + "Fill credit card expiration month field in a form with select field", + document: `
+ + +
`, + focusedInputId: "cc-number", + profileData: { + guid: "123", + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": 6, + "cc-exp-year": 25, + }, + expectedResult: { + "cc-number": "4111111111111111", + "cc-name": "test name", + "cc-exp-month": "6", + "cc-exp-year": "2025", + }, + }, + { + description: + "Fill credit card information correctly when one of the card type options is 'American Express'", + document: `
+ + + + + +
`, + focusedInputId: "cc-number", + profileData: { + guid: "123", + "cc-number": "378282246310005", + "cc-type": "amex", + "cc-name": "test name", + "cc-exp-month": 8, + "cc-exp-year": 26, + }, + expectedResult: { + guid: "123", + "cc-number": "378282246310005", + "cc-type": "AX", + "cc-name": "test name", + "cc-exp-month": 8, + "cc-exp-year": 26, + }, + }, +]; + +const TESTCASES_BOTH_CHANGED_AND_UNCHANGED = [ + { + description: + "Form with a disabled input and non-disabled inputs. The 'country' field should not change", + document: `
+ + + + +
`, + focusedInputId: "given-name", + profileData: { + guid: "123", + "given-name": "John", + "family-name": "Doe", + "street-address": "100 Main Street", + country: "CA", + }, + expectedResult: { + "given-name": "John", + "family-name": "Doe", + "street-addr": "100 Main Street", + country: "DE", + }, + }, +]; + +function do_test(testcases, testFn) { + for (let tc of testcases) { + (function () { + let testcase = tc; + add_task(async function () { + info("Starting testcase: " + testcase.description); + let ccNumber = testcase.profileData["cc-number"]; + if (ccNumber) { + testcase.profileData["cc-number-encrypted"] = + await OSKeyStore.encrypt(ccNumber); + delete testcase.profileData["cc-number"]; + } + + let doc = MockDocument.createTestDocument( + "http://localhost:8080/test/", + testcase.document + ); + let form = doc.querySelector("form"); + let formLike = FormLikeFactory.createFromForm(form); + let handler = new FormAutofillHandler(formLike); + let promises = []; + // Replace the internal decrypt method with OSKeyStore API, + // but don't pass the reauth parameter to avoid triggering + // reauth login dialog in these tests. + let decryptHelper = async (cipherText, reauth) => { + return OSKeyStore.decrypt(cipherText, false); + }; + handler.collectFormFields(); + + let focusedInput = doc.getElementById(testcase.focusedInputId); + 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; + } + + handler.activeSection.fieldDetails.forEach(field => { + let element = field.elementWeakRef.get(); + 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)); + }); + + let [adaptedProfile] = handler.activeSection.getAdaptedProfiles([ + testcase.profileData, + ]); + await handler.autofillFormFields(adaptedProfile, focusedInput); + Assert.equal( + handler.activeSection.filledRecordGUID, + testcase.profileData.guid, + "Check if filledRecordGUID is set correctly" + ); + await Promise.all(promises); + }); + })(); + } +} + +do_test(TESTCASES, (testcase, element) => { + let id = element.id; + return [ + new Promise(resolve => { + element.addEventListener( + "input", + () => { + Assert.ok(true, "Checking " + id + " field fires input event"); + resolve(); + }, + { once: true } + ); + }), + new Promise(resolve => { + element.addEventListener( + "change", + () => { + Assert.ok(true, "Checking " + id + " field fires change event"); + Assert.equal( + element.value, + testcase.expectedResult[id], + "Check the " + id + " field was filled with correct data" + ); + resolve(); + }, + { once: true } + ); + }), + ]; +}); + +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); + }), + ]; +}); + +do_test(TESTCASES_FILL_SELECT, (testcase, element) => { + let id = element.id; + return [ + new Promise(resolve => { + element.addEventListener( + "input", + () => { + Assert.equal( + element.value, + testcase.expectedResult[id], + "Check the " + id + " field was filled with correct data" + ); + resolve(); + }, + { once: true } + ); + }), + ]; +}); + +do_test(TESTCASES_BOTH_CHANGED_AND_UNCHANGED, (testcase, element) => { + // Ensure readonly and disabled inputs are not autofilled + if (element.readOnly || element.disabled) { + 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); + }), + ]; + } + let id = element.id; + // Ensure that non-disabled and non-readonly fields are filled correctly + return [ + new Promise(resolve => { + element.addEventListener( + "input", + () => { + Assert.ok(true, "Checking " + id + " field fires input event"); + resolve(); + }, + { once: true } + ); + }), + new Promise(resolve => { + element.addEventListener( + "change", + () => { + Assert.ok(true, "Checking " + id + " field fires change event"); + Assert.equal( + element.value, + testcase.expectedResult[id], + "Check the " + id + " field was filled with correct data" + ); + resolve(); + }, + { once: true } + ); + }), + ]; +}); -- cgit v1.2.3