зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1847888 - P3. Add testcases r=mtigley,joschmidt,credential-management-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D190583
This commit is contained in:
Родитель
11da4086b3
Коммит
b2897a17f3
|
@ -16,4 +16,10 @@ support-files = [
|
|||
|
||||
["browser_address_doorhanger_tel.js"]
|
||||
|
||||
["browser_address_doorhanger_ui.js"]
|
||||
|
||||
["browser_address_telemetry.js"]
|
||||
|
||||
["browser_edit_address_doorhanger_display.js"]
|
||||
|
||||
["browser_edit_address_doorhanger_save_edited_fields.js"]
|
||||
|
|
|
@ -12,7 +12,10 @@ async function expectSavedAddresses(expectedCount) {
|
|||
|
||||
add_setup(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["extensions.formautofill.addresses.capture.v2.enabled", true]],
|
||||
set: [
|
||||
["extensions.formautofill.addresses.capture.v2.enabled", true],
|
||||
["extensions.formautofill.addresses.supported", "on"],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -137,11 +140,8 @@ add_task(async function test_doorhanger_not_shown_when_autofill_untouched() {
|
|||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: ADDRESS_FORM_URL },
|
||||
async function (browser) {
|
||||
await sleep(1000);
|
||||
await openPopupOn(browser, "form #given-name");
|
||||
await sleep(1000);
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await sleep(1000);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
await waitForAutofill(
|
||||
browser,
|
||||
|
@ -154,7 +154,6 @@ add_task(async function test_doorhanger_not_shown_when_autofill_untouched() {
|
|||
form.querySelector("input[type=submit]").click();
|
||||
});
|
||||
|
||||
await sleep(1000);
|
||||
is(PopupNotifications.panel.state, "closed", "Doorhanger is hidden");
|
||||
}
|
||||
);
|
||||
|
@ -183,7 +182,6 @@ add_task(async function test_doorhanger_not_shown_when_fill_duplicate() {
|
|||
},
|
||||
});
|
||||
|
||||
await sleep(1000);
|
||||
is(PopupNotifications.panel.state, "closed", "Doorhanger is hidden");
|
||||
}
|
||||
);
|
||||
|
@ -228,7 +226,6 @@ add_task(
|
|||
},
|
||||
});
|
||||
|
||||
await sleep(1000);
|
||||
is(PopupNotifications.panel.state, "closed", "Doorhanger is hidden");
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
"use strict";
|
||||
|
||||
const { FormAutofill } = ChromeUtils.importESModule(
|
||||
"resource://autofill/FormAutofill.sys.mjs"
|
||||
);
|
||||
|
||||
async function expectSavedAddresses(expectedCount) {
|
||||
const addresses = await getAddresses();
|
||||
is(
|
||||
addresses.length,
|
||||
expectedCount,
|
||||
`${addresses.length} address in the storage`
|
||||
);
|
||||
return addresses;
|
||||
}
|
||||
|
||||
function verifyDoorhangerContent(saved, removed = {}) {
|
||||
const rows = [
|
||||
...getNotification().querySelectorAll(`.address-save-update-row-container`),
|
||||
];
|
||||
|
||||
let texts = rows.reduce((acc, cur) => acc + cur.textContent, "");
|
||||
for (const text of Object.values(saved)) {
|
||||
ok(texts.includes(text), `Show ${text} in the doorhanger`);
|
||||
texts = texts.replace(text, "");
|
||||
}
|
||||
for (const text of Object.values(removed)) {
|
||||
ok(texts.includes(text), `Show ${text} in the doorhanger (removed)`);
|
||||
texts = texts.replace(text, "");
|
||||
}
|
||||
is(texts.trim(), "", `Doorhanger shows all the submitted data`);
|
||||
}
|
||||
|
||||
function checkVisibility(element) {
|
||||
return element.checkVisibility({
|
||||
checkOpacity: true,
|
||||
checkVisibilityCSS: true,
|
||||
});
|
||||
}
|
||||
|
||||
function recordToFormSelector(record) {
|
||||
let obj = {};
|
||||
for (const [key, value] of Object.entries(record)) {
|
||||
obj[`#${key}`] = value;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
add_setup(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["extensions.formautofill.addresses.capture.v2.enabled", true],
|
||||
["extensions.formautofill.addresses.supported", "on"],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
async function showDoorhanger(browser, values = null) {
|
||||
const defaultValues = {
|
||||
"#given-name": "John",
|
||||
"#family-name": "Doe",
|
||||
"#organization": "Mozilla",
|
||||
"#street-address": "123 Sesame Street",
|
||||
};
|
||||
|
||||
const onPopupShown = waitForPopupShown();
|
||||
const promise = BrowserTestUtils.browserLoaded(browser);
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#given-name",
|
||||
newValues: values ?? defaultValues,
|
||||
});
|
||||
await promise;
|
||||
await onPopupShown;
|
||||
}
|
||||
|
||||
// Save address doorhanger should show description when users has no saved address
|
||||
add_task(async function test_save_doorhanger_show_description() {
|
||||
await expectSavedAddresses(0);
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: ADDRESS_FORM_URL },
|
||||
async function (browser) {
|
||||
await showDoorhanger(browser);
|
||||
|
||||
const header = AutofillDoorhanger.header(getNotification());
|
||||
is(checkVisibility(header), true, "Should always show header");
|
||||
|
||||
const description = AutofillDoorhanger.description(getNotification());
|
||||
is(
|
||||
checkVisibility(description),
|
||||
true,
|
||||
"Should show description when this is the first address saved"
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Save address doorhanger should not show description when users has at least one saved address
|
||||
add_task(async function test_save_doorhanger_hide_description() {
|
||||
await setStorage(TEST_ADDRESS_1);
|
||||
await expectSavedAddresses(1);
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: ADDRESS_FORM_URL },
|
||||
async function (browser) {
|
||||
await showDoorhanger(browser);
|
||||
|
||||
const header = AutofillDoorhanger.header(getNotification());
|
||||
is(checkVisibility(header), true, "Should always show header");
|
||||
|
||||
const description = AutofillDoorhanger.description(getNotification());
|
||||
is(
|
||||
checkVisibility(description),
|
||||
false,
|
||||
"Should not show description when there is at least one saved address"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
await removeAllRecords();
|
||||
});
|
||||
|
||||
// Test open edit address popup and then click "learn more" button
|
||||
add_task(async function test_click_learn_more_button_in_edit_doorhanger() {
|
||||
await expectSavedAddresses(0);
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: ADDRESS_FORM_URL },
|
||||
async function (browser) {
|
||||
await showDoorhanger(browser);
|
||||
|
||||
let tabOpenPromise = BrowserTestUtils.waitForNewTab(gBrowser, url =>
|
||||
url.endsWith(AddressSaveDoorhanger.learnMoreURL)
|
||||
);
|
||||
await clickAddressDoorhangerButton(
|
||||
ADDRESS_MENU_BUTTON,
|
||||
ADDRESS_MENU_LEARN_MORE
|
||||
);
|
||||
const tab = await tabOpenPromise;
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_click_address_setting_button_in_edit_doorhanger() {
|
||||
await expectSavedAddresses(0);
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: ADDRESS_FORM_URL },
|
||||
async function (browser) {
|
||||
await showDoorhanger(browser);
|
||||
|
||||
let tabOpenPromise = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
`about:preferences#${AddressSaveDoorhanger.preferenceURL}`
|
||||
);
|
||||
await clickAddressDoorhangerButton(
|
||||
ADDRESS_MENU_BUTTON,
|
||||
ADDRESS_MENU_PREFENCE
|
||||
);
|
||||
const tab = await tabOpenPromise;
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_address_display_in_save_doorhanger() {
|
||||
await expectSavedAddresses(0);
|
||||
|
||||
const TESTS = [
|
||||
{
|
||||
description: "Test submit a form without email and tel fields",
|
||||
form: {
|
||||
"#family-name": "Doe",
|
||||
"#organization": "Mozilla",
|
||||
"#street-address": "123 Sesame Street",
|
||||
},
|
||||
expectedSectionCount: 1,
|
||||
},
|
||||
{
|
||||
description: "Test submit a form with email field",
|
||||
form: {
|
||||
"#given-name": "John",
|
||||
"#organization": "Mozilla",
|
||||
"#street-address": "123 Sesame Street",
|
||||
"#email": "test@mozilla.org",
|
||||
},
|
||||
expectedSectionCount: 2,
|
||||
},
|
||||
{
|
||||
description: "Test submit a form with tel field",
|
||||
form: {
|
||||
"#given-name": "John",
|
||||
"#family-name": "Doe",
|
||||
"#organization": "Mozilla",
|
||||
"#street-address": "123 Sesame Street",
|
||||
"#tel": "+13453453456",
|
||||
},
|
||||
expectedSectionCount: 2,
|
||||
},
|
||||
];
|
||||
|
||||
for (const TEST of TESTS) {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: ADDRESS_FORM_URL },
|
||||
async function (browser) {
|
||||
info(TEST.description);
|
||||
await showDoorhanger(browser, TEST.form);
|
||||
|
||||
is(
|
||||
getNotification().querySelectorAll(
|
||||
`.address-save-update-row-container`
|
||||
).length,
|
||||
TEST.expectedSectionCount,
|
||||
`Should have ${TEST.expectedSectionCount} address section`
|
||||
);
|
||||
|
||||
// When the form has no country field, doorhanger shows the default region
|
||||
verifyDoorhangerContent({
|
||||
...TEST.form,
|
||||
country: FormAutofill.DEFAULT_REGION,
|
||||
});
|
||||
|
||||
await clickAddressDoorhangerButton(SECONDARY_BUTTON);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
await removeAllRecords();
|
||||
});
|
||||
|
||||
add_task(async function test_show_added_text_in_update_doorhanger() {
|
||||
await setStorage(TEST_ADDRESS_2);
|
||||
await expectSavedAddresses(1);
|
||||
|
||||
const form = {
|
||||
...TEST_ADDRESS_2,
|
||||
|
||||
email: "test@mozilla.org", // Add email field
|
||||
"given-name": TEST_ADDRESS_2["given-name"] + " Doe", // Append
|
||||
"street-address": TEST_ADDRESS_2["street-address"] + " 4F", // Append
|
||||
};
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: ADDRESS_FORM_URL },
|
||||
async function (browser) {
|
||||
await showDoorhanger(browser, recordToFormSelector(form));
|
||||
|
||||
// When the form has no country field, doorhanger shows the default region
|
||||
verifyDoorhangerContent({
|
||||
...form,
|
||||
country: FormAutofill.DEFAULT_REGION,
|
||||
});
|
||||
|
||||
await clickAddressDoorhangerButton(SECONDARY_BUTTON);
|
||||
}
|
||||
);
|
||||
|
||||
await removeAllRecords();
|
||||
});
|
||||
|
||||
add_task(async function test_show_removed_text_in_update_doorhanger() {
|
||||
const SAVED_ADDRESS = {
|
||||
...TEST_ADDRESS_2,
|
||||
organization: "Mozilla",
|
||||
};
|
||||
await setStorage(SAVED_ADDRESS);
|
||||
await expectSavedAddresses(1);
|
||||
|
||||
// We will ask whether users would like to update "Mozilla" to "mozilla"
|
||||
const form = {
|
||||
...SAVED_ADDRESS,
|
||||
|
||||
organization: SAVED_ADDRESS.organization.toLowerCase(),
|
||||
};
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: ADDRESS_FORM_URL },
|
||||
async function (browser) {
|
||||
await showDoorhanger(browser, recordToFormSelector(form));
|
||||
|
||||
// When the form has no country field, doorhanger shows the default region
|
||||
verifyDoorhangerContent(
|
||||
{ ...form, country: FormAutofill.DEFAULT_REGION },
|
||||
{ organization: SAVED_ADDRESS.organization }
|
||||
);
|
||||
|
||||
await clickAddressDoorhangerButton(SECONDARY_BUTTON);
|
||||
}
|
||||
);
|
||||
|
||||
await removeAllRecords();
|
||||
});
|
|
@ -1,5 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
const { TelemetryTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/TelemetryTestUtils.sys.mjs"
|
||||
);
|
||||
|
@ -8,11 +10,6 @@ const { AddressTelemetry } = ChromeUtils.importESModule(
|
|||
"resource://autofill/AutofillTelemetry.sys.mjs"
|
||||
);
|
||||
|
||||
// Preference definitions
|
||||
const ENABLED_PREF = ENABLED_AUTOFILL_ADDRESSES_PREF;
|
||||
const AVAILABLE_PREF = AUTOFILL_ADDRESSES_AVAILABLE_PREF;
|
||||
const CAPTURE_ENABLE_PREF = ENABLED_AUTOFILL_ADDRESSES_CAPTURE_PREF;
|
||||
|
||||
// Telemetry definitions
|
||||
const EVENT_CATEGORY = "address";
|
||||
|
||||
|
@ -260,9 +257,9 @@ async function openTabAndUseAutofillProfile(
|
|||
add_setup(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[ENABLED_PREF, true],
|
||||
[AVAILABLE_PREF, "on"],
|
||||
[CAPTURE_ENABLE_PREF, true],
|
||||
[ENABLED_AUTOFILL_ADDRESSES_PREF, true],
|
||||
[AUTOFILL_ADDRESSES_AVAILABLE_PREF, "on"],
|
||||
["extensions.formautofill.addresses.capture.v2.enabled", true],
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -349,9 +346,6 @@ add_task(async function test_popup_opened_form_without_autocomplete() {
|
|||
});
|
||||
|
||||
add_task(async function test_submit_autofill_profile_new() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["extensions.formautofill.addresses.capture.v2.enabled", true]],
|
||||
});
|
||||
async function test_per_command(
|
||||
command,
|
||||
idx,
|
||||
|
@ -405,16 +399,12 @@ add_task(async function test_submit_autofill_profile_new() {
|
|||
...formArgs("submitted", {}, fields, "user_filled", "unavailable"),
|
||||
];
|
||||
|
||||
// FTU
|
||||
await test_per_command(MAIN_BUTTON, undefined, { 1: 1 }, 1);
|
||||
await assertTelemetry(expected_content, [
|
||||
[EVENT_CATEGORY, "show", "capture_doorhanger"],
|
||||
[EVENT_CATEGORY, "pref", "capture_doorhanger"],
|
||||
[EVENT_CATEGORY, "save", "capture_doorhanger"],
|
||||
]);
|
||||
|
||||
// Need to close preference tab
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
|
||||
TelemetryTestUtils.assertScalar(
|
||||
TelemetryTestUtils.getProcessScalars("content"),
|
||||
SCALAR_DETECTED_SECTION_COUNT,
|
||||
|
@ -486,7 +476,7 @@ add_task(async function test_submit_autofill_profile_update() {
|
|||
useCount
|
||||
);
|
||||
|
||||
SpecialPowers.clearUserPref(ENABLED_PREF);
|
||||
SpecialPowers.clearUserPref(ENABLED_AUTOFILL_ADDRESSES_PREF);
|
||||
|
||||
await removeAllRecords();
|
||||
}
|
||||
|
@ -529,10 +519,10 @@ add_task(async function test_submit_autofill_profile_update() {
|
|||
[EVENT_CATEGORY, "update", "update_doorhanger"],
|
||||
]);
|
||||
|
||||
await test_per_command(SECONDARY_BUTTON, undefined, { 0: 1, 1: 1 }, 2);
|
||||
await test_per_command(SECONDARY_BUTTON, undefined, { 0: 1 });
|
||||
await assertTelemetry(expected_content, [
|
||||
[EVENT_CATEGORY, "show", "update_doorhanger"],
|
||||
[EVENT_CATEGORY, "save", "update_doorhanger"],
|
||||
[EVENT_CATEGORY, "cancel", "update_doorhanger"],
|
||||
]);
|
||||
|
||||
await removeAllRecords();
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
"use strict";
|
||||
|
||||
async function expectSavedAddresses(expectedCount) {
|
||||
const addresses = await getAddresses();
|
||||
is(
|
||||
addresses.length,
|
||||
expectedCount,
|
||||
`${addresses.length} address in the storage`
|
||||
);
|
||||
return addresses;
|
||||
}
|
||||
|
||||
function recordToFormSelector(record) {
|
||||
let obj = {};
|
||||
for (const [key, value] of Object.entries(record)) {
|
||||
obj[`#${key}`] = value;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
add_setup(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["extensions.formautofill.addresses.capture.v2.enabled", true],
|
||||
["extensions.formautofill.addresses.supported", "on"],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
// Test different scenarios when we change something in the edit address dorhanger
|
||||
add_task(async function test_save_edited_fields() {
|
||||
await expectSavedAddresses(0);
|
||||
|
||||
const initRecord = {
|
||||
"given-name": "John",
|
||||
"family-name": "Doe",
|
||||
organization: "Mozilla",
|
||||
"street-address": "123 Sesame Street",
|
||||
tel: "+13453453456",
|
||||
};
|
||||
|
||||
const TESTS = [
|
||||
{
|
||||
description: "adding the email field",
|
||||
editedFields: {
|
||||
email: "test@mozilla.org",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "changing the given-name field",
|
||||
editedFields: {
|
||||
name: "Jane",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "appending the street-address field",
|
||||
editedFields: {
|
||||
"street-address": initRecord["street-address"] + " 4F",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "removing some fields",
|
||||
editedFields: {
|
||||
name: "",
|
||||
tel: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "doing all kinds of stuff",
|
||||
editedFields: {
|
||||
organization: initRecord.organization.toLowerCase(),
|
||||
"address-level1": "CA",
|
||||
tel: "",
|
||||
"street-address": initRecord["street-address"] + " Apt.6",
|
||||
name: "Jane Doe",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (const TEST of TESTS) {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: ADDRESS_FORM_URL },
|
||||
async function (browser) {
|
||||
info(`Test ${TEST.description}`);
|
||||
|
||||
const onSavePopupShown = waitForPopupShown();
|
||||
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#given-name",
|
||||
newValues: recordToFormSelector(initRecord),
|
||||
});
|
||||
|
||||
await onSavePopupShown;
|
||||
|
||||
const onEditPopupShown = waitForPopupShown();
|
||||
await clickAddressDoorhangerButton(EDIT_ADDRESS_BUTTON);
|
||||
await onEditPopupShown;
|
||||
fillEditDoorhanger(TEST.editedFields);
|
||||
|
||||
await clickAddressDoorhangerButton(MAIN_BUTTON);
|
||||
}
|
||||
);
|
||||
|
||||
const expectedRecord = normalizeAddressFields({
|
||||
...initRecord,
|
||||
...TEST.editedFields,
|
||||
});
|
||||
|
||||
const addresses = await expectSavedAddresses(1);
|
||||
for (const [key, value] of Object.entries(expectedRecord)) {
|
||||
is(addresses[0][key] ?? "", value, `${key} field is saved`);
|
||||
}
|
||||
|
||||
await removeAllRecords();
|
||||
}
|
||||
});
|
||||
|
||||
// This test tests edit doorhanger "save" & "cancel" buttons work correctly
|
||||
// when the edit doorhanger is triggered in an save doorhanger
|
||||
add_task(async function test_edit_doorhanger_triggered_by_save_doorhanger() {
|
||||
for (const CLICKED_BUTTON of [MAIN_BUTTON, SECONDARY_BUTTON]) {
|
||||
await expectSavedAddresses(0);
|
||||
|
||||
const initRecord = {
|
||||
"given-name": "John",
|
||||
"family-name": "Doe",
|
||||
organization: "Mozilla",
|
||||
"street-address": "123 Sesame Street",
|
||||
tel: "+13453453456",
|
||||
};
|
||||
|
||||
const editRecord = {
|
||||
email: "test@mozilla.org",
|
||||
};
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: ADDRESS_FORM_URL },
|
||||
async browser => {
|
||||
info(
|
||||
`Test clicking ${CLICKED_BUTTON == MAIN_BUTTON ? "save" : "cancel"}`
|
||||
);
|
||||
const onSavePopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#given-name",
|
||||
newValues: recordToFormSelector(initRecord),
|
||||
});
|
||||
await onSavePopupShown;
|
||||
|
||||
const onEditPopupShown = waitForPopupShown();
|
||||
await clickAddressDoorhangerButton(EDIT_ADDRESS_BUTTON);
|
||||
await onEditPopupShown;
|
||||
fillEditDoorhanger(editRecord);
|
||||
|
||||
await clickAddressDoorhangerButton(CLICKED_BUTTON);
|
||||
}
|
||||
);
|
||||
|
||||
await expectSavedAddresses(CLICKED_BUTTON == MAIN_BUTTON ? 1 : 0);
|
||||
await removeAllRecords();
|
||||
}
|
||||
});
|
||||
|
||||
// This test tests edit doorhanger "save" & "cancel" buttons work correctly
|
||||
// when the edit doorhanger is triggered in an update doorhnager
|
||||
add_task(async function test_edit_doorhanger_triggered_by_update_doorhanger() {
|
||||
for (const CLICKED_BUTTON of [MAIN_BUTTON, SECONDARY_BUTTON]) {
|
||||
// TEST_ADDRESS_2 doesn't contain email field
|
||||
await setStorage(TEST_ADDRESS_2);
|
||||
await expectSavedAddresses(1);
|
||||
|
||||
const initRecord = {
|
||||
"given-name": TEST_ADDRESS_2["given-name"],
|
||||
"street-address": TEST_ADDRESS_2["street-address"],
|
||||
country: TEST_ADDRESS_2.country,
|
||||
email: "test@mozilla.org",
|
||||
};
|
||||
|
||||
const editRecord = {
|
||||
email: "test@mozilla.org",
|
||||
};
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: ADDRESS_FORM_URL },
|
||||
async browser => {
|
||||
info(
|
||||
`Test clicking ${CLICKED_BUTTON == MAIN_BUTTON ? "save" : "cancel"}`
|
||||
);
|
||||
const onUpdatePopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#given-name",
|
||||
newValues: recordToFormSelector(initRecord),
|
||||
});
|
||||
await onUpdatePopupShown;
|
||||
|
||||
const onEditPopupShown = waitForPopupShown();
|
||||
await clickAddressDoorhangerButton(EDIT_ADDRESS_BUTTON);
|
||||
await onEditPopupShown;
|
||||
fillEditDoorhanger(editRecord);
|
||||
|
||||
await clickAddressDoorhangerButton(CLICKED_BUTTON);
|
||||
}
|
||||
);
|
||||
|
||||
const addresses = await expectSavedAddresses(1);
|
||||
const expectedRecord =
|
||||
CLICKED_BUTTON == MAIN_BUTTON
|
||||
? { ...initRecord, ...editRecord }
|
||||
: TEST_ADDRESS_2;
|
||||
|
||||
for (const [key, value] of Object.entries(expectedRecord)) {
|
||||
is(addresses[0][key] ?? "", value, `${key} field is saved`);
|
||||
}
|
||||
|
||||
await removeAllRecords();
|
||||
}
|
||||
});
|
|
@ -0,0 +1,116 @@
|
|||
"use strict";
|
||||
|
||||
const SUBMIT_RECORD = {
|
||||
"given-name": "John",
|
||||
"family-name": "Doe",
|
||||
organization: "Mozilla",
|
||||
"street-address": "123 Sesame Street",
|
||||
tel: "+13453453456",
|
||||
};
|
||||
|
||||
const TEST_CASE = [
|
||||
{
|
||||
description: "adding the email field",
|
||||
editedFields: {
|
||||
email: "test@mozilla.org",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "changing the given-name field",
|
||||
editedFields: {
|
||||
name: "Jane",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "appending the street-address field",
|
||||
editedFields: {
|
||||
"street-address": SUBMIT_RECORD["street-address"] + " 4F",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "removing some fields",
|
||||
editedFields: {
|
||||
name: "",
|
||||
tel: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "doing all kinds of stuff",
|
||||
editedFields: {
|
||||
organization: SUBMIT_RECORD.organization.toLowerCase(),
|
||||
"address-level1": "CA",
|
||||
tel: "",
|
||||
"street-address": SUBMIT_RECORD["street-address"] + " Apt.6",
|
||||
name: "Jane Doe",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
async function expectSavedAddresses(expectedCount) {
|
||||
const addresses = await getAddresses();
|
||||
is(
|
||||
addresses.length,
|
||||
expectedCount,
|
||||
`${addresses.length} address in the storage`
|
||||
);
|
||||
return addresses;
|
||||
}
|
||||
|
||||
function recordToFormSelector(record) {
|
||||
let obj = {};
|
||||
for (const [key, value] of Object.entries(record)) {
|
||||
obj[`#${key}`] = value;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
add_setup(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["extensions.formautofill.addresses.capture.v2.enabled", true],
|
||||
["extensions.formautofill.addresses.supported", "on"],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
// Test different scenarios when we change something in the edit address dorhanger
|
||||
add_task(async function test_save_edited_fields() {
|
||||
await expectSavedAddresses(0);
|
||||
|
||||
for (const TEST of TEST_CASE) {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: ADDRESS_FORM_URL },
|
||||
async function (browser) {
|
||||
info(`Test ${TEST.description}`);
|
||||
|
||||
let onPopupShown = waitForPopupShown();
|
||||
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#given-name",
|
||||
newValues: recordToFormSelector(SUBMIT_RECORD),
|
||||
});
|
||||
|
||||
await onPopupShown;
|
||||
|
||||
onPopupShown = waitForPopupShown();
|
||||
await clickAddressDoorhangerButton(EDIT_ADDRESS_BUTTON);
|
||||
await onPopupShown;
|
||||
fillEditDoorhanger(TEST.editedFields);
|
||||
|
||||
await clickAddressDoorhangerButton(MAIN_BUTTON);
|
||||
}
|
||||
);
|
||||
|
||||
const expectedRecord = normalizeAddressFields({
|
||||
...SUBMIT_RECORD,
|
||||
...TEST.editedFields,
|
||||
});
|
||||
|
||||
const addresses = await expectSavedAddresses(1);
|
||||
for (const [key, value] of Object.entries(expectedRecord)) {
|
||||
is(addresses[0][key] ?? "", value, `${key} field is saved`);
|
||||
}
|
||||
|
||||
await removeAllRecords();
|
||||
}
|
||||
});
|
|
@ -48,6 +48,3 @@ skip-if = [
|
|||
["browser_remoteiframe.js"]
|
||||
|
||||
["browser_submission_in_private_mode.js"]
|
||||
|
||||
["browser_update_doorhanger.js"]
|
||||
skip-if = ["true"] # bug 1426981 # Bug 1445538
|
||||
|
|
|
@ -82,6 +82,8 @@ add_task(async function test_saveAddress() {
|
|||
"VK_TAB",
|
||||
TEST_ADDRESS_1["family-name"],
|
||||
"VK_TAB",
|
||||
TEST_ADDRESS_1.organization,
|
||||
"VK_TAB",
|
||||
TEST_ADDRESS_1["street-address"],
|
||||
"VK_TAB",
|
||||
TEST_ADDRESS_1["address-level2"],
|
||||
|
@ -90,8 +92,6 @@ add_task(async function test_saveAddress() {
|
|||
"VK_TAB",
|
||||
TEST_ADDRESS_1["postal-code"],
|
||||
"VK_TAB",
|
||||
TEST_ADDRESS_1.organization,
|
||||
"VK_TAB",
|
||||
// TEST_ADDRESS_1.country, // Country is already US
|
||||
"VK_TAB",
|
||||
TEST_ADDRESS_1.tel,
|
||||
|
|
|
@ -1,189 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Note that this testcase is built based on the assumption that subtests are
|
||||
* run in order. So if you're going to add a new subtest, please add it in the end.
|
||||
*/
|
||||
|
||||
add_setup(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["extensions.formautofill.addresses.capture.enabled", true]],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_update_address() {
|
||||
await setStorage(TEST_ADDRESS_1);
|
||||
let addresses = await getAddresses();
|
||||
is(addresses.length, 1, "1 address in storage");
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: FORM_URL },
|
||||
async function (browser) {
|
||||
// Autofill address fields
|
||||
await openPopupOn(browser, "form #organization");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
await waitForAutofill(browser, "#tel", addresses[0].tel);
|
||||
|
||||
// Update address fields and submit
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#organization",
|
||||
newValues: {
|
||||
"#organization": "Mozilla",
|
||||
},
|
||||
});
|
||||
|
||||
await onPopupShown;
|
||||
|
||||
// Choose to update address by doorhanger
|
||||
let onUpdated = waitForStorageChangedEvents("update");
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
await onUpdated;
|
||||
}
|
||||
);
|
||||
|
||||
addresses = await getAddresses();
|
||||
is(addresses.length, 1, "Still 1 address in storage");
|
||||
is(addresses[0].organization, "Mozilla", "Verify the organization field");
|
||||
});
|
||||
|
||||
add_task(async function test_create_new_address() {
|
||||
let addresses = await getAddresses();
|
||||
is(addresses.length, 1, "1 address in storage");
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: FORM_URL },
|
||||
async function (browser) {
|
||||
// Autofill address fields
|
||||
await openPopupOn(browser, "form #tel");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
await waitForAutofill(browser, "#tel", addresses[0].tel);
|
||||
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#tel",
|
||||
newValues: {
|
||||
"#tel": "+1234567890",
|
||||
},
|
||||
});
|
||||
|
||||
await onPopupShown;
|
||||
|
||||
// Choose to add address by doorhanger
|
||||
let onAdded = waitForStorageChangedEvents("add");
|
||||
await clickDoorhangerButton(SECONDARY_BUTTON);
|
||||
await onAdded;
|
||||
}
|
||||
);
|
||||
|
||||
addresses = await getAddresses();
|
||||
is(addresses.length, 2, "2 addresses in storage");
|
||||
is(addresses[1].tel, "+1234567890", "Verify the tel field");
|
||||
});
|
||||
|
||||
add_task(async function test_create_new_address_merge() {
|
||||
let addresses = await getAddresses();
|
||||
is(addresses.length, 2, "2 addresses in storage");
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: FORM_URL },
|
||||
async function (browser) {
|
||||
await openPopupOn(browser, "form #tel");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
await waitForAutofill(browser, "#tel", addresses[1].tel);
|
||||
|
||||
// Choose the latest address and revert to the original phone number
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#tel",
|
||||
newValues: {
|
||||
"#tel": "+16172535702",
|
||||
},
|
||||
});
|
||||
|
||||
await onPopupShown;
|
||||
await clickDoorhangerButton(SECONDARY_BUTTON);
|
||||
}
|
||||
);
|
||||
|
||||
addresses = await getAddresses();
|
||||
is(addresses.length, 2, "Still 2 addresses in storage");
|
||||
});
|
||||
|
||||
add_task(async function test_submit_untouched_fields() {
|
||||
let addresses = await getAddresses();
|
||||
is(addresses.length, 2, "2 addresses in storage");
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: FORM_URL },
|
||||
async function (browser) {
|
||||
await openPopupOn(browser, "form #organization");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
await waitForAutofill(browser, "#tel", addresses[0].tel);
|
||||
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await SpecialPowers.spawn(browser, [], async function () {
|
||||
let form = content.document.getElementById("form");
|
||||
let tel = form.querySelector("#tel");
|
||||
tel.value = "12345"; // ".value" won't change the highlight status.
|
||||
});
|
||||
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
focusSelector: "#tel",
|
||||
newValues: {
|
||||
"#organization": "Organization",
|
||||
},
|
||||
});
|
||||
await onPopupShown;
|
||||
|
||||
let onUpdated = waitForStorageChangedEvents("update");
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
await onUpdated;
|
||||
}
|
||||
);
|
||||
|
||||
addresses = await getAddresses();
|
||||
is(addresses.length, 2, "Still 2 addresses in storage");
|
||||
is(addresses[0].organization, "Organization", "organization should change");
|
||||
is(addresses[0].tel, "+16172535702", "tel should remain unchanged");
|
||||
});
|
||||
|
||||
add_task(async function test_submit_reduced_fields() {
|
||||
let addresses = await getAddresses();
|
||||
is(addresses.length, 2, "2 addresses in storage");
|
||||
|
||||
let url = BASE_URL + "autocomplete_simple_basic.html";
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url },
|
||||
async function (browser) {
|
||||
await openPopupOn(browser, "form#simple input[name=tel]");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
await waitForAutofill(browser, "form #simple_tel", "6172535702");
|
||||
|
||||
let onPopupShown = waitForPopupShown();
|
||||
await focusUpdateSubmitForm(browser, {
|
||||
formSelector: "form#simple",
|
||||
focusSelector: "form #simple_tel",
|
||||
newValues: {
|
||||
"input[name=tel]": "123456789",
|
||||
},
|
||||
});
|
||||
|
||||
await onPopupShown;
|
||||
|
||||
let onUpdated = waitForStorageChangedEvents("update");
|
||||
await clickDoorhangerButton(MAIN_BUTTON);
|
||||
await onUpdated;
|
||||
}
|
||||
);
|
||||
|
||||
addresses = await getAddresses();
|
||||
is(addresses.length, 2, "Still 2 addresses in storage");
|
||||
is(addresses[0].tel, "123456789", "tel should should be changed");
|
||||
is(addresses[0]["postal-code"], "02139", "postal code should be kept");
|
||||
});
|
|
@ -11,6 +11,15 @@ const { FormAutofillParent } = ChromeUtils.importESModule(
|
|||
"resource://autofill/FormAutofillParent.sys.mjs"
|
||||
);
|
||||
|
||||
const { AutofillDoorhanger, AddressEditDoorhanger, AddressSaveDoorhanger } =
|
||||
ChromeUtils.importESModule(
|
||||
"resource://autofill/FormAutofillPrompter.sys.mjs"
|
||||
);
|
||||
|
||||
const { FormAutofillNameUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/shared/FormAutofillNameUtils.sys.mjs"
|
||||
);
|
||||
|
||||
const MANAGE_ADDRESSES_DIALOG_URL =
|
||||
"chrome://formautofill/content/manageAddresses.xhtml";
|
||||
const MANAGE_CREDIT_CARDS_DIALOG_URL =
|
||||
|
@ -185,6 +194,10 @@ const TEST_CREDIT_CARD_5 = {
|
|||
const MAIN_BUTTON = "button";
|
||||
const SECONDARY_BUTTON = "secondaryButton";
|
||||
const MENU_BUTTON = "menubutton";
|
||||
const EDIT_ADDRESS_BUTTON = "edit";
|
||||
const ADDRESS_MENU_BUTTON = "addressMenuButton";
|
||||
const ADDRESS_MENU_LEARN_MORE = "learnMore";
|
||||
const ADDRESS_MENU_PREFENCE = "preference";
|
||||
|
||||
/**
|
||||
* Collection of timeouts that are used to ensure something should not happen.
|
||||
|
@ -715,39 +728,66 @@ function waitForPopupShown() {
|
|||
/**
|
||||
* Clicks the popup notification button and wait for popup hidden.
|
||||
*
|
||||
* @param {string} button The button type in popup notification.
|
||||
* @param {string} buttonType The button type in popup notification.
|
||||
* @param {number} index The action's index in menu list.
|
||||
*/
|
||||
async function clickDoorhangerButton(button, index) {
|
||||
async function clickDoorhangerButton(buttonType, index = 0) {
|
||||
let popuphidden = BrowserTestUtils.waitForEvent(
|
||||
PopupNotifications.panel,
|
||||
"popuphidden"
|
||||
);
|
||||
|
||||
if (button == MAIN_BUTTON || button == SECONDARY_BUTTON) {
|
||||
EventUtils.synthesizeMouseAtCenter(getNotification()[button], {});
|
||||
} else if (button == MENU_BUTTON) {
|
||||
let button;
|
||||
if (buttonType == MAIN_BUTTON || buttonType == SECONDARY_BUTTON) {
|
||||
button = getNotification()[buttonType];
|
||||
} else if (buttonType == MENU_BUTTON) {
|
||||
// Click the dropmarker arrow and wait for the menu to show up.
|
||||
info("expecting notification menu button present");
|
||||
await BrowserTestUtils.waitForCondition(() => getNotification().menubutton);
|
||||
await sleep(2000); // menubutton needs extra time for binding
|
||||
let notification = getNotification();
|
||||
|
||||
ok(notification.menubutton, "notification menupopup displayed");
|
||||
let dropdownPromise = BrowserTestUtils.waitForEvent(
|
||||
notification.menupopup,
|
||||
"popupshown"
|
||||
);
|
||||
await EventUtils.synthesizeMouseAtCenter(notification.menubutton, {});
|
||||
|
||||
notification.menubutton.click();
|
||||
info("expecting notification popup show up");
|
||||
await dropdownPromise;
|
||||
|
||||
let actionMenuItem = notification.querySelectorAll("menuitem")[index];
|
||||
await EventUtils.synthesizeMouseAtCenter(actionMenuItem, {});
|
||||
button = notification.querySelectorAll("menuitem")[index];
|
||||
}
|
||||
|
||||
button.click();
|
||||
info("expecting notification popup hidden");
|
||||
await popuphidden;
|
||||
}
|
||||
|
||||
async function clickAddressDoorhangerButton(buttonType, subType) {
|
||||
const notification = getNotification();
|
||||
let button;
|
||||
if (buttonType == EDIT_ADDRESS_BUTTON) {
|
||||
button = AddressSaveDoorhanger.editButton(notification);
|
||||
} else if (buttonType == ADDRESS_MENU_BUTTON) {
|
||||
const menu = AutofillDoorhanger.menuButton(notification);
|
||||
const promise = BrowserTestUtils.waitForEvent(menu.menupopup, "popupshown");
|
||||
menu.click();
|
||||
await promise;
|
||||
if (subType == ADDRESS_MENU_PREFENCE) {
|
||||
button = AutofillDoorhanger.preferenceButton(notification);
|
||||
} else if (subType == ADDRESS_MENU_LEARN_MORE) {
|
||||
button = AutofillDoorhanger.learnMoreButton(notification);
|
||||
}
|
||||
} else {
|
||||
await clickDoorhangerButton(buttonType);
|
||||
return;
|
||||
}
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(button, {});
|
||||
}
|
||||
|
||||
function getDoorhangerCheckbox() {
|
||||
return getNotification().checkbox;
|
||||
}
|
||||
|
@ -1120,6 +1160,31 @@ async function add_autofill_heuristic_tests(patterns, fixturePathPrefix = "") {
|
|||
add_heuristic_tests(patterns, fixturePathPrefix, { testAutofill: true });
|
||||
}
|
||||
|
||||
function fillEditDoorhanger(record) {
|
||||
const notification = getNotification();
|
||||
|
||||
for (const [key, value] of Object.entries(record)) {
|
||||
const id = AddressEditDoorhanger.getInputId(key);
|
||||
const element = notification.querySelector(`#${id}`);
|
||||
element.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This function should be removed. We should make normalizeFields in
|
||||
// FormAutofillStorageBase.sys.mjs static and using it directly
|
||||
function normalizeAddressFields(record) {
|
||||
let normalized = { ...record };
|
||||
|
||||
if (normalized.name != undefined) {
|
||||
let nameParts = FormAutofillNameUtils.splitName(normalized.name);
|
||||
normalized["given-name"] = nameParts.given;
|
||||
normalized["additional-name"] = nameParts.middle;
|
||||
normalized["family-name"] = nameParts.family;
|
||||
delete normalized.name;
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
add_setup(function () {
|
||||
OSKeyStoreTestUtils.setup();
|
||||
});
|
||||
|
|
|
@ -13,8 +13,6 @@ support-files = [
|
|||
"formautofill_common.js",
|
||||
]
|
||||
|
||||
["test_address_level_1_submission.html"]
|
||||
|
||||
["test_autofill_and_ordinal_forms.html"]
|
||||
|
||||
["test_autofocus_form.html"]
|
||||
|
@ -30,5 +28,3 @@ skip-if = ["verify"]
|
|||
["test_multi_locale_CA_address_form.html"]
|
||||
|
||||
["test_multiple_forms.html"]
|
||||
|
||||
["test_on_address_submission.html"]
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test autofill submission for a country without address-level1</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript" src="formautofill_common.js"></script>
|
||||
<script type="text/javascript" src="satchel_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
Form autofill test: Test autofill submission for a country without address-level1
|
||||
|
||||
<script>
|
||||
/* import-globals-from ../../../../../toolkit/components/satchel/test/satchel_common.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_ADDRESSES = [{
|
||||
organization: "Mozilla",
|
||||
"street-address": "123 Sesame Street",
|
||||
country: "DE",
|
||||
timesUsed: 1,
|
||||
}];
|
||||
|
||||
add_task(async function test_DE_is_valid_testcase() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["extensions.formautofill.addresses.capture.enabled", true],
|
||||
["extensions.formautofill.addresses.supportedCountries", "US,CA,DE"],
|
||||
["extensions.formautofill.creditCards.supportedCountries", "US,CA,DE"],
|
||||
],
|
||||
});
|
||||
let chromeScript = SpecialPowers.loadChromeScript(function test_country_data() {
|
||||
/* eslint-env mozilla/chrome-script */
|
||||
const {AddressDataLoader} = ChromeUtils.importESModule("resource://gre/modules/shared/FormAutofillUtils.sys.mjs");
|
||||
let data = AddressDataLoader.getData("DE");
|
||||
addMessageListener("CheckSubKeys", () => {
|
||||
return !data.defaultLocale.sub_keys;
|
||||
});
|
||||
});
|
||||
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
chromeScript.destroy();
|
||||
});
|
||||
|
||||
let result = await chromeScript.sendQuery("CheckSubKeys");
|
||||
ok(result, "Check that there are no sub_keys for the test country");
|
||||
});
|
||||
|
||||
add_task(async function test_form_will_submit_without_sub_keys() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
// This needs to match the country in the previous test and must have no sub_keys.
|
||||
["browser.search.region", "DE"],
|
||||
["extensions.formautofill.addresses.capture.enabled", true],
|
||||
["extensions.formautofill.addresses.supportedCountries", "US,CA,DE"],
|
||||
["extensions.formautofill.addresses.supported", "detect"]
|
||||
],
|
||||
});
|
||||
// Click a field to get the form handler created
|
||||
await focusAndWaitForFieldsIdentified("input[autocomplete='organization']");
|
||||
|
||||
let loadPromise = new Promise(resolve => {
|
||||
/* eslint-disable-next-line mozilla/balanced-listeners */
|
||||
document.getElementById("submit_frame").addEventListener("load", resolve);
|
||||
});
|
||||
|
||||
clickOnElement("input[type=submit]");
|
||||
await onStorageChanged("add");
|
||||
// Check if timesUsed is set correctly
|
||||
let matching = await checkAddresses(TEST_ADDRESSES);
|
||||
ok(matching, "Address saved as expected");
|
||||
|
||||
await loadPromise;
|
||||
isnot(window.submit_frame.location.href, "about:blank", "Check form submitted");
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<!-- Submit to the frame so that the test doesn't get replaced. We don't return
|
||||
-- false in onsubmit since we're testing the submission succeeds. -->
|
||||
<iframe id="submit_frame" name="submit_frame"></iframe>
|
||||
<form action="/" target="submit_frame" method="POST">
|
||||
<p><label>organization: <input autocomplete="organization" value="Mozilla"></label></p>
|
||||
<p><label>streetAddress: <input autocomplete="street-address" value="123 Sesame Street"></label></p>
|
||||
<p><label>address-level1: <select autocomplete="address-level1">
|
||||
<option selected>AL</option>
|
||||
<option>AK</option>
|
||||
</select></label></p>
|
||||
<p><label>country: <input autocomplete="country" value="DE"></label></p>
|
||||
<p><input type="submit"></p>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,118 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test autofill submit</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript" src="formautofill_common.js"></script>
|
||||
<script type="text/javascript" src="satchel_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
Form autofill test: check if address is saved/updated correctly
|
||||
|
||||
<script>
|
||||
/* import-globals-from ../../../../../toolkit/components/satchel/test/satchel_common.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
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",
|
||||
}];
|
||||
|
||||
add_task(async function setup_prefs() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["extensions.formautofill.addresses.enabled", true],
|
||||
["extensions.formautofill.addresses.capture.enabled", true],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
initPopupListener();
|
||||
|
||||
// Submit first address for saving.
|
||||
add_task(async function check_storage_after_form_submitted() {
|
||||
for (let key in TEST_ADDRESSES[0]) {
|
||||
await setInput("#" + key, TEST_ADDRESSES[0][key]);
|
||||
}
|
||||
|
||||
clickOnElement("input[type=submit]");
|
||||
|
||||
let expectedAddresses = TEST_ADDRESSES.slice(0, 1);
|
||||
await onStorageChanged("add");
|
||||
// Check if timesUsed is set correctly
|
||||
expectedAddresses[0].timesUsed = 1;
|
||||
let matching = await checkAddresses(expectedAddresses);
|
||||
ok(matching, "Address saved as expected");
|
||||
delete expectedAddresses[0].timesUsed;
|
||||
});
|
||||
|
||||
// Submit another new address.
|
||||
add_task(async function check_storage_after_another_address_submitted() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [["privacy.reduceTimerPrecision", false]]});
|
||||
|
||||
document.querySelector("form").reset();
|
||||
for (let key in TEST_ADDRESSES[1]) {
|
||||
await setInput("#" + key, TEST_ADDRESSES[1][key]);
|
||||
}
|
||||
|
||||
clickOnElement("input[type=submit]");
|
||||
|
||||
// The 2nd test address should be on the top since it's the last used one.
|
||||
let addressesInMenu = TEST_ADDRESSES.slice(1);
|
||||
addressesInMenu.push(TEST_ADDRESSES[0]);
|
||||
|
||||
// let expectedAddresses = TEST_ADDRESSES.slice(0);
|
||||
await onStorageChanged("add");
|
||||
let matching = await checkAddresses(TEST_ADDRESSES);
|
||||
ok(matching, "New address saved as expected");
|
||||
|
||||
await setInput("#organization", "");
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
await expectPopup();
|
||||
checkMenuEntries(addressesInMenu.map(address =>
|
||||
JSON.stringify({primary: address.organization, secondary: address["street-address"]})
|
||||
));
|
||||
});
|
||||
|
||||
// Submit another new address that is mergeable.
|
||||
add_task(async function new_address_submitted_and_merged() {
|
||||
// TODO: Bug Bug 1812294
|
||||
});
|
||||
|
||||
// Submit an updated autofill address and merge.
|
||||
add_task(async function check_storage_after_form_submitted() {
|
||||
// TODO: Bug Bug 1812294
|
||||
});
|
||||
|
||||
// Submit a subset address manually.
|
||||
add_task(async function submit_subset_manually() {
|
||||
// TODO: Bug Bug 1812294
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<div>
|
||||
|
||||
<form onsubmit="return false">
|
||||
<p>This is a basic form for submitting test.</p>
|
||||
<p><label>organization: <input id="organization" name="organization" autocomplete="organization" type="text"></label></p>
|
||||
<p><label>streetAddress: <input id="street-address" name="street-address" autocomplete="street-address" type="text"></label></p>
|
||||
<p><label>tel: <input id="tel" name="tel" autocomplete="tel" type="text"></label></p>
|
||||
<p><label>country: <input id="country" name="country" autocomplete="country" type="text"></label></p>
|
||||
<p><input type="submit"></p>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -55,7 +55,7 @@ let CONTENT = {};
|
|||
* The UI data sourced from the `CONTENT` variable is used for rendering. Derived classes
|
||||
* should override the `render()` method to customize the layout.
|
||||
*/
|
||||
class AutofillDoorhanger {
|
||||
export class AutofillDoorhanger {
|
||||
/**
|
||||
* Constructs an instance of the `AutofillDoorhanger` class.
|
||||
*
|
||||
|
@ -63,6 +63,14 @@ class AutofillDoorhanger {
|
|||
* @param {object} oldRecord The old record that can be merged with the new record
|
||||
* @param {object} newRecord The new record submitted by users
|
||||
*/
|
||||
static headerClass = "address-capture-header";
|
||||
static descriptionClass = "address-capture-description";
|
||||
static contentClass = "address-capture-content";
|
||||
static menuButtonId = "address-capture-menu-button";
|
||||
|
||||
static preferenceURL = null;
|
||||
static learnMoreURL = null;
|
||||
|
||||
constructor(browser, oldRecord, newRecord) {
|
||||
this.browser = browser;
|
||||
this.oldRecord = oldRecord;
|
||||
|
@ -98,27 +106,63 @@ class AutofillDoorhanger {
|
|||
*/
|
||||
|
||||
// The container of the header part
|
||||
static header(panel) {
|
||||
return panel.querySelector(`.${AutofillDoorhanger.headerClass}`);
|
||||
}
|
||||
get header() {
|
||||
return this.panel.querySelector(".address-capture-header");
|
||||
return AutofillDoorhanger.header(this.panel);
|
||||
}
|
||||
|
||||
// The container of the description part
|
||||
static description(panel) {
|
||||
return panel.querySelector(`.${AutofillDoorhanger.descriptionClass}`);
|
||||
}
|
||||
get description() {
|
||||
return this.panel.querySelector(".address-capture-description");
|
||||
return AutofillDoorhanger.description(this.panel);
|
||||
}
|
||||
|
||||
// The container of the content part
|
||||
static content(panel) {
|
||||
return panel.querySelector(`.${AutofillDoorhanger.contentClass}`);
|
||||
}
|
||||
get content() {
|
||||
return this.panel.querySelector(".address-capture-content");
|
||||
return AutofillDoorhanger.content(this.panel);
|
||||
}
|
||||
|
||||
static menuButton(panel) {
|
||||
return panel.querySelector(`#${AutofillDoorhanger.menuButtonId}`);
|
||||
}
|
||||
get menuButton() {
|
||||
return AutofillDoorhanger.menuButton(this.panel);
|
||||
}
|
||||
|
||||
static preferenceButton(panel) {
|
||||
const menu = AutofillDoorhanger.menuButton(panel);
|
||||
return menu.menupopup.querySelector(
|
||||
`[data-l10n-id=address-capture-manage-address-button]`
|
||||
);
|
||||
}
|
||||
static learnMoreButton(panel) {
|
||||
const menu = AutofillDoorhanger.menuButton(panel);
|
||||
return menu.menupopup.querySelector(
|
||||
`[data-l10n-id=address-capture-learn-more-button]`
|
||||
);
|
||||
}
|
||||
|
||||
get preferenceURL() {
|
||||
return this.constructor.preferenceURL;
|
||||
}
|
||||
get learnMoreURL() {
|
||||
return this.constructor.learnMoreURL;
|
||||
}
|
||||
|
||||
onMenuItemClick(evt) {
|
||||
if (evt == "open-pref") {
|
||||
this.browser.ownerGlobal.openPreferences("privacy-address-autofill");
|
||||
this.browser.ownerGlobal.openPreferences(this.preferenceURL);
|
||||
} else if (evt == "learn-more") {
|
||||
const url =
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
||||
"automatically-fill-your-address-web-forms";
|
||||
this.learnMoreURL;
|
||||
this.browser.ownerGlobal.openWebLinkIn(url, "tab", {
|
||||
relatedToCurrent: true,
|
||||
});
|
||||
|
@ -141,16 +185,12 @@ class AutofillDoorhanger {
|
|||
this.doc.l10n.setAttributes(text, this.ui.header.l10nId);
|
||||
|
||||
// Render the menu button
|
||||
const menuButtonId = "address-capture-menu-button";
|
||||
if (
|
||||
!this.ui.menu?.length ||
|
||||
this.header.querySelector(`#${menuButtonId}`)
|
||||
) {
|
||||
if (!this.ui.menu?.length || AutofillDoorhanger.menuButton(this.panel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const button = this.doc.createXULElement("toolbarbutton");
|
||||
button.setAttribute("id", menuButtonId);
|
||||
button.setAttribute("id", AutofillDoorhanger.menuButtonId);
|
||||
|
||||
const menupopup = this.doc.createXULElement("menupopup");
|
||||
menupopup.setAttribute("class", "toolbar-menupopup");
|
||||
|
@ -273,6 +313,7 @@ class AutofillDoorhanger {
|
|||
return {
|
||||
label: msg.attributes.find(x => x.name == "label").value,
|
||||
accessKey: msg.attributes.find(x => x.name == "accessKey").value,
|
||||
dismiss: param.dismiss,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -302,7 +343,11 @@ class AutofillDoorhanger {
|
|||
}
|
||||
}
|
||||
|
||||
class AddressSaveDoorhanger extends AutofillDoorhanger {
|
||||
export class AddressSaveDoorhanger extends AutofillDoorhanger {
|
||||
static preferenceURL = "privacy-address-autofill";
|
||||
static learnMoreURL = "automatically-fill-your-address-web-forms";
|
||||
static editButtonId = "address-capture-edit-address-button";
|
||||
|
||||
#editAddressCb = null;
|
||||
|
||||
constructor(browser, oldRecord, newRecord, editAddressCb) {
|
||||
|
@ -311,6 +356,13 @@ class AddressSaveDoorhanger extends AutofillDoorhanger {
|
|||
this.#editAddressCb = editAddressCb;
|
||||
}
|
||||
|
||||
static editButton(panel) {
|
||||
return panel.querySelector(`#${AddressSaveDoorhanger.editButtonId}`);
|
||||
}
|
||||
get editButton() {
|
||||
return AddressSaveDoorhanger.editButton(this.panel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a line by comparing the old and the new address field and returns an array of
|
||||
* <span> elements that represents the formatted line.
|
||||
|
@ -399,6 +451,7 @@ class AddressSaveDoorhanger extends AutofillDoorhanger {
|
|||
field => [this.oldRecord[field], this.newRecord[field]]
|
||||
);
|
||||
break;
|
||||
case "country":
|
||||
case "tel":
|
||||
case "email":
|
||||
case "organization":
|
||||
|
@ -458,10 +511,9 @@ class AddressSaveDoorhanger extends AutofillDoorhanger {
|
|||
this.content.appendChild(section);
|
||||
|
||||
// Put the edit address button in the first section
|
||||
const editButtonId = "address-capture-edit-address-button";
|
||||
if (!this.doc.getElementById(editButtonId)) {
|
||||
if (!AddressSaveDoorhanger.editButton(this.panel)) {
|
||||
const button = this.doc.createXULElement("toolbarbutton");
|
||||
button.setAttribute("id", editButtonId);
|
||||
button.setAttribute("id", AddressSaveDoorhanger.editButtonId);
|
||||
|
||||
// The element will be removed after the popup is closed
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
|
@ -479,9 +531,9 @@ class AddressSaveDoorhanger extends AutofillDoorhanger {
|
|||
* Address Update doorhanger and Address Save doorhanger have the same implementation.
|
||||
* The only difference is UI.
|
||||
*/
|
||||
class AddressUpdateDoorhanger extends AddressSaveDoorhanger {}
|
||||
export class AddressUpdateDoorhanger extends AddressSaveDoorhanger {}
|
||||
|
||||
class AddressEditDoorhanger extends AutofillDoorhanger {
|
||||
export class AddressEditDoorhanger extends AutofillDoorhanger {
|
||||
constructor(browser, record) {
|
||||
// Address edit dialog doesn't have "old" record
|
||||
super(browser, null, record);
|
||||
|
@ -694,7 +746,7 @@ class AddressEditDoorhanger extends AutofillDoorhanger {
|
|||
input = this.doc.createElement("input");
|
||||
}
|
||||
|
||||
input.setAttribute("id", AddressEditDoorhanger.#getInputId(fieldName));
|
||||
input.setAttribute("id", AddressEditDoorhanger.getInputId(fieldName));
|
||||
input.value = this.#getFieldDisplayData(fieldName) ?? null;
|
||||
div.appendChild(input);
|
||||
|
||||
|
@ -706,7 +758,7 @@ class AddressEditDoorhanger extends AutofillDoorhanger {
|
|||
return regex;
|
||||
}
|
||||
|
||||
static #getInputId(fieldName) {
|
||||
static getInputId(fieldName) {
|
||||
return `address-edit-${fieldName}-input`;
|
||||
}
|
||||
|
||||
|
@ -753,7 +805,13 @@ CONTENT = {
|
|||
sections: [
|
||||
{
|
||||
imgClass: "address-capture-img-address",
|
||||
categories: ["name", "organization", "street-address", "address"],
|
||||
categories: [
|
||||
"name",
|
||||
"organization",
|
||||
"street-address",
|
||||
"address",
|
||||
"country",
|
||||
],
|
||||
},
|
||||
{
|
||||
imgClass: "address-capture-img-email",
|
||||
|
@ -806,7 +864,13 @@ CONTENT = {
|
|||
sections: [
|
||||
{
|
||||
imgClass: "address-capture-img-address",
|
||||
categories: ["name", "organization", "street-address", "address"],
|
||||
categories: [
|
||||
"name",
|
||||
"organization",
|
||||
"street-address",
|
||||
"address",
|
||||
"country",
|
||||
],
|
||||
},
|
||||
{
|
||||
imgClass: "address-capture-img-email",
|
||||
|
@ -862,13 +926,14 @@ CONTENT = {
|
|||
footer: {
|
||||
mainAction: {
|
||||
l10nId: "address-capture-save-button",
|
||||
callbackState: "create",
|
||||
callbackState: "edit",
|
||||
confirmationHintId: "confirmation-hint-address-created",
|
||||
},
|
||||
secondaryActions: [
|
||||
{
|
||||
l10nId: "address-capture-cancel-button",
|
||||
callbackState: "cancel",
|
||||
dismiss: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -880,7 +945,7 @@ CONTENT = {
|
|||
},
|
||||
|
||||
addCreditCard: {
|
||||
notificationId: "autofill-credit-card",
|
||||
notificationId: "autofill-credit-card-add",
|
||||
message: formatStringFromName("saveCreditCardMessage", [brandShortName]),
|
||||
descriptionLabel: GetStringFromName("saveCreditCardDescriptionLabel"),
|
||||
descriptionIcon: true,
|
||||
|
@ -947,7 +1012,7 @@ CONTENT = {
|
|||
},
|
||||
},
|
||||
updateCreditCard: {
|
||||
notificationId: "autofill-credit-card",
|
||||
notificationId: "autofill-credit-card-update",
|
||||
message: GetStringFromName("updateCreditCardMessage"),
|
||||
descriptionLabel: GetStringFromName("updateCreditCardDescriptionLabel"),
|
||||
descriptionIcon: true,
|
||||
|
@ -1344,13 +1409,16 @@ export let FormAutofillPrompter = {
|
|||
newRecord
|
||||
);
|
||||
|
||||
if (state == "create") {
|
||||
if (state == "edit") {
|
||||
// If users choose "save" in the edit address doorhanger, we don't need
|
||||
// to show the save/update doorhanger after the edit address doorhanger
|
||||
// is closed
|
||||
recordToSave = editedRecord;
|
||||
chromeWin.PopupNotifications.remove(this._addrSaveDoorhanger);
|
||||
resolve({ state, confimationHintId: null });
|
||||
resolve({
|
||||
state: isSave ? "create" : "update",
|
||||
confimationHintId: null,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче