зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1836450 - Redesign the address/credit card normalization flow r=credential-management-reviewers,sgalich
Differential Revision: https://phabricator.services.mozilla.com/D181360
This commit is contained in:
Родитель
e8fa16ce58
Коммит
9a18720b2c
|
@ -10,5 +10,6 @@ support-files =
|
|||
head_address.js
|
||||
|
||||
[browser_address_doorhanger_display.js]
|
||||
[browser_address_doorhanger_not_shown.js]
|
||||
[browser_address_doorhanger_tel.js]
|
||||
[browser_address_telemetry.js]
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
"use strict";
|
||||
|
||||
const DEFAULT_TEST_DOC = `<form id="form">
|
||||
<input id="street-addr" autocomplete="street-address">
|
||||
<select id="address-level1" autocomplete="address-level1">
|
||||
<option value=""></option>
|
||||
<option value="AL">Alabama</option>
|
||||
<option value="AK">Alaska</option>
|
||||
<option value="AP">Armed Forces Pacific</option>
|
||||
|
||||
<option value="ca">california</option>
|
||||
<option value="AR">US-Arkansas</option>
|
||||
<option value="US-CA">California</option>
|
||||
<option value="CA">California</option>
|
||||
<option value="US-AZ">US_Arizona</option>
|
||||
<option value="Ariz">Arizonac</option>
|
||||
</select>
|
||||
<input id="city" autocomplete="address-level2">
|
||||
<input id="country" autocomplete="country">
|
||||
<input id="email" autocomplete="email">
|
||||
<input id="tel" autocomplete="tel">
|
||||
<input id="cc-name" autocomplete="cc-name">
|
||||
<input id="cc-number" autocomplete="cc-number">
|
||||
<input id="cc-exp-month" autocomplete="cc-exp-month">
|
||||
<input id="cc-exp-year" autocomplete="cc-exp-year">
|
||||
<select id="cc-type">
|
||||
<option value="">Select</option>
|
||||
<option value="visa">Visa</option>
|
||||
<option value="mastercard">Master Card</option>
|
||||
<option value="amex">American Express</option>
|
||||
</select>
|
||||
<input id="submit" type="submit">
|
||||
</form>`;
|
||||
const TARGET_ELEMENT_ID = "street-addr";
|
||||
|
||||
const TESTCASES = [
|
||||
{
|
||||
description:
|
||||
"Should not trigger address saving if the number of fields is less than 3",
|
||||
document: DEFAULT_TEST_DOC,
|
||||
targetElementId: TARGET_ELEMENT_ID,
|
||||
formValue: {
|
||||
"#street-addr": "331 E. Evelyn Avenue",
|
||||
"#tel": "1-650-903-0800",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
add_setup(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["extensions.formautofill.addresses.capture.enabled", true],
|
||||
["extensions.formautofill.addresses.supported", "on"],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_save_doorhanger_not_shown() {
|
||||
for (const TEST of TESTCASES) {
|
||||
info(`Test ${TEST.description}`);
|
||||
|
||||
await BrowserTestUtils.withNewTab(EMPTY_URL, async function (browser) {
|
||||
await SpecialPowers.spawn(browser, [TEST.document], doc => {
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
content.document.body.innerHTML = doc;
|
||||
});
|
||||
|
||||
await SimpleTest.promiseFocus(browser);
|
||||
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: `#${TEST.targetElementId}`,
|
||||
newValues: TEST.formValue,
|
||||
});
|
||||
|
||||
await ensureNoDoorhanger(browser);
|
||||
});
|
||||
}
|
||||
});
|
|
@ -65,3 +65,51 @@ add_task(async function test_save_doorhanger_tel_invalid() {
|
|||
await removeAllRecords();
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_save_doorhanger_tel_concatenated() {
|
||||
const EXPECTED = [
|
||||
{
|
||||
"given-name": "Test User",
|
||||
organization: "Mozilla",
|
||||
tel: "+15202486621",
|
||||
},
|
||||
];
|
||||
|
||||
const MARKUP = `<form id="form">
|
||||
<input id="given-name" autocomplete="given-name">
|
||||
<input id="organization" autocomplete="organization">
|
||||
<input id="tel-country-code" autocomplete="tel-country-code">
|
||||
<input id="tel-national" autocomplete="tel-national">
|
||||
<input type="submit">
|
||||
</form>`;
|
||||
|
||||
await expectSavedAddresses([]);
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: EMPTY_URL },
|
||||
async function (browser) {
|
||||
await SpecialPowers.spawn(browser, [MARKUP], doc => {
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
content.document.body.innerHTML = doc;
|
||||
});
|
||||
|
||||
let onPopupShown = waitForPopupShown();
|
||||
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#given-name",
|
||||
newValues: {
|
||||
"#given-name": "Test User",
|
||||
"#organization": "Mozilla",
|
||||
"#tel-country-code": "+1",
|
||||
"#tel-national": "5202486621",
|
||||
},
|
||||
});
|
||||
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON, 0);
|
||||
}
|
||||
);
|
||||
|
||||
await expectSavedAddresses(EXPECTED);
|
||||
await removeAllRecords();
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
const URL = BASE_URL + "autocomplete_basic.html";
|
||||
|
||||
add_task(async function setup_storage() {
|
||||
add_setup(async function setup_storage() {
|
||||
await setStorage(
|
||||
TEST_ADDRESS_2,
|
||||
TEST_ADDRESS_3,
|
||||
|
@ -104,13 +104,7 @@ add_task(async function test_phishing_warning_single_category() {
|
|||
".autocomplete-richlistitem:last-child"
|
||||
)._warningTextBox;
|
||||
ok(warningBox, "Got phishing warning box");
|
||||
await expectWarningText(browser, "Autofills phone");
|
||||
is(
|
||||
warningBox.ownerGlobal.getComputedStyle(warningBox).backgroundColor,
|
||||
"rgba(248, 232, 28, 0.2)",
|
||||
"Check warning text background color"
|
||||
);
|
||||
|
||||
await expectWarningText(browser, "Also autofills address");
|
||||
await closePopup(browser);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -25,6 +25,8 @@ skip-if = (!debug && os == "mac") || (os == "win" && ccov) # perma-fail see Bug
|
|||
skip-if = (!debug && os == "mac") || (os == "win" && ccov) # perma-fail see Bug 1655601, Bug 1655600
|
||||
[browser_creditCard_doorhanger_logo.js]
|
||||
skip-if = (!debug && os == "mac") || (os == "win" && ccov) # perma-fail see Bug 1655601, Bug 1655600
|
||||
[browser_creditCard_doorhanger_not_shown.js]
|
||||
skip-if = (!debug && os == "mac") || (os == "win" && ccov) # perma-fail see Bug 1655601, Bug 1655600
|
||||
[browser_creditCard_doorhanger_sync.js]
|
||||
skip-if = (!debug && os == "mac") || (os == "win" && ccov) # perma-fail see Bug 1655601, Bug 1655600
|
||||
[browser_creditCard_dropdown_layout.js]
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
"use strict";
|
||||
|
||||
const DEFAULT_TEST_DOC = `<form id="form">
|
||||
<input id="street-addr" autocomplete="street-address">
|
||||
<select id="address-level1" autocomplete="address-level1">
|
||||
<option value=""></option>
|
||||
<option value="AL">Alabama</option>
|
||||
<option value="AK">Alaska</option>
|
||||
<option value="AP">Armed Forces Pacific</option>
|
||||
|
||||
<option value="ca">california</option>
|
||||
<option value="AR">US-Arkansas</option>
|
||||
<option value="US-CA">California</option>
|
||||
<option value="CA">California</option>
|
||||
<option value="US-AZ">US_Arizona</option>
|
||||
<option value="Ariz">Arizonac</option>
|
||||
</select>
|
||||
<input id="city" autocomplete="address-level2">
|
||||
<input id="country" autocomplete="country">
|
||||
<input id="email" autocomplete="email">
|
||||
<input id="tel" autocomplete="tel">
|
||||
<input id="cc-name" autocomplete="cc-name">
|
||||
<input id="cc-number" autocomplete="cc-number">
|
||||
<input id="cc-exp-month" autocomplete="cc-exp-month">
|
||||
<input id="cc-exp-year" autocomplete="cc-exp-year">
|
||||
<select id="cc-type">
|
||||
<option value="">Select</option>
|
||||
<option value="visa">Visa</option>
|
||||
<option value="mastercard">Master Card</option>
|
||||
<option value="amex">American Express</option>
|
||||
</select>
|
||||
<input id="submit" type="submit">
|
||||
</form>`;
|
||||
|
||||
const TESTCASES = [
|
||||
{
|
||||
description: "Should not trigger credit card saving if number is empty",
|
||||
document: DEFAULT_TEST_DOC,
|
||||
targetElementId: "cc-name",
|
||||
formValue: {
|
||||
"#cc-name": "John Doe",
|
||||
"#cc-exp-month": 12,
|
||||
"#cc-exp-year": 2000,
|
||||
},
|
||||
},
|
||||
{
|
||||
description:
|
||||
"Should not trigger credit card saving if there is more than one cc-number field but less than four fields",
|
||||
document: `<form id="form">
|
||||
<input id="cc-type" autocomplete="cc-type">
|
||||
<input id="cc-name" autocomplete="cc-name">
|
||||
<input id="cc-number1" maxlength="4">
|
||||
<input id="cc-number2" maxlength="4">
|
||||
<input id="cc-number3" maxlength="4">
|
||||
<input id="cc-exp-month" autocomplete="cc-exp-month">
|
||||
<input id="cc-exp-year" autocomplete="cc-exp-year">
|
||||
<input id="submit" type="submit">
|
||||
</form>
|
||||
`,
|
||||
targetElementId: "cc-name",
|
||||
formValue: {
|
||||
"#cc-name": "John Doe",
|
||||
"#cc-number1": "3714",
|
||||
"#cc-number2": "4963",
|
||||
"#cc-number3": "5398",
|
||||
"#cc-exp-month": 12,
|
||||
"#cc-exp-year": 2000,
|
||||
"#cc-type": "amex",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function test_save_doorhanger_not_shown() {
|
||||
for (const TEST of TESTCASES) {
|
||||
info(`Test ${TEST.description}`);
|
||||
|
||||
await BrowserTestUtils.withNewTab(EMPTY_URL, async function (browser) {
|
||||
await SpecialPowers.spawn(browser, [TEST.document], doc => {
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
content.document.body.innerHTML = doc;
|
||||
});
|
||||
|
||||
await SimpleTest.promiseFocus(browser);
|
||||
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: `#${TEST.targetElementId}`,
|
||||
newValues: TEST.formValue,
|
||||
});
|
||||
|
||||
await ensureNoDoorhanger(browser);
|
||||
});
|
||||
}
|
||||
});
|
|
@ -193,6 +193,7 @@ const MENU_BUTTON = "menubutton";
|
|||
const TIMEOUT_ENSURE_PROFILE_NOT_SAVED = 1000;
|
||||
const TIMEOUT_ENSURE_CC_DIALOG_NOT_CLOSED = 500;
|
||||
const TIMEOUT_ENSURE_AUTOCOMPLETE_NOT_SHOWN = 1000;
|
||||
const TIMEOUT_ENSURE_DOORHANGER_NOT_SHOWN = 1000;
|
||||
|
||||
async function ensureCreditCardDialogNotClosed(win) {
|
||||
const unloadHandler = () => {
|
||||
|
@ -229,7 +230,16 @@ async function ensureNoAutocompletePopup(browser) {
|
|||
setTimeout(resolve, TIMEOUT_ENSURE_AUTOCOMPLETE_NOT_SHOWN)
|
||||
);
|
||||
const items = getDisplayedPopupItems(browser);
|
||||
ok(!items.length, "Should not found autocomplete items");
|
||||
ok(!items.length, "Should not find autocomplete items");
|
||||
}
|
||||
|
||||
async function ensureNoDoorhanger(browser) {
|
||||
await new Promise(resolve =>
|
||||
setTimeout(resolve, TIMEOUT_ENSURE_DOORHANGER_NOT_SHOWN)
|
||||
);
|
||||
|
||||
let notifications = PopupNotifications.panel.childNodes;
|
||||
ok(!notifications.length, "Should not find a doorhanger");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,30 +20,36 @@ Form autofill test: preview and highlight
|
|||
const MOCK_STORAGE = [
|
||||
{
|
||||
organization: "Sesame Street",
|
||||
country: "US",
|
||||
"street-address": "123 Sesame Street.",
|
||||
tel: "+13453453456",
|
||||
},
|
||||
{
|
||||
organization: "Mozilla",
|
||||
country: "US",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
},
|
||||
{
|
||||
organization: "Tel org",
|
||||
country: "US",
|
||||
tel: "+12223334444",
|
||||
},
|
||||
{
|
||||
organization: "Random Org",
|
||||
country: "US",
|
||||
"address-level1": "First Admin Level",
|
||||
tel: "+13453453456",
|
||||
},
|
||||
{
|
||||
organization: "readonly Org",
|
||||
country: "US",
|
||||
"address-level1": "First Admin Level",
|
||||
tel: "+13453453456",
|
||||
name: "John Doe",
|
||||
},
|
||||
{
|
||||
organization: "test org",
|
||||
country: "US",
|
||||
"address-level2": "Not a Town",
|
||||
tel: "+13453453456",
|
||||
name: "John Doe",
|
||||
|
|
|
@ -19,10 +19,12 @@ Form autofill test: check if address is saved/updated correctly
|
|||
|
||||
let TEST_ADDRESSES = [{
|
||||
organization: "Sesame Street",
|
||||
country: "US",
|
||||
"street-address": "123 Sesame Street.",
|
||||
tel: "+13453453456",
|
||||
}, {
|
||||
organization: "Mozilla",
|
||||
country: "US",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
tel: "+16509030800",
|
||||
}];
|
||||
|
|
|
@ -63,11 +63,6 @@ const TEST_ADDRESS_EMPTY_AFTER_NORMALIZE = {
|
|||
country: "XXXXXX",
|
||||
};
|
||||
|
||||
const TEST_ADDRESS_EMPTY_AFTER_UPDATE_ADDRESS_2 = {
|
||||
"street-address": "",
|
||||
country: "XXXXXX",
|
||||
};
|
||||
|
||||
ChromeUtils.defineESModuleGetters(this, {
|
||||
Preferences: "resource://gre/modules/Preferences.sys.mjs",
|
||||
});
|
||||
|
@ -245,7 +240,7 @@ add_task(async function test_update() {
|
|||
|
||||
let address = await profileStorage.addresses.get(guid, { rawData: true });
|
||||
|
||||
Assert.equal(address.country, undefined);
|
||||
Assert.equal(address.country, "US");
|
||||
Assert.ok(address.timeLastModified > timeLastModified);
|
||||
do_check_record_matches(address, TEST_ADDRESS_3);
|
||||
Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 1);
|
||||
|
@ -317,13 +312,6 @@ add_task(async function test_update() {
|
|||
);
|
||||
|
||||
profileStorage.addresses.update(guid, TEST_ADDRESS_2);
|
||||
await Assert.rejects(
|
||||
profileStorage.addresses.update(
|
||||
guid,
|
||||
TEST_ADDRESS_EMPTY_AFTER_UPDATE_ADDRESS_2
|
||||
),
|
||||
/Record contains no valid field\./
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_notifyUsed() {
|
||||
|
|
|
@ -64,150 +64,6 @@ const TESTCASES = [
|
|||
creditCard: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
description: `"country" using @autocomplete shouldn't be identified aggressively`,
|
||||
document: `<form>
|
||||
<input id="given-name" autocomplete="given-name">
|
||||
<input id="organization" autocomplete="organization">
|
||||
<input id="country" autocomplete="country">
|
||||
</form>`,
|
||||
formValue: {
|
||||
"given-name": "John",
|
||||
organization: "Mozilla",
|
||||
country: "United States",
|
||||
},
|
||||
expectedRecord: {
|
||||
// "United States" is not a valid country, only country-name. See isRecordCreatable.
|
||||
address: [],
|
||||
creditCard: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
description: `"country" using heuristics should be identified aggressively`,
|
||||
document: `<form>
|
||||
<input id="given-name" autocomplete="given-name">
|
||||
<input id="organization" autocomplete="organization">
|
||||
<input id="country" name="country">
|
||||
</form>`,
|
||||
formValue: {
|
||||
"given-name": "John",
|
||||
organization: "Mozilla",
|
||||
country: "United States",
|
||||
},
|
||||
expectedRecord: {
|
||||
address: [
|
||||
{
|
||||
"given-name": "John",
|
||||
organization: "Mozilla",
|
||||
country: "US",
|
||||
},
|
||||
],
|
||||
creditCard: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
description: `"tel" related fields should be concatenated`,
|
||||
document: `<form>
|
||||
<input id="given-name" autocomplete="given-name">
|
||||
<input id="organization" autocomplete="organization">
|
||||
<input id="tel-country-code" autocomplete="tel-country-code">
|
||||
<input id="tel-national" autocomplete="tel-national">
|
||||
</form>`,
|
||||
formValue: {
|
||||
"given-name": "John",
|
||||
organization: "Mozilla",
|
||||
"tel-country-code": "+1",
|
||||
"tel-national": "1234567890",
|
||||
},
|
||||
expectedRecord: {
|
||||
address: [
|
||||
{
|
||||
"given-name": "John",
|
||||
organization: "Mozilla",
|
||||
tel: "+11234567890",
|
||||
},
|
||||
],
|
||||
creditCard: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
description: `"tel" should be removed if it's too short`,
|
||||
document: `<form>
|
||||
<input id="given-name" autocomplete="given-name">
|
||||
<input id="organization" autocomplete="organization">
|
||||
<input id="country" autocomplete="country">
|
||||
<input id="tel" autocomplete="tel-national">
|
||||
</form>`,
|
||||
formValue: {
|
||||
"given-name": "John",
|
||||
organization: "Mozilla",
|
||||
country: "US",
|
||||
tel: "1234",
|
||||
},
|
||||
expectedRecord: {
|
||||
address: [
|
||||
{
|
||||
"given-name": "John",
|
||||
organization: "Mozilla",
|
||||
country: "US",
|
||||
tel: "",
|
||||
},
|
||||
],
|
||||
creditCard: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
description: `"tel" should be removed if it's too long`,
|
||||
document: `<form>
|
||||
<input id="given-name" autocomplete="given-name">
|
||||
<input id="organization" autocomplete="organization">
|
||||
<input id="country" autocomplete="country">
|
||||
<input id="tel" autocomplete="tel-national">
|
||||
</form>`,
|
||||
formValue: {
|
||||
"given-name": "John",
|
||||
organization: "Mozilla",
|
||||
country: "US",
|
||||
tel: "1234567890123456",
|
||||
},
|
||||
expectedRecord: {
|
||||
address: [
|
||||
{
|
||||
"given-name": "John",
|
||||
organization: "Mozilla",
|
||||
country: "US",
|
||||
tel: "",
|
||||
},
|
||||
],
|
||||
creditCard: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
description: `"tel" should be removed if it contains invalid characters`,
|
||||
document: `<form>
|
||||
<input id="given-name" autocomplete="given-name">
|
||||
<input id="organization" autocomplete="organization">
|
||||
<input id="country" autocomplete="country">
|
||||
<input id="tel" autocomplete="tel-national">
|
||||
</form>`,
|
||||
formValue: {
|
||||
"given-name": "John",
|
||||
organization: "Mozilla",
|
||||
country: "US",
|
||||
tel: "12345###!!!",
|
||||
},
|
||||
expectedRecord: {
|
||||
address: [
|
||||
{
|
||||
"given-name": "John",
|
||||
organization: "Mozilla",
|
||||
country: "US",
|
||||
tel: "",
|
||||
},
|
||||
],
|
||||
creditCard: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "All name related fields should be counted as 1 field only.",
|
||||
document: `<form>
|
||||
|
@ -268,8 +124,6 @@ const TESTCASES = [
|
|||
"cc-name": "Foo Bar",
|
||||
"cc-exp": "2022-06",
|
||||
"cc-type": "Visa",
|
||||
"cc-exp-month": "6",
|
||||
"cc-exp-year": "2022",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -463,8 +317,8 @@ const TESTCASES = [
|
|||
creditCard: [
|
||||
{
|
||||
"cc-number": "5105105105105100",
|
||||
"cc-exp-month": "5",
|
||||
"cc-exp-year": "2026",
|
||||
"cc-exp-month": "05",
|
||||
"cc-exp-year": "26",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -486,8 +340,6 @@ const TESTCASES = [
|
|||
{
|
||||
"cc-number": "5105105105105100",
|
||||
"cc-exp": "07/27",
|
||||
"cc-exp-month": "7",
|
||||
"cc-exp-year": "2027",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -72,12 +72,6 @@ const TEST_CREDIT_CARD_WITH_2_DIGITS_YEAR = {
|
|||
"cc-exp-year": 12,
|
||||
};
|
||||
|
||||
const TEST_CREDIT_CARD_WITH_INVALID_FIELD = {
|
||||
"cc-name": "John Doe",
|
||||
"cc-number": "344060747836806",
|
||||
"cc-type": { invalid: "invalid" },
|
||||
};
|
||||
|
||||
const TEST_CREDIT_CARD_WITH_INVALID_EXPIRY_DATE = {
|
||||
"cc-name": "John Doe",
|
||||
"cc-number": "5103059495477870",
|
||||
|
@ -255,11 +249,6 @@ add_task(async function test_add() {
|
|||
)
|
||||
);
|
||||
|
||||
await Assert.rejects(
|
||||
profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_INVALID_FIELD),
|
||||
/"cc-type" contains invalid data type: object/
|
||||
);
|
||||
|
||||
await Assert.rejects(
|
||||
profileStorage.creditCards.add({}),
|
||||
/Record contains no valid field\./
|
||||
|
@ -394,14 +383,6 @@ add_task(async function test_update() {
|
|||
/No matching record\./
|
||||
);
|
||||
|
||||
await Assert.rejects(
|
||||
profileStorage.creditCards.update(
|
||||
guid,
|
||||
TEST_CREDIT_CARD_WITH_INVALID_FIELD
|
||||
),
|
||||
/"cc-type" contains invalid data type: object/
|
||||
);
|
||||
|
||||
await Assert.rejects(
|
||||
profileStorage.creditCards.update(guid, {}),
|
||||
/Record contains no valid field\./
|
||||
|
|
|
@ -232,16 +232,19 @@ const ADDRESS_RECONCILE_TESTCASES = [
|
|||
"given-name": "Mark",
|
||||
"family-name": "Hammond",
|
||||
tel: "123456",
|
||||
country: "US",
|
||||
},
|
||||
local: [
|
||||
{
|
||||
"given-name": "Skip",
|
||||
"family-name": "Hammond",
|
||||
country: "US",
|
||||
},
|
||||
{
|
||||
"given-name": "Skip",
|
||||
"family-name": "Hammond",
|
||||
organization: "Mozilla",
|
||||
country: "US",
|
||||
},
|
||||
],
|
||||
remote: {
|
||||
|
|
|
@ -107,9 +107,11 @@ const ADDRESS_COMPUTE_TESTCASES = [
|
|||
description: 'Has "country"',
|
||||
address: {
|
||||
country: "US",
|
||||
name: "Timothy John Berners-Lee",
|
||||
},
|
||||
expectedResult: {
|
||||
country: "US",
|
||||
name: "Timothy John Berners-Lee",
|
||||
"country-name": "United States",
|
||||
},
|
||||
},
|
||||
|
@ -322,9 +324,11 @@ const ADDRESS_NORMALIZE_TESTCASES = [
|
|||
description: 'Has "country" in lowercase',
|
||||
address: {
|
||||
country: "us",
|
||||
name: "name",
|
||||
},
|
||||
expectedResult: {
|
||||
country: "US",
|
||||
name: "name",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -334,59 +338,67 @@ const ADDRESS_NORMALIZE_TESTCASES = [
|
|||
country: "AA",
|
||||
},
|
||||
expectedResult: {
|
||||
country: undefined,
|
||||
country: "US",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Has "country-name"',
|
||||
address: {
|
||||
"country-name": "united states",
|
||||
name: "name",
|
||||
},
|
||||
expectedResult: {
|
||||
country: "US",
|
||||
"country-name": "United States",
|
||||
name: "name",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Has alternative "country-name"',
|
||||
address: {
|
||||
"country-name": "america",
|
||||
name: "name",
|
||||
},
|
||||
expectedResult: {
|
||||
country: "US",
|
||||
"country-name": "United States",
|
||||
name: "name",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Has "country-name" as a substring',
|
||||
address: {
|
||||
"country-name": "test america test",
|
||||
name: "name",
|
||||
},
|
||||
expectedResult: {
|
||||
country: "US",
|
||||
"country-name": "United States",
|
||||
name: "name",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Has "country-name" as part of a word',
|
||||
address: {
|
||||
"given-name": "John", // Make sure it won't be an empty record.
|
||||
"country-name": "TRUST",
|
||||
name: "name", // Make sure it won't be an empty record.
|
||||
},
|
||||
expectedResult: {
|
||||
country: undefined,
|
||||
"country-name": undefined,
|
||||
country: "US",
|
||||
"country-name": "United States",
|
||||
name: "name",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Has unknown "country-name"',
|
||||
address: {
|
||||
"given-name": "John", // Make sure it won't be an empty record.
|
||||
"country-name": "unknown country name",
|
||||
name: "name", // Make sure it won't be an empty record.
|
||||
},
|
||||
expectedResult: {
|
||||
country: undefined,
|
||||
"country-name": undefined,
|
||||
country: "US",
|
||||
"country-name": "United States",
|
||||
name: "name",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -394,33 +406,37 @@ const ADDRESS_NORMALIZE_TESTCASES = [
|
|||
address: {
|
||||
country: "us",
|
||||
"country-name": "unknown country name",
|
||||
name: "name",
|
||||
},
|
||||
expectedResult: {
|
||||
country: "US",
|
||||
"country-name": "United States",
|
||||
name: "name",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Has "country-name" and unknown "country"',
|
||||
address: {
|
||||
"given-name": "John", // Make sure it won't be an empty record.
|
||||
country: "AA",
|
||||
"country-name": "united states",
|
||||
name: "name",
|
||||
},
|
||||
expectedResult: {
|
||||
country: undefined,
|
||||
"country-name": undefined,
|
||||
country: "US",
|
||||
"country-name": "United States",
|
||||
name: "name",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'Has unsupported "country"',
|
||||
address: {
|
||||
"given-name": "John", // Make sure it won't be an empty record.
|
||||
country: "XX",
|
||||
name: "name",
|
||||
},
|
||||
expectedResult: {
|
||||
country: undefined,
|
||||
"country-name": undefined,
|
||||
country: "US",
|
||||
"country-name": "United States",
|
||||
name: "name",
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
@ -39,10 +39,10 @@ skip-if =
|
|||
[test_clearPopulatedForm.js]
|
||||
[test_collectFormFields.js]
|
||||
[test_createRecords.js]
|
||||
[test_creditCardRecords.js]
|
||||
skip-if =
|
||||
tsan # Times out, bug 1612707
|
||||
apple_silicon # bug 1729554
|
||||
[test_creditCardRecords.js]
|
||||
[test_extractLabelStrings.js]
|
||||
[test_findLabelElements.js]
|
||||
[test_getAdaptedProfiles.js]
|
||||
|
|
|
@ -465,7 +465,11 @@ export class FormAutofillParent extends JSWindowActorParent {
|
|||
const storage = lazy.gFormAutofillStorage.addresses;
|
||||
|
||||
// Make sure record is normalized before comparing with records in the storage
|
||||
storage._normalizeRecord(address.record);
|
||||
try {
|
||||
storage._normalizeRecord(address.record);
|
||||
} catch (_e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const newAddress = new lazy.AddressComponent(
|
||||
address.record,
|
||||
|
@ -524,7 +528,6 @@ export class FormAutofillParent extends JSWindowActorParent {
|
|||
return false;
|
||||
}
|
||||
|
||||
dump(`[Dimi]Save: ${JSON.stringify(newAddress.record)}\n`);
|
||||
return async () => {
|
||||
await lazy.FormAutofillPrompter.promptToSaveAddress(
|
||||
browser,
|
||||
|
@ -537,13 +540,14 @@ export class FormAutofillParent extends JSWindowActorParent {
|
|||
}
|
||||
|
||||
async _onCreditCardSubmit(creditCard, browser) {
|
||||
// Let's reset the credit card to empty, and then network auto-detect will
|
||||
// pick it up.
|
||||
delete creditCard.record["cc-type"];
|
||||
|
||||
const storage = lazy.gFormAutofillStorage.creditCards;
|
||||
|
||||
// Make sure record is normalized before comparing with records in the storage
|
||||
storage._normalizeRecord(creditCard.record);
|
||||
try {
|
||||
storage._normalizeRecord(creditCard.record);
|
||||
} catch (_e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the record alreay exists in the storage, don't bother showing the prompt
|
||||
const matchRecord = (
|
||||
|
|
|
@ -1383,7 +1383,7 @@ class AutofillRecords {
|
|||
_normalizeRecord(record, preserveEmptyFields = false) {
|
||||
this._normalizeFields(record);
|
||||
|
||||
for (let key in record) {
|
||||
for (const key in record) {
|
||||
if (!this.VALID_FIELDS.includes(key)) {
|
||||
// Though we allow unknown fields, certain fields are still protected
|
||||
// from being changed
|
||||
|
@ -1405,7 +1405,10 @@ class AutofillRecords {
|
|||
}
|
||||
}
|
||||
|
||||
if (!Object.keys(record).length) {
|
||||
const keys = Object.keys(record);
|
||||
// By default we ensure there is always a country field, so if this record
|
||||
// doesn't contain other fields, this is an empty record
|
||||
if (!keys.length || (keys.length == 1 && keys[0] == "country")) {
|
||||
throw new Error("Record contains no valid field.");
|
||||
}
|
||||
}
|
||||
|
@ -1609,13 +1612,13 @@ export class AddressesBase extends AutofillRecords {
|
|||
}
|
||||
|
||||
_normalizeFields(address) {
|
||||
this._normalizeName(address);
|
||||
this._normalizeAddress(address);
|
||||
this._normalizeCountry(address);
|
||||
this._normalizeTel(address);
|
||||
this._normalizeCountryFields(address);
|
||||
this._normalizeNameFields(address);
|
||||
this._normalizeAddressFields(address);
|
||||
this._normalizeTelFields(address);
|
||||
}
|
||||
|
||||
_normalizeName(address) {
|
||||
_normalizeNameFields(address) {
|
||||
if (address.name) {
|
||||
let nameParts = lazy.FormAutofillNameUtils.splitName(address.name);
|
||||
if (!address["given-name"] && nameParts.given) {
|
||||
|
@ -1631,7 +1634,7 @@ export class AddressesBase extends AutofillRecords {
|
|||
delete address.name;
|
||||
}
|
||||
|
||||
_normalizeAddress(address) {
|
||||
_normalizeAddressFields(address) {
|
||||
if (STREET_ADDRESS_COMPONENTS.some(c => !!address[c])) {
|
||||
// Treat "street-address" as "address-line1" if it contains only one line
|
||||
// and "address-line1" is omitted.
|
||||
|
@ -1656,16 +1659,13 @@ export class AddressesBase extends AutofillRecords {
|
|||
STREET_ADDRESS_COMPONENTS.forEach(c => delete address[c]);
|
||||
}
|
||||
|
||||
_normalizeCountry(address) {
|
||||
let country;
|
||||
|
||||
if (address.country) {
|
||||
country = address.country.toUpperCase();
|
||||
} else if (address["country-name"]) {
|
||||
country = lazy.FormAutofillUtils.identifyCountryCode(
|
||||
address["country-name"]
|
||||
);
|
||||
}
|
||||
_normalizeCountryFields(address) {
|
||||
// When we can't identify the country code, it is possible because that the region exists
|
||||
// in regionNames.properties but not in libaddressinput.
|
||||
const country =
|
||||
lazy.FormAutofillUtils.identifyCountryCode(
|
||||
address.country || address["country-name"]
|
||||
) || address.country;
|
||||
|
||||
// Only values included in the region list will be saved.
|
||||
let hasLocalizedName = false;
|
||||
|
@ -1681,13 +1681,13 @@ export class AddressesBase extends AutofillRecords {
|
|||
if (country && hasLocalizedName) {
|
||||
address.country = country;
|
||||
} else {
|
||||
delete address.country;
|
||||
address.country = FormAutofill.DEFAULT_REGION;
|
||||
}
|
||||
|
||||
delete address["country-name"];
|
||||
}
|
||||
|
||||
_normalizeTel(address) {
|
||||
_normalizeTelFields(address) {
|
||||
if (address.tel || TEL_COMPONENTS.some(c => !!address[c])) {
|
||||
lazy.FormAutofillUtils.compressTel(address);
|
||||
|
||||
|
@ -1838,12 +1838,13 @@ export class CreditCardsBase extends AutofillRecords {
|
|||
}
|
||||
|
||||
_normalizeFields(creditCard) {
|
||||
this._normalizeCCName(creditCard);
|
||||
this._normalizeCCNumber(creditCard);
|
||||
this._normalizeCCExpirationDate(creditCard);
|
||||
this._normalizeCCNameFields(creditCard);
|
||||
this._normalizeCCNumberFields(creditCard);
|
||||
this._normalizeCCExpirationDateFields(creditCard);
|
||||
this._normalizeCCTypeFields(creditCard);
|
||||
}
|
||||
|
||||
_normalizeCCName(creditCard) {
|
||||
_normalizeCCNameFields(creditCard) {
|
||||
if (
|
||||
creditCard["cc-given-name"] ||
|
||||
creditCard["cc-additional-name"] ||
|
||||
|
@ -1862,19 +1863,21 @@ export class CreditCardsBase extends AutofillRecords {
|
|||
delete creditCard["cc-family-name"];
|
||||
}
|
||||
|
||||
_normalizeCCNumber(creditCard) {
|
||||
_normalizeCCNumberFields(creditCard) {
|
||||
if (!("cc-number" in creditCard)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lazy.CreditCard.isValidNumber(creditCard["cc-number"])) {
|
||||
delete creditCard["cc-number"];
|
||||
return;
|
||||
}
|
||||
let card = new lazy.CreditCard({ number: creditCard["cc-number"] });
|
||||
|
||||
const card = new lazy.CreditCard({ number: creditCard["cc-number"] });
|
||||
creditCard["cc-number"] = card.number;
|
||||
}
|
||||
|
||||
_normalizeCCExpirationDate(creditCard) {
|
||||
_normalizeCCExpirationDateFields(creditCard) {
|
||||
let normalizedExpiration = lazy.CreditCard.normalizeExpiration({
|
||||
expirationMonth: creditCard["cc-exp-month"],
|
||||
expirationYear: creditCard["cc-exp-year"],
|
||||
|
@ -1893,6 +1896,12 @@ export class CreditCardsBase extends AutofillRecords {
|
|||
delete creditCard["cc-exp"];
|
||||
}
|
||||
|
||||
_normalizeCCTypeFields(creditCard) {
|
||||
// Let's overwrite the credit card type with auto-detect algorithm
|
||||
creditCard["cc-type"] =
|
||||
lazy.CreditCard.getType(creditCard["cc-number"]) ?? "";
|
||||
}
|
||||
|
||||
_validateFields(creditCard) {
|
||||
if (!creditCard["cc-number"]) {
|
||||
throw new Error("Missing/invalid cc-number");
|
||||
|
|
|
@ -98,15 +98,6 @@ export class FormAutofillSection {
|
|||
throw new TypeError("isRecordCreatable method must be overridden");
|
||||
}
|
||||
|
||||
/*
|
||||
* Override this method if any data for `createRecord` is needed to be
|
||||
* normalized before submitting the record.
|
||||
*
|
||||
* @param {Object} profile
|
||||
* A record for normalization.
|
||||
*/
|
||||
createNormalizedRecord(data) {}
|
||||
|
||||
/**
|
||||
* Override this method if the profile is needed to apply some transformers.
|
||||
*
|
||||
|
@ -636,7 +627,18 @@ export class FormAutofillSection {
|
|||
}
|
||||
});
|
||||
|
||||
this.createNormalizedRecord(data);
|
||||
const telFields = this.fieldDetails.filter(
|
||||
f => FormAutofillUtils.getCategoryFromFieldName(f.fieldName) == "tel"
|
||||
);
|
||||
if (
|
||||
telFields.length &&
|
||||
telFields.every(f => data.untouchedFields.includes(f.fieldName))
|
||||
) {
|
||||
// No need to verify it if none of related fields are modified after autofilling.
|
||||
if (!data.untouchedFields.includes("tel")) {
|
||||
data.untouchedFields.push("tel");
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isRecordCreatable(data.record)) {
|
||||
return null;
|
||||
|
@ -692,9 +694,12 @@ export class FormAutofillAddressSection extends FormAutofillSection {
|
|||
}
|
||||
|
||||
isRecordCreatable(record) {
|
||||
const country = FormAutofillUtils.identifyCountryCode(
|
||||
record.country || record["country-name"]
|
||||
);
|
||||
if (
|
||||
record.country &&
|
||||
!FormAutofill.isAutofillAddressesAvailableInCountry(record.country)
|
||||
country &&
|
||||
!FormAutofill.isAutofillAddressesAvailableInCountry(country)
|
||||
) {
|
||||
// We don't want to save data in the wrong fields due to not having proper
|
||||
// heuristic regexes in countries we don't yet support.
|
||||
|
@ -705,19 +710,21 @@ export class FormAutofillAddressSection extends FormAutofillSection {
|
|||
return false;
|
||||
}
|
||||
|
||||
let hasName = 0;
|
||||
let length = 0;
|
||||
for (let key of Object.keys(record)) {
|
||||
if (!record[key]) {
|
||||
continue;
|
||||
}
|
||||
if (FormAutofillUtils.getCategoryFromFieldName(key) == "name") {
|
||||
hasName = 1;
|
||||
continue;
|
||||
}
|
||||
length++;
|
||||
}
|
||||
return length + hasName >= FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD;
|
||||
// Multiple name or tel fields are treat as 1 field while countng whether
|
||||
// the number of fields exceed the valid address secton threshold
|
||||
const categories = Object.entries(record)
|
||||
.filter(e => !!e[1])
|
||||
.map(e => FormAutofillUtils.getCategoryFromFieldName(e[0]));
|
||||
|
||||
return (
|
||||
categories.reduce(
|
||||
(acc, category) =>
|
||||
["name", "tel"].includes(category) && acc.includes(category)
|
||||
? acc
|
||||
: [...acc, category],
|
||||
[]
|
||||
).length >= FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD
|
||||
);
|
||||
}
|
||||
|
||||
_getOneLineStreetAddress(address) {
|
||||
|
@ -851,53 +858,6 @@ export class FormAutofillAddressSection extends FormAutofillSection {
|
|||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
createNormalizedRecord(address) {
|
||||
if (!address) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Normalize Country
|
||||
if (address.record.country) {
|
||||
let detail = this.getFieldDetailByName("country");
|
||||
// Try identifying country field aggressively if it doesn't come from
|
||||
// @autocomplete.
|
||||
if (detail.reason != "autocomplete") {
|
||||
let countryCode = FormAutofillUtils.identifyCountryCode(
|
||||
address.record.country
|
||||
);
|
||||
if (countryCode) {
|
||||
address.record.country = countryCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize Tel
|
||||
FormAutofillUtils.compressTel(address.record);
|
||||
if (address.record.tel) {
|
||||
let allTelComponentsAreUntouched = Object.keys(address.record)
|
||||
.filter(
|
||||
field => FormAutofillUtils.getCategoryFromFieldName(field) == "tel"
|
||||
)
|
||||
.every(field => address.untouchedFields.includes(field));
|
||||
if (allTelComponentsAreUntouched) {
|
||||
// No need to verify it if none of related fields are modified after autofilling.
|
||||
if (!address.untouchedFields.includes("tel")) {
|
||||
address.untouchedFields.push("tel");
|
||||
}
|
||||
} else {
|
||||
let strippedNumber = address.record.tel.replace(/[\s\(\)-]/g, "");
|
||||
|
||||
// Remove "tel" if it contains invalid characters or the length of its
|
||||
// number part isn't between 5 and 15.
|
||||
// (The maximum length of a valid number in E.164 format is 15 digits
|
||||
// according to https://en.wikipedia.org/wiki/E.164 )
|
||||
if (!/^(\+?)[\da-zA-Z]{5,15}$/.test(strippedNumber)) {
|
||||
address.record.tel = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class FormAutofillCreditCardSection extends FormAutofillSection {
|
||||
|
@ -1309,27 +1269,4 @@ export class FormAutofillCreditCardSection extends FormAutofillSection {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
createNormalizedRecord(creditCard) {
|
||||
if (!creditCard?.record["cc-number"]) {
|
||||
return;
|
||||
}
|
||||
// Normalize cc-number
|
||||
creditCard.record["cc-number"] = lazy.CreditCard.normalizeCardNumber(
|
||||
creditCard.record["cc-number"]
|
||||
);
|
||||
|
||||
// Normalize cc-exp-month and cc-exp-year
|
||||
let { month, year } = lazy.CreditCard.normalizeExpiration({
|
||||
expirationString: creditCard.record["cc-exp"],
|
||||
expirationMonth: creditCard.record["cc-exp-month"],
|
||||
expirationYear: creditCard.record["cc-exp-year"],
|
||||
});
|
||||
if (month) {
|
||||
creditCard.record["cc-exp-month"] = month;
|
||||
}
|
||||
if (year) {
|
||||
creditCard.record["cc-exp-year"] = year;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -270,7 +270,7 @@ FormAutofillUtils = {
|
|||
},
|
||||
|
||||
isCCNumber(ccNumber) {
|
||||
return lazy.CreditCard.isValidNumber(ccNumber);
|
||||
return ccNumber && lazy.CreditCard.isValidNumber(ccNumber);
|
||||
},
|
||||
|
||||
ensureLoggedIn(promptMessage) {
|
||||
|
|
|
@ -189,9 +189,9 @@ export class CreditCard {
|
|||
}
|
||||
|
||||
// Remove dashes and whitespace
|
||||
let number = this._number.replace(/[\-\s]/g, "");
|
||||
const number = CreditCard.normalizeCardNumber(this._number);
|
||||
|
||||
let len = number.length;
|
||||
const len = number.length;
|
||||
if (len < 12 || len > 19) {
|
||||
return false;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче