forked from mirrors/gecko-dev
580 lines
20 KiB
JavaScript
580 lines
20 KiB
JavaScript
/*
|
|
* Test for form auto fill content helper fill all inputs function.
|
|
*/
|
|
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
|
|
|
"use strict";
|
|
|
|
var FormAutofillHandler, OSKeyStore;
|
|
add_task(async function setup() {
|
|
({FormAutofillHandler} = ChromeUtils.import("resource://formautofill/FormAutofillHandler.jsm"));
|
|
({OSKeyStore} = ChromeUtils.import("resource://formautofill/OSKeyStore.jsm"));
|
|
});
|
|
|
|
const TESTCASES = [
|
|
{
|
|
description: "Form without autocomplete property",
|
|
document: `<form><input id="given-name"><input id="family-name">
|
|
<input id="street-addr"><input id="city"><select id="country"></select>
|
|
<input id='email'><input id="tel"></form>`,
|
|
focusedInputId: "given-name",
|
|
profileData: {},
|
|
expectedResult: {
|
|
"street-addr": "",
|
|
"city": "",
|
|
"country": "",
|
|
"email": "",
|
|
"tel": "",
|
|
},
|
|
},
|
|
{
|
|
description: "Form with autocomplete properties and 1 token",
|
|
document: `<form><input id="given-name" autocomplete="given-name">
|
|
<input id="family-name" autocomplete="family-name">
|
|
<input id="street-addr" autocomplete="street-address">
|
|
<input id="city" autocomplete="address-level2">
|
|
<select id="country" autocomplete="country">
|
|
<option/>
|
|
<option value="US">United States</option>
|
|
</select>
|
|
<input id="email" autocomplete="email">
|
|
<input id="tel" autocomplete="tel"></form>`,
|
|
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: `<form><input id="given-name" autocomplete="shipping given-name">
|
|
<input id="family-name" autocomplete="shipping family-name">
|
|
<input id="street-addr" autocomplete="shipping street-address">
|
|
<input id="city" autocomplete="shipping address-level2">
|
|
<select id="country" autocomplete="shipping country">
|
|
<option/>
|
|
<option value="US">United States</option>
|
|
</select>
|
|
<input id='email' autocomplete="shipping email">
|
|
<input id="tel" autocomplete="shipping tel"></form>`,
|
|
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: `<form><input id="given-name" autocomplete="shipping given-name">
|
|
<input id="family-name" autocomplete="shipping family-name">
|
|
<input id="street-addr" autocomplete="shipping street-address">
|
|
<input id="city" autocomplete="shipping address-level2">
|
|
<input id="country" autocomplete="shipping country">
|
|
<input id='email' autocomplete="shipping email">
|
|
<input id="tel" autocomplete="shipping tel"></form>`,
|
|
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: `<form><input id="given-name" autocomplete="shipping given-name">
|
|
<input id="family-name" autocomplete="shipping family-name">
|
|
<input id="street-addr" autocomplete="billing street-address">
|
|
<input id="city" autocomplete="billing address-level2">
|
|
<input id="country" autocomplete="billing country">
|
|
<input id='email' autocomplete="shipping email">
|
|
<input id="tel" autocomplete="shipping tel"></form>`,
|
|
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: `<form>
|
|
<input id="given-name" autocomplete="shipping given-name">
|
|
<select id="country" autocomplete="shipping country">
|
|
<option value=""></option>
|
|
<option value="US">United States</option>
|
|
</select>
|
|
<select id="state" autocomplete="shipping address-level1">
|
|
<option value=""></option>
|
|
<option value="CA">California</option>
|
|
<option value="WA">Washington</option>
|
|
</select>
|
|
</form>`,
|
|
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: `<form>
|
|
<input id="given-name" autocomplete="shipping given-name">
|
|
<select id="country" autocomplete="shipping country">
|
|
<option value=""></option>
|
|
<option value="US">United States</option>
|
|
</select>
|
|
<select id="state" autocomplete="shipping address-level1">
|
|
<option value=""></option>
|
|
<option value="CA">California</option>
|
|
<option value="WA">Washington</option>
|
|
</select>
|
|
</form>`,
|
|
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: `<form>
|
|
<input id="given-name" autocomplete="given-name">
|
|
<input id="family-name" autocomplete="family-name">
|
|
<input id="street-addr" autocomplete="street-address">
|
|
<input id="city" autocomplete="address-level2">
|
|
<select id="country" autocomplete="country">
|
|
<option/>
|
|
<option value="US">United States</option>
|
|
</select>
|
|
<input id="email" autocomplete="email">
|
|
<input id="tel" autocomplete="tel">
|
|
<input id="cc-number" autocomplete="cc-number">
|
|
<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>`,
|
|
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: `<form>
|
|
<input id="given-name" autocomplete="given-name">
|
|
<input id="family-name" autocomplete="family-name">
|
|
<input id="street-addr" autocomplete="street-address">
|
|
<input id="city" autocomplete="address-level2">
|
|
<select id="country" autocomplete="country">
|
|
<option/>
|
|
<option value="US">United States</option>
|
|
</select>
|
|
<input id="email" autocomplete="email">
|
|
<input id="tel" autocomplete="tel">
|
|
<input id="cc-number" autocomplete="cc-number">
|
|
<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>`,
|
|
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: `<form>
|
|
<input id="given-name" autocomplete="shipping given-name">
|
|
<select id="country" autocomplete="shipping country">
|
|
<option value="US">United States</option>
|
|
</select>
|
|
<select id="state" autocomplete="shipping address-level1">
|
|
<option value=""></option>
|
|
<option value="CA">California</option>
|
|
<option value="WA">Washington</option>
|
|
</select>
|
|
</form>`,
|
|
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: `<form>
|
|
<input id="given-name" autocomplete="shipping given-name">
|
|
<input id="family-name" autocomplete="shipping family-name">
|
|
<select id="state" autocomplete="shipping address-level1">
|
|
<option value=""></option>
|
|
<option value="CA">California</option>
|
|
</select></form>`,
|
|
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: `<form>
|
|
<input id="given-name" autocomplete="shipping given-name">
|
|
<input id="family-name" autocomplete="shipping family-name">
|
|
<select id="state" autocomplete="shipping address-level1">
|
|
<option value=""></option>
|
|
<option value="ca">ca</option>
|
|
</select></form>`,
|
|
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: `<form>
|
|
<input id="given-name" autocomplete="shipping given-name">
|
|
<input id="family-name" autocomplete="shipping family-name">
|
|
<select id="state" autocomplete="shipping address-level1">
|
|
<option value=""></option>
|
|
<option value="CA">CA</option>
|
|
</select></form>`,
|
|
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: `<form>
|
|
<input id="given-name" autocomplete="shipping given-name">
|
|
<input id="family-name" autocomplete="shipping family-name">
|
|
<select id="state" autocomplete="shipping address-level1">
|
|
<option value=""></option>
|
|
<option value="US-WA">WA-Washington</option>
|
|
</select></form>`,
|
|
focusedInputId: "given-name",
|
|
profileData: {
|
|
"guid": "123",
|
|
"country": "US",
|
|
"address-level1": "WA",
|
|
},
|
|
expectedResult: {
|
|
"state": "US-WA",
|
|
},
|
|
},
|
|
|
|
// Country
|
|
{
|
|
description: "Form with country select elements",
|
|
document: `<form>
|
|
<input id="given-name" autocomplete="given-name">
|
|
<input id="family-name" autocomplete="family-name">
|
|
<select id="country" autocomplete="country">
|
|
<option value=""></option>
|
|
<option value="US">United States</option>
|
|
</select></form>`,
|
|
focusedInputId: "given-name",
|
|
profileData: {
|
|
"guid": "123",
|
|
"country": "US",
|
|
},
|
|
expectedResult: {
|
|
"country": "US",
|
|
},
|
|
},
|
|
{
|
|
description: "Form with country select elements; with lower case key",
|
|
document: `<form>
|
|
<input id="given-name" autocomplete="given-name">
|
|
<input id="family-name" autocomplete="family-name">
|
|
<select id="country" autocomplete="country">
|
|
<option value=""></option>
|
|
<option value="us">us</option>
|
|
</select></form>`,
|
|
focusedInputId: "given-name",
|
|
profileData: {
|
|
"guid": "123",
|
|
"country": "US",
|
|
},
|
|
expectedResult: {
|
|
"country": "us",
|
|
},
|
|
},
|
|
{
|
|
description: "Form with country select elements; with alternative name 1",
|
|
document: `<form>
|
|
<input id="given-name" autocomplete="given-name">
|
|
<input id="family-name" autocomplete="family-name">
|
|
<select id="country" autocomplete="country">
|
|
<option value=""></option>
|
|
<option value="XX">United States</option>
|
|
</select></form>`,
|
|
focusedInputId: "given-name",
|
|
profileData: {
|
|
"guid": "123",
|
|
"country": "US",
|
|
},
|
|
expectedResult: {
|
|
"country": "XX",
|
|
},
|
|
},
|
|
{
|
|
description: "Form with country select elements; with alternative name 2",
|
|
document: `<form>
|
|
<input id="given-name" autocomplete="given-name">
|
|
<input id="family-name" autocomplete="family-name">
|
|
<select id="country" autocomplete="country">
|
|
<option value=""></option>
|
|
<option value="XX">America</option>
|
|
</select></form>`,
|
|
focusedInputId: "given-name",
|
|
profileData: {
|
|
"guid": "123",
|
|
"country": "US",
|
|
},
|
|
expectedResult: {
|
|
"country": "XX",
|
|
},
|
|
},
|
|
{
|
|
description: "Form with country select elements; with partial matching value",
|
|
document: `<form>
|
|
<input id="given-name" autocomplete="given-name">
|
|
<input id="family-name" autocomplete="family-name">
|
|
<select id="country" autocomplete="country">
|
|
<option value=""></option>
|
|
<option value="XX">Ship to America</option>
|
|
</select></form>`,
|
|
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});
|
|
}),
|
|
];
|
|
});
|