summaryrefslogtreecommitdiffstats
path: root/comm/mail/test/browser/account/browser_mailAccountSetupWizard.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/test/browser/account/browser_mailAccountSetupWizard.js')
-rw-r--r--comm/mail/test/browser/account/browser_mailAccountSetupWizard.js931
1 files changed, 931 insertions, 0 deletions
diff --git a/comm/mail/test/browser/account/browser_mailAccountSetupWizard.js b/comm/mail/test/browser/account/browser_mailAccountSetupWizard.js
new file mode 100644
index 0000000000..33cc69e645
--- /dev/null
+++ b/comm/mail/test/browser/account/browser_mailAccountSetupWizard.js
@@ -0,0 +1,931 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+var { openAccountSetup, wait_for_account_tree_load } = ChromeUtils.import(
+ "resource://testing-common/mozmill/AccountManagerHelpers.jsm"
+);
+var { mc } = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+var { input_value, delete_all_existing } = ChromeUtils.import(
+ "resource://testing-common/mozmill/KeyboardHelpers.jsm"
+);
+var { gMockPromptService } = ChromeUtils.import(
+ "resource://testing-common/mozmill/PromptHelpers.jsm"
+);
+
+var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
+var { DNS } = ChromeUtils.import("resource:///modules/DNS.jsm");
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+let { TelemetryTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TelemetryTestUtils.sys.mjs"
+);
+var { MockRegistrar } = ChromeUtils.importESModule(
+ "resource://testing-common/MockRegistrar.sys.mjs"
+);
+var { nsMailServer } = ChromeUtils.import(
+ "resource://testing-common/mailnews/Maild.jsm"
+);
+
+var originalAlertsServiceCID;
+// We need a mock alerts service to capture notification events when loading the
+// UI after a successful account configuration in order to catch the alert
+// triggered when trying to connect to the fake IMAP server.
+class MockAlertsService {
+ QueryInterface = ChromeUtils.generateQI(["nsIAlertsService"]);
+ showAlert() {}
+}
+
+var user = {
+ name: "Yamato Nadeshiko",
+ email: "yamato.nadeshiko@example.com",
+ password: "abc12345",
+ incomingHost: "testin.example.com",
+ outgoingHost: "testout.example.com",
+};
+var outgoingShortName = "Example Två";
+
+var imapUser = {
+ name: "John Doe",
+ email: "john.doe@example-imap.com",
+ password: "abc12345",
+ incomingHost: "testin.example-imap.com",
+ outgoingHost: "testout.example-imap.com",
+};
+
+var IMAPServer = {
+ open() {
+ const {
+ ImapDaemon,
+ ImapMessage,
+ IMAP_RFC2195_extension,
+ IMAP_RFC3501_handler,
+ mixinExtension,
+ } = ChromeUtils.import("resource://testing-common/mailnews/Imapd.jsm");
+ const { nsMailServer } = ChromeUtils.import(
+ "resource://testing-common/mailnews/Maild.jsm"
+ );
+ IMAPServer.ImapMessage = ImapMessage;
+
+ this.daemon = new ImapDaemon();
+ this.server = new nsMailServer(daemon => {
+ let handler = new IMAP_RFC3501_handler(daemon);
+ mixinExtension(handler, IMAP_RFC2195_extension);
+
+ handler.kUsername = "john.doe@example-imap.com";
+ handler.kPassword = "abc12345";
+ handler.kAuthRequired = true;
+ handler.kAuthSchemes = ["PLAIN"];
+ return handler;
+ }, this.daemon);
+ this.server.start(1993);
+ info(`IMAP server started on port ${this.server.port}`);
+
+ registerCleanupFunction(() => this.close());
+ },
+ close() {
+ this.server.stop();
+ },
+ get port() {
+ return this.server.port;
+ },
+};
+
+var SMTPServer = {
+ open() {
+ const { SmtpDaemon, SMTP_RFC2821_handler } = ChromeUtils.import(
+ "resource://testing-common/mailnews/Smtpd.jsm"
+ );
+ const { nsMailServer } = ChromeUtils.import(
+ "resource://testing-common/mailnews/Maild.jsm"
+ );
+
+ this.daemon = new SmtpDaemon();
+ this.server = new nsMailServer(daemon => {
+ let handler = new SMTP_RFC2821_handler(daemon);
+ handler.kUsername = "john.doe@example-imap.com";
+ handler.kPassword = "abc12345";
+ handler.kAuthRequired = true;
+ handler.kAuthSchemes = ["PLAIN"];
+ return handler;
+ }, this.daemon);
+ this.server.start(1587);
+ info(`SMTP server started on port ${this.server.port}`);
+
+ registerCleanupFunction(() => this.close());
+ },
+ close() {
+ this.server.stop();
+ },
+ get port() {
+ return this.server.port;
+ },
+};
+
+var _srv = DNS.srv;
+var _txt = DNS.txt;
+DNS.srv = function (name) {
+ if (["_caldavs._tcp.localhost", "_carddavs._tcp.localhost"].includes(name)) {
+ return [{ prio: 0, weight: 0, host: "example.org", port: 443 }];
+ }
+ if (
+ [
+ "_caldavs._tcp.example-imap.com",
+ "_carddavs._tcp.example-imap.com",
+ ].includes(name)
+ ) {
+ return [{ prio: 0, weight: 0, host: "example.org", port: 443 }];
+ }
+ throw new Error(`Unexpected DNS SRV lookup: ${name}`);
+};
+DNS.txt = function (name) {
+ if (name == "_caldavs._tcp.localhost") {
+ return [{ data: "path=/browser/comm/calendar/test/browser/data/dns.sjs" }];
+ }
+ if (name == "_carddavs._tcp.localhost") {
+ return [
+ {
+ data: "path=/browser/comm/mail/components/addrbook/test/browser/data/dns.sjs",
+ },
+ ];
+ }
+ if (name == "_caldavs._tcp.example-imap.com") {
+ return [{ data: "path=/browser/comm/calendar/test/browser/data/dns.sjs" }];
+ }
+ if (name == "_carddavs._tcp.example-imap.com") {
+ return [
+ {
+ data: "path=/browser/comm/mail/components/addrbook/test/browser/data/dns.sjs",
+ },
+ ];
+ }
+ throw new Error(`Unexpected DNS TXT lookup: ${name}`);
+};
+
+const PREF_NAME = "mailnews.auto_config_url";
+const PREF_VALUE = Services.prefs.getCharPref(PREF_NAME);
+
+// Remove an account in the Account Manager, but not via the UI.
+function remove_account_internal(tab, account, outgoing) {
+ let win = tab.browser.contentWindow;
+
+ // Remove the account and incoming server
+ let serverId = account.incomingServer.serverURI;
+ MailServices.accounts.removeAccount(account);
+ account = null;
+ if (serverId in win.accountArray) {
+ delete win.accountArray[serverId];
+ }
+ win.selectServer(null, null);
+
+ // Remove the outgoing server
+ let smtpKey = outgoing.key;
+ MailServices.smtp.deleteServer(outgoing);
+ win.replaceWithDefaultSmtpServer(smtpKey);
+}
+
+add_task(async function test_mail_account_setup() {
+ originalAlertsServiceCID = MockRegistrar.register(
+ "@mozilla.org/alerts-service;1",
+ MockAlertsService
+ );
+
+ // Set the pref to load a local autoconfig file.
+ let url =
+ "http://mochi.test:8888/browser/comm/mail/test/browser/account/xml/";
+ Services.prefs.setCharPref(PREF_NAME, url);
+
+ let tab = await openAccountSetup();
+ let tabDocument = tab.browser.contentWindow.document;
+
+ // Input user's account information
+ EventUtils.synthesizeMouseAtCenter(
+ tabDocument.getElementById("realname"),
+ {},
+ tab.browser.contentWindow
+ );
+
+ if (tabDocument.getElementById("realname").value) {
+ // If any realname is already filled, clear it out, we have our own.
+ delete_all_existing(mc, tabDocument.getElementById("realname"));
+ }
+ input_value(mc, user.name);
+ EventUtils.synthesizeKey("VK_TAB", {}, mc.window);
+ input_value(mc, user.email);
+ EventUtils.synthesizeKey("VK_TAB", {}, mc.window);
+ input_value(mc, user.password);
+
+ let notificationBox = tab.browser.contentWindow.gAccountSetup.notificationBox;
+
+ let notificationShowed = BrowserTestUtils.waitForCondition(
+ () =>
+ notificationBox.getNotificationWithValue("accountSetupSuccess") != null,
+ "Timeout waiting for error notification to be showed"
+ );
+
+ let popOption = tabDocument.getElementById("resultsOption-pop3");
+ let protocolPOPSelected = BrowserTestUtils.waitForCondition(
+ () => !popOption.hidden && popOption.classList.contains("selected"),
+ "Timeout waiting for the POP3 option to be visible and selected"
+ );
+
+ // Load the autoconfig file from http://localhost:433**/autoconfig/example.com
+ EventUtils.synthesizeMouseAtCenter(
+ tabDocument.getElementById("continueButton"),
+ {},
+ tab.browser.contentWindow
+ );
+
+ // Wait for the successful notification to show up.
+ await notificationShowed;
+
+ // Only the POP protocol should be available, therefore we need to confirm
+ // that the UI is returning only 1 pre-selected protocol.
+ await protocolPOPSelected;
+
+ // Confirm that the IMAP and EXCHANGE options are hidden.
+ Assert.ok(tabDocument.getElementById("resultsOption-imap").hidden);
+ Assert.ok(tabDocument.getElementById("resultsOption-exchange").hidden);
+
+ // Register the prompt service to handle the confirm() dialog
+ gMockPromptService.register();
+ gMockPromptService.returnValue = true;
+
+ // Open the advanced settings (Account Manager) to create the account
+ // immediately. We use an invalid email/password so the setup will fail
+ // anyway.
+ EventUtils.synthesizeMouseAtCenter(
+ tabDocument.getElementById("manualConfigButton"),
+ {},
+ tab.browser.contentWindow
+ );
+
+ await BrowserTestUtils.waitForCondition(
+ () => !tabDocument.getElementById("manualConfigArea").hidden,
+ "Timeout waiting for the manual edit area to become visible"
+ );
+
+ let tabmail = mc.window.document.getElementById("tabmail");
+ let tabChanged = BrowserTestUtils.waitForCondition(
+ () => tabmail.selectedTab != tab,
+ "Timeout waiting for the currently active tab to change"
+ );
+
+ let advancedSetupButton = tabDocument.getElementById("advancedSetupButton");
+ advancedSetupButton.scrollIntoView();
+
+ EventUtils.synthesizeMouseAtCenter(
+ advancedSetupButton,
+ {},
+ tab.browser.contentWindow
+ );
+
+ // Wait for the current Account Setup tab to be closed and the Account
+ // Settings tab to open before running other sub tests.
+ await tabChanged;
+
+ await subtest_verify_account(tabmail.selectedTab, user);
+
+ // Close the Account Settings tab.
+ tabmail.closeTab(tabmail.currentTabInfo);
+
+ // Confirm that we properly updated the folderPaneVisible attribute for the
+ // tabmail when we created the account in the background.
+ Assert.ok(tabmail.currentTabInfo.folderPaneVisible);
+
+ // Confirm that the folder pane is visible.
+ Assert.ok(BrowserTestUtils.is_visible(tabmail.currentAbout3Pane.folderTree));
+
+ let promptState = gMockPromptService.promptState;
+ Assert.equal("confirm", promptState.method);
+
+ // Clean up
+ gMockPromptService.unregister();
+ Services.prefs.setCharPref(PREF_NAME, PREF_VALUE);
+});
+
+async function subtest_verify_account(tab, user) {
+ await BrowserTestUtils.waitForCondition(
+ () => tab.browser.contentWindow.currentAccount != null,
+ "Timeout waiting for current account to become non-null"
+ );
+
+ let account = tab.browser.contentWindow.currentAccount;
+ let identity = account.defaultIdentity;
+ let incoming = account.incomingServer;
+ let outgoing = MailServices.smtp.getServerByKey(identity.smtpServerKey);
+
+ let config = {
+ "incoming server username": {
+ actual: incoming.username,
+ expected: user.email.split("@")[0],
+ },
+ // This was creating test failure.
+ //
+ // "outgoing server username": {
+ // actual: outgoing.username,
+ // expected: user.email,
+ // },
+ "incoming server hostname": {
+ // Note: N in the hostName is uppercase
+ actual: incoming.hostName,
+ expected: user.incomingHost,
+ },
+ "outgoing server hostname": {
+ // And this is lowercase
+ actual: outgoing.hostname,
+ expected: user.outgoingHost,
+ },
+ "user real name": { actual: identity.fullName, expected: user.name },
+ "user email address": { actual: identity.email, expected: user.email },
+ "outgoing description": {
+ actual: outgoing.description,
+ expected: outgoingShortName,
+ },
+ };
+
+ try {
+ for (let i in config) {
+ Assert.equal(
+ config[i].actual,
+ config[i].expected,
+ `Configured ${i} is ${config[i].actual}. It should be ${config[i].expected}.`
+ );
+ }
+ } finally {
+ remove_account_internal(tab, account, outgoing);
+ }
+}
+
+/**
+ * Make sure that we don't re-set the information we get from the config
+ * file if the password is incorrect.
+ */
+add_task(async function test_bad_password_uses_old_settings() {
+ // Set the pref to load a local autoconfig file, that will fetch the
+ // ../account/xml/example.com which contains the settings for the
+ // @example.com email account (see the 'user' object).
+ let url =
+ "http://mochi.test:8888/browser/comm/mail/test/browser/account/xml/";
+ Services.prefs.setCharPref(PREF_NAME, url);
+
+ Services.telemetry.clearScalars();
+
+ let tab = await openAccountSetup();
+ let tabDocument = tab.browser.contentWindow.document;
+
+ // Input user's account information
+ EventUtils.synthesizeMouseAtCenter(
+ tabDocument.getElementById("realname"),
+ {},
+ tab.browser.contentWindow
+ );
+
+ if (tabDocument.getElementById("realname").value) {
+ // If any realname is already filled, clear it out, we have our own.
+ delete_all_existing(mc, tabDocument.getElementById("realname"));
+ }
+ input_value(mc, user.name);
+ EventUtils.synthesizeKey("VK_TAB", {}, mc.window);
+ input_value(mc, user.email);
+ EventUtils.synthesizeKey("VK_TAB", {}, mc.window);
+ input_value(mc, user.password);
+
+ // Load the autoconfig file from http://localhost:433**/autoconfig/example.com
+ EventUtils.synthesizeMouseAtCenter(
+ tabDocument.getElementById("continueButton"),
+ {},
+ tab.browser.contentWindow
+ );
+
+ let createButton = tabDocument.getElementById("createButton");
+ await BrowserTestUtils.waitForCondition(
+ () => !createButton.hidden && !createButton.disabled,
+ "Timeout waiting for create button to become visible and active"
+ );
+
+ let notificationBox = tab.browser.contentWindow.gAccountSetup.notificationBox;
+
+ let notificationShowed = BrowserTestUtils.waitForCondition(
+ () => notificationBox.getNotificationWithValue("accountSetupError") != null,
+ "Timeout waiting for error notification to be showed"
+ );
+
+ createButton.scrollIntoView();
+ EventUtils.synthesizeMouseAtCenter(
+ createButton,
+ {},
+ tab.browser.contentWindow
+ );
+
+ await notificationShowed;
+
+ await BrowserTestUtils.waitForCondition(
+ () => !createButton.disabled,
+ "Timeout waiting for create button to become active"
+ );
+
+ let manualConfigButton = tabDocument.getElementById("manualConfigButton");
+ manualConfigButton.scrollIntoView();
+
+ EventUtils.synthesizeMouseAtCenter(
+ manualConfigButton,
+ {},
+ tab.browser.contentWindow
+ );
+
+ await BrowserTestUtils.waitForCondition(
+ () => !tabDocument.getElementById("manualConfigArea").hidden,
+ "Timeout waiting for the manual edit area to become visible"
+ );
+
+ let outgoingAuthSelect = tabDocument.getElementById("outgoingAuthMethod");
+ // Make sure the select field is inside the viewport.
+ outgoingAuthSelect.scrollIntoView();
+ outgoingAuthSelect.focus();
+
+ let popupOpened = BrowserTestUtils.waitForEvent(
+ document.getElementById("ContentSelectDropdown"),
+ "popupshown"
+ );
+ EventUtils.sendKey("space", tab.browser.contentWindow);
+ await popupOpened;
+
+ // The default value should be on "Normal password", which is after
+ // "No authentication", so we need to go up. We do this on purpose so we can
+ // properly test and track the order of options.
+ EventUtils.sendKey("up", tab.browser.contentWindow);
+
+ let userNameDisabled = BrowserTestUtils.waitForCondition(
+ () => tabDocument.getElementById("outgoingUsername").disabled,
+ "Timeout waiting for the outgoing username field to be disabled"
+ );
+ EventUtils.sendKey("return", tab.browser.contentWindow);
+
+ // Confirm that the outgoing username field is disabled.
+ await userNameDisabled;
+
+ // Revert the outgoing authentication method to "Normal Password".
+ outgoingAuthSelect.focus();
+ popupOpened = BrowserTestUtils.waitForEvent(
+ document.getElementById("ContentSelectDropdown"),
+ "popupshown"
+ );
+ // Change the outgoing authentication method to "No Authentication".
+ EventUtils.sendKey("space", tab.browser.contentWindow);
+ await popupOpened;
+
+ EventUtils.sendKey("down", tab.browser.contentWindow);
+
+ let usernameEnabled = BrowserTestUtils.waitForCondition(
+ () => !tabDocument.getElementById("outgoingUsername").disabled,
+ "Timeout waiting for the outgoing username field to be enabled"
+ );
+ EventUtils.sendKey("return", tab.browser.contentWindow);
+
+ // Confirm that the outgoing username field is enabled.
+ await usernameEnabled;
+
+ let notificationRemoved = BrowserTestUtils.waitForCondition(
+ () => notificationBox.getNotificationWithValue("accountSetupError") == null,
+ "Timeout waiting for error notification to be removed"
+ );
+
+ createButton.scrollIntoView();
+ EventUtils.synthesizeMouseAtCenter(
+ createButton,
+ {},
+ tab.browser.contentWindow
+ );
+
+ // Triggering again the "createButton" should clear previous notifications.
+ await notificationRemoved;
+
+ // Make sure all the values are the same as in the user object.
+ Assert.equal(
+ tabDocument.getElementById("outgoingHostname").value,
+ user.outgoingHost,
+ "Outgoing server changed!"
+ );
+ Assert.equal(
+ tabDocument.getElementById("incomingHostname").value,
+ user.incomingHost,
+ "incoming server changed!"
+ );
+
+ // A new error notification should appear.
+ await BrowserTestUtils.waitForCondition(
+ () => notificationBox.getNotificationWithValue("accountSetupError") != null,
+ "Timeout waiting for error notification to be showed"
+ );
+
+ let scalars = TelemetryTestUtils.getProcessScalars("parent", true);
+ Assert.equal(
+ scalars["tb.account.failed_email_account_setup"]["xml-from-db"],
+ 1,
+ "Count of failed email account setup with xml config must be correct"
+ );
+ Assert.equal(
+ scalars["tb.account.failed_email_account_setup"].user,
+ 1,
+ "Count of failed email account setup with manual config must be correct"
+ );
+
+ // Clean up
+ Services.prefs.setCharPref(PREF_NAME, PREF_VALUE);
+
+ let closeButton = tabDocument.getElementById("cancelButton");
+ closeButton.scrollIntoView();
+
+ EventUtils.synthesizeMouseAtCenter(
+ closeButton,
+ {},
+ tab.browser.contentWindow
+ );
+});
+
+add_task(async function test_remember_password() {
+ await remember_password_test(true);
+ await remember_password_test(false);
+});
+
+/**
+ * Test remember_password checkbox behavior with
+ * signon.rememberSignons set to "aPrefValue"
+ *
+ * @param {boolean} aPrefValue - The preference value for signon.rememberSignons.
+ */
+async function remember_password_test(aPrefValue) {
+ // Save the pref for backup purpose.
+ let rememberSignons_pref_save = Services.prefs.getBoolPref(
+ "signon.rememberSignons",
+ true
+ );
+
+ Services.prefs.setBoolPref("signon.rememberSignons", aPrefValue);
+
+ let tab = await openAccountSetup();
+ let tabDocument = tab.browser.contentWindow.document;
+ let password = tabDocument.getElementById("password");
+ let passwordToggle = tabDocument.getElementById("passwordToggleButton");
+
+ // The password field is empty, so confirm that the toggle button is hidden.
+ Assert.ok(passwordToggle.hidden);
+
+ // Type something in the password field.
+ password.focus();
+ input_value(mc, "testing");
+
+ // The password toggle button should be visible now.
+ Assert.ok(!passwordToggle.hidden);
+
+ // Click on the password toggle button.
+ EventUtils.synthesizeMouseAtCenter(
+ passwordToggle,
+ {},
+ tab.browser.contentWindow
+ );
+
+ // The password field should have being turned into clear text.
+ Assert.equal(password.type, "text");
+
+ // Click on the password toggle button again.
+ EventUtils.synthesizeMouseAtCenter(
+ passwordToggle,
+ {},
+ tab.browser.contentWindow
+ );
+
+ // The password field should have being turned back into a password type.
+ Assert.equal(password.type, "password");
+
+ let rememberPassword = tabDocument.getElementById("rememberPassword");
+ Assert.ok(rememberPassword.disabled != aPrefValue);
+ Assert.equal(rememberPassword.checked, aPrefValue);
+
+ // Empty the password field.
+ delete_all_existing(mc, password);
+
+ // Restore the saved signon.rememberSignons value.
+ Services.prefs.setBoolPref(
+ "signon.rememberSignons",
+ rememberSignons_pref_save
+ );
+
+ let closeButton = tabDocument.getElementById("cancelButton");
+ closeButton.scrollIntoView();
+
+ // Close the wizard.
+ EventUtils.synthesizeMouseAtCenter(
+ closeButton,
+ {},
+ tab.browser.contentWindow
+ );
+}
+
+/**
+ * Test the full account setup with an IMAP account, verifying the correct info
+ * in the final page.
+ */
+add_task(async function test_full_account_setup() {
+ // Initialize the fake IMAP and SMTP server to simulate a real account login.
+ IMAPServer.open();
+ SMTPServer.open();
+
+ // Set the pref to load a local autoconfig file.
+ let url =
+ "http://mochi.test:8888/browser/comm/mail/test/browser/account/xml/";
+ Services.prefs.setCharPref(PREF_NAME, url);
+
+ let tab = await openAccountSetup();
+ let tabDocument = tab.browser.contentWindow.document;
+
+ // If any realname is already filled, clear it out, we have our own.
+ tabDocument.getElementById("realname").value = "";
+
+ // The focus should be on the "realname" input by default, so let's fill it.
+ input_value(mc, imapUser.name);
+ EventUtils.synthesizeKey("VK_TAB", {}, mc.window);
+ input_value(mc, imapUser.email);
+ EventUtils.synthesizeKey("VK_TAB", {}, mc.window);
+ input_value(mc, imapUser.password);
+
+ let notificationBox = tab.browser.contentWindow.gAccountSetup.notificationBox;
+
+ let notificationShowed = BrowserTestUtils.waitForCondition(
+ () =>
+ notificationBox.getNotificationWithValue("accountSetupSuccess") != null,
+ "Timeout waiting for error notification to be showed"
+ );
+
+ let imapOption = tabDocument.getElementById("resultsOption-imap");
+ let protocolIMAPSelected = BrowserTestUtils.waitForCondition(
+ () => !imapOption.hidden && imapOption.classList.contains("selected"),
+ "Timeout waiting for the IMAP option to be visible and selected"
+ );
+
+ // Since we're focused inside a form, pressing "Enter" should submit it.
+ EventUtils.synthesizeKey("VK_RETURN", {}, mc.window);
+
+ // Wait for the successful notification to show up.
+ await notificationShowed;
+
+ // Confirm the IMAP protocol is visible and selected.
+ await protocolIMAPSelected;
+
+ let finalViewShowed = BrowserTestUtils.waitForCondition(
+ () => !tabDocument.getElementById("successView").hidden,
+ "Timeout waiting for the final page to be visible"
+ );
+
+ let insecureDialogShowed = BrowserTestUtils.waitForCondition(
+ () => tabDocument.getElementById("insecureDialog").open,
+ "Timeout waiting for the #insecureDialog to be visible"
+ );
+
+ // Press "Enter" again to proceed with the account creation.
+ tabDocument.getElementById("createButton").focus();
+ EventUtils.synthesizeKey("VK_RETURN", {}, mc.window);
+
+ // Since we're using plain authentication in the mock IMAP server, the
+ // insecure warning dialog should appear. Let's wait for it.
+ await insecureDialogShowed;
+
+ // Click the acknowledge checkbox and confirm the insecure dialog.
+ let acknowledgeCheckbox = tabDocument.getElementById("acknowledgeWarning");
+ acknowledgeCheckbox.scrollIntoView();
+
+ EventUtils.synthesizeMouseAtCenter(
+ acknowledgeCheckbox,
+ {},
+ tab.browser.contentWindow
+ );
+
+ // Prepare to handle the linked services notification.
+ let syncingBox = tab.browser.contentWindow.gAccountSetup.syncingBox;
+
+ let syncingNotificationShowed = BrowserTestUtils.waitForCondition(
+ () => syncingBox.getNotificationWithValue("accountSetupLoading") != null,
+ "Timeout waiting for the syncing notification to be removed"
+ );
+
+ let syncingNotificationRemoved = BrowserTestUtils.waitForCondition(
+ () => !syncingBox.getNotificationWithValue("accountSetupLoading"),
+ "Timeout waiting for the syncing notification to be removed"
+ );
+
+ let confirmButton = tabDocument.getElementById("insecureConfirmButton");
+ confirmButton.scrollIntoView();
+
+ // Close the insecure dialog.
+ EventUtils.synthesizeMouseAtCenter(
+ confirmButton,
+ {},
+ tab.browser.contentWindow
+ );
+
+ // The final page should be visible.
+ await finalViewShowed;
+
+ let tabmail = mc.window.document.getElementById("tabmail");
+
+ // The tab shouldn't change even if we created a new account.
+ Assert.equal(tab, tabmail.selectedTab, "Tab should should still be the same");
+
+ // Assert the UI is properly filled with the new account info.
+ Assert.equal(
+ tabDocument.getElementById("newAccountName").textContent,
+ imapUser.name
+ );
+ Assert.equal(
+ tabDocument.getElementById("newAccountEmail").textContent,
+ imapUser.email
+ );
+ Assert.equal(
+ tabDocument.getElementById("newAccountProtocol").textContent,
+ "imap"
+ );
+
+ // The fetching of connected address books and calendars should start.
+ await syncingNotificationShowed;
+
+ // Wait for the fetching of address books and calendars to end.
+ await syncingNotificationRemoved;
+
+ // Wait for the linked address book section to be visible.
+ let addressBookSection = tabDocument.getElementById("linkedAddressBooks");
+ await TestUtils.waitForCondition(
+ () => BrowserTestUtils.is_visible(addressBookSection),
+ "linked address book section visible",
+ 250
+ );
+
+ // The section should be expanded already.
+ let abList = tabDocument.querySelector(
+ "#addressBooksSetup .linked-services-list"
+ );
+ Assert.ok(BrowserTestUtils.is_visible(abList), "address book list visible");
+
+ // Check the linked address book was found.
+ Assert.equal(abList.childElementCount, 1);
+ Assert.equal(
+ abList.querySelector("li > span.protocol-type").textContent,
+ "CardDAV"
+ );
+ Assert.equal(
+ abList.querySelector("li > span.list-item-name").textContent,
+ "You found me!"
+ );
+
+ // Connect the linked address book.
+ let abDirectoryPromise = TestUtils.topicObserved("addrbook-directory-synced");
+ EventUtils.synthesizeMouseAtCenter(
+ abList.querySelector("li > button.small-button"),
+ {},
+ tab.browser.contentWindow
+ );
+ let [abDirectory] = await abDirectoryPromise;
+ Assert.equal(abDirectory.dirName, "You found me!");
+ Assert.equal(abDirectory.dirType, Ci.nsIAbManager.CARDDAV_DIRECTORY_TYPE);
+ Assert.equal(
+ abDirectory.getStringValue("carddav.url", ""),
+ "https://example.org/browser/comm/mail/components/addrbook/test/browser/data/addressbook.sjs"
+ );
+
+ // Wait for the linked calendar section to be visible.
+ let calendarSection = tabDocument.getElementById("linkedCalendars");
+ await TestUtils.waitForCondition(
+ () => BrowserTestUtils.is_visible(calendarSection),
+ "linked calendar section visible",
+ 250
+ );
+
+ // The section should be expanded already.
+ let calendarList = tabDocument.querySelector(
+ "#calendarsSetup .linked-services-list"
+ );
+ Assert.ok(BrowserTestUtils.is_visible(calendarList), "calendar list visible");
+
+ // Check the linked calendar was found.
+ Assert.equal(calendarList.childElementCount, 2);
+ Assert.equal(
+ calendarList.querySelector("li > span.protocol-type").textContent,
+ "CalDAV"
+ );
+ Assert.equal(
+ calendarList.querySelector("li > span.list-item-name").textContent,
+ "You found me!"
+ );
+ Assert.equal(
+ calendarList.querySelector("li:nth-child(2) > span.protocol-type")
+ .textContent,
+ "CalDAV"
+ );
+ Assert.equal(
+ calendarList.querySelector("li:nth-child(2) > span.list-item-name")
+ .textContent,
+ "Röda dagar"
+ );
+
+ // Connect the linked calendar.
+ let calendarPromise = new Promise(resolve => {
+ let observer = {
+ onCalendarRegistered(calendar) {
+ cal.manager.removeObserver(this);
+ resolve(calendar);
+ },
+ onCalendarUnregistering() {},
+ onCalendarDeleting() {},
+ };
+ cal.manager.addObserver(observer);
+ });
+
+ let calendarDialogShowed = BrowserTestUtils.waitForCondition(
+ () => tabDocument.getElementById("calendarDialog").open,
+ "Timeout waiting for the #calendarDialog to be visible"
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ calendarList.querySelector("li > button.small-button"),
+ {},
+ tab.browser.contentWindow
+ );
+ await calendarDialogShowed;
+ EventUtils.synthesizeMouseAtCenter(
+ tabDocument.getElementById("calendarDialogConfirmButton"),
+ {},
+ tab.browser.contentWindow
+ );
+
+ let calendar = await calendarPromise;
+ Assert.equal(calendar.name, "You found me!");
+ Assert.equal(calendar.type, "caldav");
+ // This address doesn't need to actually exist for the test to pass.
+ Assert.equal(
+ calendar.uri.spec,
+ "https://example.org/browser/comm/calendar/test/browser/data/calendar.sjs"
+ );
+
+ let logins = Services.logins.findLogins("https://example.org", null, "");
+ Assert.equal(logins.length, 1);
+ Assert.equal(
+ logins[0].username,
+ imapUser.email,
+ "username was saved for linked address book/calendar"
+ );
+ Assert.equal(
+ logins[0].password,
+ imapUser.password,
+ "password was saved for linked address book/calendar"
+ );
+
+ let tabChanged = BrowserTestUtils.waitForCondition(
+ () => tabmail.selectedTab != tab,
+ "Timeout waiting for the currently active tab to change"
+ );
+
+ let finishButton = tabDocument.getElementById("finishButton");
+ finishButton.focus();
+ finishButton.scrollIntoView();
+
+ // Close the wizard.
+ EventUtils.synthesizeMouseAtCenter(
+ finishButton,
+ {},
+ tab.browser.contentWindow
+ );
+
+ await tabChanged;
+
+ // Confirm the mail 3 pane is the currently selected tab.
+ Assert.equal(
+ tabmail.selectedTab.mode.name,
+ "mail3PaneTab",
+ "The currently selected tab is the primary Mail tab"
+ );
+
+ // Remove the address book and calendar.
+ MailServices.ab.deleteAddressBook(abDirectory.URI);
+ cal.manager.removeCalendar(calendar);
+
+ // Restore the original pref.
+ Services.prefs.setCharPref(PREF_NAME, PREF_VALUE);
+
+ // Wait for Thunderbird to connect to the server and check for messages.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, 1000));
+
+ IMAPServer.close();
+ SMTPServer.close();
+ Services.logins.removeAllLogins();
+});
+
+registerCleanupFunction(function () {
+ MockRegistrar.unregister(originalAlertsServiceCID);
+ DNS.srv = _srv;
+ DNS.txt = _txt;
+});