/* * Test for form auto fill content helper fill all inputs function. */ /* eslint-disable mozilla/no-arbitrary-setTimeout */ "use strict"; const { setTimeout, clearTimeout } = ChromeUtils.import( "resource://gre/modules/Timer.jsm", {} ); var FormAutofillHandler, OSKeyStore; add_task(async function setup() { ({ FormAutofillHandler } = ChromeUtils.import( "resource://formautofill/FormAutofillHandler.jsm" )); ({ OSKeyStore } = ChromeUtils.import( "resource://gre/modules/OSKeyStore.jsm" )); }); 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 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: "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 addr and CC fields.", document: ``, focusedInputId: "cc-number", profileData: { guid: "123", "cc-number": "4111111111111111", "cc-name": "test name", "cc-exp-month": "06", "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", }, }, ]; 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", }, }, ]; 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); handler.focusedInput = focusedInput; 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 } ); }), ]; });