Revision control

Copy as Markdown

Other Tools

const { sinon } = ChromeUtils.importESModule(
);
const { GuessConfig } = ChromeUtils.importESModule(
);
const PREF_NAME = "mailnews.auto_config_url";
const PREF_VALUE = Services.prefs.getCharPref(PREF_NAME);
add_setup(function () {
// Set the pref to load a local autoconfig file.
const url =
Services.prefs.setCharPref(PREF_NAME, url);
});
registerCleanupFunction(function () {
// Restore the original pref.
Services.prefs.setCharPref(PREF_NAME, PREF_VALUE);
});
add_task(async function test_account_email_manual_config_form() {
// Fill in email auto form and click continue, waiting for config found
// view to be shown.
const dialog = await subtest_open_account_hub_dialog();
const emailUser = {
name: "John Doe",
email: "john.doe@momo.invalid",
password: "abc12345",
incomingHost: "mail.momo.invalid",
incomingPort: 123,
outgoingHost: "mail.momo.invalid",
outgoingPort: 465,
};
await subtest_fill_initial_config_fields(dialog, emailUser);
const configFoundTemplate = dialog.querySelector("email-config-found");
await TestUtils.waitForCondition(
() =>
BrowserTestUtils.isVisible(configFoundTemplate.querySelector("#imap")),
"The IMAP config option should be visible"
);
// Edit configuration button should lead to manual config form.
EventUtils.synthesizeMouseAtCenter(
configFoundTemplate.querySelector("#editConfiguration"),
{}
);
const manualConfigTemplate = dialog.querySelector(
"#emailManualConfigSubview"
);
await TestUtils.waitForCondition(
() => BrowserTestUtils.isVisible(manualConfigTemplate),
"The manual config template should be in view"
);
await subtest_close_account_hub_dialog(dialog, manualConfigTemplate);
});
add_task(async function test_account_email_manual_config_form_pop3() {
// Fill in email auto form and click continue, waiting for config found
// view to be shown.
const dialog = await subtest_open_account_hub_dialog();
const emailUser = {
name: "John Doe",
email: "john.doe@momo.invalid",
password: "abc12345",
incomingHost: "mail.momo.invalid",
incomingPort: 123,
outgoingHost: "mail.momo.invalid",
outgoingPort: 465,
};
await subtest_fill_initial_config_fields(dialog, emailUser);
const configFoundTemplate = dialog.querySelector("email-config-found");
await TestUtils.waitForCondition(
() =>
BrowserTestUtils.isVisible(configFoundTemplate.querySelector("#pop3")),
"The POP3 config option should be visible"
);
EventUtils.synthesizeMouseAtCenter(
configFoundTemplate.querySelector("#pop3"),
{}
);
// POP3 should be the selected config.
Assert.ok(
configFoundTemplate.querySelector("#pop3").classList.contains("selected"),
"POP3 should be the selected config option"
);
// Edit configuration button should lead to manual config form.
EventUtils.synthesizeMouseAtCenter(
configFoundTemplate.querySelector("#editConfiguration"),
{}
);
const manualConfigTemplate = dialog.querySelector(
"#emailManualConfigSubview"
);
await TestUtils.waitForCondition(
() => BrowserTestUtils.isVisible(manualConfigTemplate),
"The manual config template should be in view"
);
await subtest_close_account_hub_dialog(dialog, manualConfigTemplate);
});
add_task(async function test_manual_config_connect_reviews_updated_settings() {
const sandbox = sinon.createSandbox();
const { dialog, manualConfigTemplate } = await openManualConfigSubview();
const incomingHostname = manualConfigTemplate.querySelector(
"#manualIncomingHostname"
);
const incomingUsername = manualConfigTemplate.querySelector(
"#manualIncomingUsername"
);
const incomingPort = manualConfigTemplate.querySelector(
"#manualIncomingPort"
);
const outgoingHostname = manualConfigTemplate.querySelector(
"#manualOutgoingHostname"
);
const outgoingPort = manualConfigTemplate.querySelector(
"#manualOutgoingPort"
);
incomingHostname.value = "IMAP.MOMO.INVALID";
incomingUsername.value = "john.doe";
incomingPort.value = "143";
outgoingHostname.value = "SMTP.MOMO.INVALID";
outgoingPort.value = "587";
const manualConfigForm =
manualConfigTemplate.querySelector("#manualConfigForm");
Assert.ok(
manualConfigForm.checkValidity(),
"The changed manual configuration should be valid before submitting it"
);
const updatedConfig = manualConfigTemplate.captureState().copy();
updatedConfig.incoming.hostname = "imap.tested.momo.invalid";
updatedConfig.incoming.port = 993;
updatedConfig.incoming.socketType = Ci.nsMsgSocketType.SSL;
updatedConfig.incoming.auth = Ci.nsMsgAuthMethod.passwordCleartext;
updatedConfig.incoming.username = "john.doe@momo.invalid";
updatedConfig.outgoing.hostname = "smtp.tested.momo.invalid";
updatedConfig.outgoing.port = 465;
updatedConfig.outgoing.socketType = Ci.nsMsgSocketType.SSL;
updatedConfig.outgoing.auth = Ci.nsMsgAuthMethod.passwordCleartext;
updatedConfig.outgoing.username = "john.doe@momo.invalid";
sandbox
.stub(GuessConfig, "guessConfig")
.callsFake(async (domain, _progress, initialConfig, configType) => {
Assert.equal(
domain,
"momo.invalid",
"The manual config test should use the email domain"
);
Assert.equal(
configType,
"both",
"The combined manual form should test incoming and outgoing settings"
);
Assert.equal(
initialConfig.incoming.hostname,
"imap.momo.invalid",
"The current incoming hostname should be sent for testing"
);
Assert.equal(
initialConfig.incoming.port,
143,
"The current incoming port should be sent for testing"
);
Assert.equal(
initialConfig.outgoing.hostname,
"smtp.momo.invalid",
"The current outgoing hostname should be sent for testing"
);
Assert.equal(
initialConfig.outgoing.port,
587,
"The current outgoing port should be sent for testing"
);
return updatedConfig;
});
outgoingHostname.querySelector("input").focus();
EventUtils.synthesizeKey("KEY_Enter", {}, window);
const passwordSubview = dialog.querySelector("#emailPasswordSubview");
Assert.ok(
BrowserTestUtils.isHidden(passwordSubview),
"A config test that updates settings should not continue to the password step"
);
const header =
manualConfigTemplate.shadowRoot.querySelector(
"account-hub-header"
).shadowRoot;
const notification = header.querySelector("#emailFormNotification");
await TestUtils.waitForCondition(
() =>
BrowserTestUtils.isVisible(notification) &&
notification.classList.contains("success"),
"The successful config test notification should be visible"
);
Assert.ok(
BrowserTestUtils.isVisible(manualConfigTemplate),
"A config test that updates settings should keep the manual config form visible"
);
const successNotificationTitle = header.querySelector(
"#emailFormNotificationTitle .localized-title"
);
Assert.equal(
document.l10n.getAttributes(successNotificationTitle).id,
"account-hub-config-test-success",
"The success notification should report a valid configuration"
);
const manualConfigTitle =
manualConfigTemplate.shadowRoot.querySelector("#title");
Assert.equal(
manualConfigTemplate.getAttribute("title-id"),
"account-hub-manual-config-review-settings-title",
"The manual config header should ask the user to review the updated settings"
);
Assert.equal(
document.l10n.getAttributes(manualConfigTitle).id,
"account-hub-manual-config-review-settings-title",
"The header title should use the review updated settings text"
);
Assert.ok(
!dialog.querySelector("#emailFooter #forward").disabled,
"Continue should be available after the user reviews the updated settings"
);
Assert.equal(
incomingHostname.value,
"imap.tested.momo.invalid",
"The incoming hostname should update from the tested config"
);
Assert.equal(
incomingUsername.value,
"john.doe@momo.invalid",
"The incoming username should update from the tested config"
);
Assert.equal(
incomingPort.value,
"993",
"The incoming port should update from the tested config"
);
Assert.equal(
outgoingHostname.value,
"smtp.tested.momo.invalid",
"The outgoing hostname should update from the tested config"
);
Assert.equal(
outgoingPort.value,
"465",
"The outgoing port should update from the tested config"
);
Assert.ok(
GuessConfig.guessConfig.calledOnce,
"The config should be tested before continuing"
);
sandbox.restore();
await subtest_close_account_hub_dialog(dialog, manualConfigTemplate);
});
add_task(
async function test_manual_config_connect_reviews_user_edits_confirmed_by_test() {
const sandbox = sinon.createSandbox();
const { dialog, manualConfigTemplate } = await openManualConfigSubview();
const incomingHostname = manualConfigTemplate.querySelector(
"#manualIncomingHostname"
);
const incomingPort = manualConfigTemplate.querySelector(
"#manualIncomingPort"
);
const outgoingHostname = manualConfigTemplate.querySelector(
"#manualOutgoingHostname"
);
const outgoingPort = manualConfigTemplate.querySelector(
"#manualOutgoingPort"
);
incomingHostname.value = "imap.confirmed.momo.invalid";
incomingPort.value = "993";
outgoingHostname.value = "smtp.confirmed.momo.invalid";
outgoingPort.value = "587";
sandbox
.stub(GuessConfig, "guessConfig")
.callsFake(async (domain, _progress, initialConfig, configType) => {
Assert.equal(
domain,
"momo.invalid",
"The manual config test should use the email domain"
);
Assert.equal(
configType,
"both",
"The combined manual form should test incoming and outgoing settings"
);
Assert.equal(
initialConfig.incoming.hostname,
"imap.confirmed.momo.invalid",
"The edited incoming hostname should be sent for testing"
);
Assert.equal(
initialConfig.incoming.port,
993,
"The edited incoming port should be sent for testing"
);
Assert.equal(
initialConfig.outgoing.hostname,
"smtp.confirmed.momo.invalid",
"The edited outgoing hostname should be sent for testing"
);
Assert.equal(
initialConfig.outgoing.port,
587,
"The edited outgoing port should be sent for testing"
);
return initialConfig.copy();
});
const footerForward = dialog.querySelector("#emailFooter #forward");
EventUtils.synthesizeMouseAtCenter(footerForward, {});
const passwordSubview = dialog.querySelector("#emailPasswordSubview");
Assert.ok(
BrowserTestUtils.isHidden(passwordSubview),
"A config test that confirms user edits should not continue to the password step"
);
const header =
manualConfigTemplate.shadowRoot.querySelector(
"account-hub-header"
).shadowRoot;
const notification = header.querySelector("#emailFormNotification");
await TestUtils.waitForCondition(
() =>
BrowserTestUtils.isVisible(notification) &&
notification.classList.contains("success"),
"The successful config test notification should be visible"
);
Assert.ok(
BrowserTestUtils.isVisible(manualConfigTemplate),
"A config test that confirms user edits should keep the manual config form visible"
);
Assert.equal(
manualConfigTemplate.getAttribute("title-id"),
"account-hub-manual-config-review-settings-title",
"The manual config header should ask the user to review the updated settings"
);
Assert.ok(
!footerForward.disabled,
"Continue should be available after the user reviews the confirmed settings"
);
EventUtils.synthesizeMouseAtCenter(footerForward, {});
await TestUtils.waitForCondition(
() => BrowserTestUtils.isVisible(passwordSubview),
"Continuing without more updates should leave the manual config form"
);
Assert.ok(
BrowserTestUtils.isHidden(manualConfigTemplate),
"The manual config form should be hidden after the reviewed settings are confirmed"
);
Assert.equal(
GuessConfig.guessConfig.callCount,
2,
"The config should be tested before each continue attempt"
);
sandbox.restore();
await subtest_close_account_hub_dialog(dialog, passwordSubview);
}
);
add_task(async function test_manual_config_connect_continues_without_changes() {
const sandbox = sinon.createSandbox();
const { dialog, manualConfigTemplate } = await openManualConfigSubview();
sandbox
.stub(GuessConfig, "guessConfig")
.callsFake(async (domain, _progress, initialConfig, configType) => {
Assert.equal(
domain,
"momo.invalid",
"The manual config test should use the email domain"
);
Assert.equal(
configType,
"both",
"The combined manual form should test incoming and outgoing settings"
);
return initialConfig.copy();
});
EventUtils.synthesizeMouseAtCenter(
dialog.querySelector("#emailFooter #forward"),
{}
);
const passwordSubview = dialog.querySelector("#emailPasswordSubview");
await TestUtils.waitForCondition(
() => BrowserTestUtils.isVisible(passwordSubview),
"A successful config test with no updates should continue to the password step"
);
Assert.ok(
BrowserTestUtils.isHidden(manualConfigTemplate),
"A successful config test with no updates should leave the manual config form"
);
Assert.ok(
GuessConfig.guessConfig.calledOnce,
"The config should be tested before continuing"
);
sandbox.restore();
await subtest_close_account_hub_dialog(dialog, passwordSubview);
});
add_task(async function test_manual_config_connect_shows_test_error() {
const sandbox = sinon.createSandbox();
const { dialog, manualConfigTemplate } = await openManualConfigSubview();
sandbox
.stub(GuessConfig, "guessConfig")
.rejects(new Error("Configuration test failed"));
EventUtils.synthesizeMouseAtCenter(
dialog.querySelector("#emailFooter #forward"),
{}
);
const header =
manualConfigTemplate.shadowRoot.querySelector(
"account-hub-header"
).shadowRoot;
const notification = header.querySelector("#emailFormNotification");
await TestUtils.waitForCondition(
() =>
BrowserTestUtils.isVisible(notification) &&
notification.classList.contains("error"),
"The failed config test notification should be visible"
);
Assert.equal(
document.l10n.getAttributes(
header.querySelector("#emailFormNotificationTitle .localized-title")
).id,
"account-hub-find-settings-failed",
"The error notification should report that settings could not be found"
);
Assert.ok(
BrowserTestUtils.isVisible(manualConfigTemplate),
"A failed config test should keep the manual config form visible"
);
Assert.ok(
!dialog.querySelector("#emailFooter #forward").disabled,
"Connect should be available to retry after a config test error"
);
sandbox.restore();
await subtest_close_account_hub_dialog(dialog, manualConfigTemplate);
});
add_task(async function test_manual_config_error_summary_for_invalid_fields() {
const dialog = await subtest_open_account_hub_dialog();
const emailUser = {
name: "John Doe",
email: "john.doe@momo.invalid",
password: "abc12345",
incomingHost: "mail.momo.invalid",
incomingPort: 123,
outgoingHost: "mail.momo.invalid",
outgoingPort: 465,
};
await subtest_fill_initial_config_fields(dialog, emailUser);
const configFoundTemplate = dialog.querySelector("email-config-found");
await TestUtils.waitForCondition(
() =>
BrowserTestUtils.isVisible(configFoundTemplate.querySelector("#imap")),
"The IMAP config option should be visible"
);
EventUtils.synthesizeMouseAtCenter(
configFoundTemplate.querySelector("#editConfiguration"),
{}
);
const manualConfigTemplate = dialog.querySelector(
"#emailManualConfigSubview"
);
await TestUtils.waitForCondition(
() => BrowserTestUtils.isVisible(manualConfigTemplate),
"The manual config template should be in view"
);
const incomingHostname = manualConfigTemplate.querySelector(
"#manualIncomingHostname"
);
const incomingUsername = manualConfigTemplate.querySelector(
"#manualIncomingUsername"
);
const incomingPort = manualConfigTemplate.querySelector(
"#manualIncomingPort"
);
incomingHostname.value = "";
incomingUsername.value = "";
incomingPort.value = "0";
const footerForward = dialog.querySelector("#emailFooter #forward");
Assert.ok(!footerForward.disabled, "Connect should start enabled");
EventUtils.synthesizeMouseAtCenter(footerForward, {});
const header =
manualConfigTemplate.shadowRoot.querySelector(
"account-hub-header"
).shadowRoot;
const notification = header.querySelector("#emailFormNotification");
await TestUtils.waitForCondition(
() => !notification.hidden && notification.open,
"The expanded error notification should be visible"
);
Assert.ok(footerForward.disabled, "Connect should be disabled after errors");
Assert.deepEqual(
Array.from(header.querySelectorAll(".manual-config-error-list a")).map(
link => link.textContent
),
["Hostname", "Username", "Port"],
"The notification should list the invalid fields"
);
const hostnameInput = incomingHostname.querySelector("input");
Assert.equal(
hostnameInput.getAttribute("aria-describedby"),
"manualIncomingHostnameInputErrorMessage",
"The invalid hostname should be described by its error text"
);
header.querySelector(".manual-config-error-list a").click();
await TestUtils.waitForCondition(
() =>
document.querySelector("account-hub-container").shadowRoot
.activeElement == hostnameInput,
"The invalid field should be focused"
);
Assert.equal(
document.querySelector("account-hub-container").shadowRoot.activeElement,
hostnameInput,
"Clicking an error summary link should focus the field"
);
incomingHostname.value = "imap.mail.momo.invalid";
incomingHostname.dispatchEvent(new Event("input", { bubbles: true }));
incomingUsername.value = "john.doe";
incomingUsername.dispatchEvent(new Event("input", { bubbles: true }));
incomingPort.value = "993";
incomingPort.dispatchEvent(new Event("input", { bubbles: true }));
await TestUtils.waitForCondition(
() => !footerForward.disabled,
"Connect should be re-enabled after errors are fixed"
);
await subtest_close_account_hub_dialog(dialog, manualConfigTemplate);
});
async function openManualConfigSubview() {
const dialog = await subtest_open_account_hub_dialog();
await subtest_fill_initial_config_fields(dialog, {
name: "John Doe",
email: "john.doe@momo.invalid",
password: "abc12345",
incomingHost: "mail.momo.invalid",
incomingPort: 123,
outgoingHost: "mail.momo.invalid",
outgoingPort: 465,
});
const configFoundTemplate = dialog.querySelector("email-config-found");
await TestUtils.waitForCondition(
() =>
BrowserTestUtils.isVisible(configFoundTemplate.querySelector("#imap")),
"The IMAP config option should be visible"
);
EventUtils.synthesizeMouseAtCenter(
configFoundTemplate.querySelector("#editConfiguration"),
{}
);
const manualConfigTemplate = dialog.querySelector(
"#emailManualConfigSubview"
);
await TestUtils.waitForCondition(
() => BrowserTestUtils.isVisible(manualConfigTemplate),
"The manual config template should be in view"
);
return { dialog, manualConfigTemplate };
}