summaryrefslogtreecommitdiffstats
path: root/comm/mail/test/browser/folder-pane
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/test/browser/folder-pane')
-rw-r--r--comm/mail/test/browser/folder-pane/browser.ini49
-rw-r--r--comm/mail/test/browser/folder-pane/browser_displayMessageWithFolderModes.js250
-rw-r--r--comm/mail/test/browser/folder-pane/browser_folderNamesInRecentMode.js117
-rw-r--r--comm/mail/test/browser/folder-pane/browser_folderPane.js136
-rw-r--r--comm/mail/test/browser/folder-pane/browser_folderPaneConsumers.js143
-rw-r--r--comm/mail/test/browser/folder-pane/browser_folderPaneHeader.js945
-rw-r--r--comm/mail/test/browser/folder-pane/browser_folderPaneModeContextMenu.js208
7 files changed, 1848 insertions, 0 deletions
diff --git a/comm/mail/test/browser/folder-pane/browser.ini b/comm/mail/test/browser/folder-pane/browser.ini
new file mode 100644
index 0000000000..90ec2e2b31
--- /dev/null
+++ b/comm/mail/test/browser/folder-pane/browser.ini
@@ -0,0 +1,49 @@
+[DEFAULT]
+prefs =
+ mail.account.account2.identities=id1,id2
+ mail.account.account2.server=server2
+ mail.accountmanager.accounts=account2
+ mail.accountmanager.defaultaccount=account2
+ mail.identity.id1.fullName=Tinderbox
+ mail.identity.id1.htmlSigFormat=false
+ mail.identity.id1.smtpServer=smtp1
+ mail.identity.id1.useremail=tinderbox@foo.invalid
+ mail.identity.id1.valid=true
+ mail.identity.id2.fullName=Tinderboxpushlog
+ mail.identity.id2.htmlSigFormat=true
+ mail.identity.id2.smtpServer=smtp1
+ mail.identity.id2.useremail=tinderboxpushlog@foo.invalid
+ mail.identity.id2.valid=true
+ mail.provider.suppress_dialog_on_startup=true
+ mail.server.server2.check_new_mail=false
+ mail.server.server2.directory-rel=[ProfD]Mail/tinderbox
+ mail.server.server2.download_on_biff=true
+ mail.server.server2.hostname=tinderbox123
+ mail.server.server2.login_at_startup=false
+ mail.server.server2.name=tinderbox@foo.invalid
+ mail.server.server2.type=pop3
+ mail.server.server2.userName=tinderbox
+ mail.server.server2.whiteListAbURI=
+ mail.shell.checkDefaultClient=false
+ mail.smtp.defaultserver=smtp1
+ mail.smtpserver.smtp1.hostname=tinderbox123
+ mail.smtpserver.smtp1.username=tinderbox
+ mail.smtpservers=smtp1
+ mail.spotlight.firstRunDone=true
+ mail.startup.enabledMailCheckOnce=true
+ mail.winsearch.firstRunDone=true
+ mailnews.start_page.override_url=about:blank
+ mailnews.start_page.url=about:blank
+ ui.prefersReducedMotion=1
+subsuite = thunderbird
+
+[browser_displayMessageWithFolderModes.js]
+skip-if = true # TODO
+[browser_folderNamesInRecentMode.js]
+skip-if = true # TODO
+[browser_folderPane.js]
+[browser_folderPaneConsumers.js]
+skip-if = true # TODO
+# skip-if = os == 'mac'
+[browser_folderPaneHeader.js]
+[browser_folderPaneModeContextMenu.js]
diff --git a/comm/mail/test/browser/folder-pane/browser_displayMessageWithFolderModes.js b/comm/mail/test/browser/folder-pane/browser_displayMessageWithFolderModes.js
new file mode 100644
index 0000000000..71d448a068
--- /dev/null
+++ b/comm/mail/test/browser/folder-pane/browser_displayMessageWithFolderModes.js
@@ -0,0 +1,250 @@
+/* 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/. */
+
+/*
+ * Test that displaying messages in folder tabs works correctly with folder
+ * modes. This includes:
+ * - switching to the default folder mode if the folder isn't present in the
+ * current folder mode
+ * - not switching otherwise
+ * - making sure that we're able to expand the right folders in the smart folder
+ * mode
+ */
+
+"use strict";
+
+var {
+ assert_folder_child_in_view,
+ assert_folder_collapsed,
+ assert_folder_expanded,
+ assert_folder_mode,
+ assert_folder_not_visible,
+ assert_folder_selected_and_displayed,
+ assert_folder_tree_view_row_count,
+ assert_folder_visible,
+ assert_message_not_in_view,
+ assert_selected_and_displayed,
+ be_in_folder,
+ collapse_folder,
+ display_message_in_folder_tab,
+ get_smart_folder_named,
+ inboxFolder,
+ make_message_sets_in_folders,
+ mc,
+ select_none,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+
+var folder;
+var dummyFolder;
+var inbox2Folder;
+var smartInboxFolder;
+
+var msgHdr;
+
+add_setup(async function () {
+ assert_folder_mode("all");
+ assert_folder_tree_view_row_count(7);
+
+ // This is a subfolder of the inbox so that
+ // test_display_message_in_smart_folder_mode_works is able to test that we
+ // don't attempt to expand any inboxes.
+ inboxFolder.createSubfolder("DisplayMessageWithFolderModesA", null);
+ folder = inboxFolder.getChildNamed("DisplayMessageWithFolderModesA");
+ // This second folder is meant to act as a dummy folder to switch to when we
+ // want to not be in folder.
+ inboxFolder.createSubfolder("DisplayMessageWithFolderModesB", null);
+ dummyFolder = inboxFolder.getChildNamed("DisplayMessageWithFolderModesB");
+ await make_message_sets_in_folders([folder], [{ count: 5 }]);
+ // The message itself doesn't really matter, as long as there's at least one
+ // in the inbox. We will delete this in teardownModule because the inbox
+ // is a shared resource and it's not okay to leave stuff in there.
+ await make_message_sets_in_folders([inboxFolder], [{ count: 1 }]);
+
+ // Create another subfolder on the top level that is not a parent of the
+ // 2 folders so that it is not visible in Favorite mode.
+ inboxFolder.server.rootFolder.createSubfolder("Inbox2", null);
+ inbox2Folder = inboxFolder.server.rootFolder.getChildNamed("Inbox2");
+
+ await be_in_folder(folder);
+ msgHdr = mc.window.gFolderDisplay.view.dbView.getMsgHdrAt(0);
+});
+
+/**
+ * Test that displaying a message causes a switch to the default folder mode if
+ * the folder isn't present in the current folder mode.
+ */
+add_task(
+ async function test_display_message_with_folder_not_present_in_current_folder_mode() {
+ // Make sure the folder doesn't appear in the favorite folder mode just
+ // because it was selected last before switching
+ await be_in_folder(inboxFolder);
+
+ // Enable the favorite folders view. This folder isn't currently a favorite
+ // folder.
+ mc.folderTreeView.activeModes = "favorite";
+ // Hide the all folders view. The activeModes setter takes care of removing
+ // the mode is is already visible.
+ mc.folderTreeView.activeModes = "all";
+
+ assert_folder_not_visible(folder);
+ assert_folder_not_visible(inboxFolder);
+ assert_folder_not_visible(inbox2Folder);
+
+ // Try displaying a message
+ display_message_in_folder_tab(msgHdr);
+
+ assert_folder_mode("favorite");
+ assert_folder_selected_and_displayed(folder);
+ assert_selected_and_displayed(msgHdr);
+ }
+);
+
+/**
+ * Test that displaying a message _does not_ cause a switch to the default
+ * folder mode if the folder is present in the current folder mode.
+ */
+add_task(
+ async function test_display_message_with_folder_present_in_current_folder_mode() {
+ // Mark the folder as a favorite
+ folder.setFlag(Ci.nsMsgFolderFlags.Favorite);
+ // Also mark the dummy folder as a favorite, in preparation for
+ // test_display_message_in_smart_folder_mode_works
+ dummyFolder.setFlag(Ci.nsMsgFolderFlags.Favorite);
+
+ // Make sure the folder doesn't appear in the favorite folder mode just
+ // because it was selected last before switching
+ await be_in_folder(inboxFolder);
+
+ // Hide the all folders view. The activeModes setter takes care of removing
+ // the mode if is already visible.
+ mc.folderTreeView.activeModes = "all";
+
+ // Select the folder to open the parent row.
+ await be_in_folder(folder);
+
+ assert_folder_visible(folder);
+ assert_folder_visible(dummyFolder);
+ // Also their parent folder should be visible.
+ assert_folder_visible(inboxFolder);
+ // But not a sibling of their parent, which is not Favorite.
+ assert_folder_not_visible(inbox2Folder);
+
+ // Try displaying a message
+ display_message_in_folder_tab(msgHdr);
+
+ assert_folder_mode("favorite");
+ assert_folder_selected_and_displayed(folder);
+ assert_selected_and_displayed(msgHdr);
+
+ // Now unset the flags so that we don't affect later tests.
+ folder.clearFlag(Ci.nsMsgFolderFlags.Favorite);
+ dummyFolder.clearFlag(Ci.nsMsgFolderFlags.Favorite);
+ }
+);
+
+/**
+ * Test that displaying a message in smart folders mode causes the parent in the
+ * view to expand.
+ */
+add_task(async function test_display_message_in_smart_folder_mode_works() {
+ // Clear the message selection, otherwise msgHdr will still be displayed and
+ // display_message_in_folder_tab(msgHdr) will be a no-op.
+ select_none();
+ // Show the smart folder view before removing the favorite view.
+ mc.folderTreeView.activeModes = "smart";
+ // Hide the favorite view. The activeModes setter takes care of removing a
+ // view if is currently active.
+ mc.folderTreeView.activeModes = "favorite";
+
+ // Switch to the dummy folder, otherwise msgHdr will be in the view and the
+ // display message in folder tab logic will simply select the message without
+ // bothering to expand any folders.
+ await be_in_folder(dummyFolder);
+
+ let rootFolder = folder.server.rootFolder;
+ // Check that the folder is actually the child of the account root
+ assert_folder_child_in_view(folder, rootFolder);
+
+ // Collapse everything
+ smartInboxFolder = get_smart_folder_named("Inbox");
+ collapse_folder(smartInboxFolder);
+ assert_folder_collapsed(smartInboxFolder);
+ collapse_folder(rootFolder);
+ assert_folder_collapsed(rootFolder);
+ assert_folder_not_visible(folder);
+
+ // Try displaying the message
+ display_message_in_folder_tab(msgHdr);
+
+ // Check that the right folders have expanded
+ assert_folder_mode("smart");
+ assert_folder_collapsed(smartInboxFolder);
+ assert_folder_expanded(rootFolder);
+ assert_folder_selected_and_displayed(folder);
+ assert_selected_and_displayed(msgHdr);
+});
+
+/**
+ * Test that displaying a message in an inbox in smart folders mode causes the
+ * message to be displayed in the smart inbox.
+ */
+add_task(
+ async function test_display_inbox_message_in_smart_folder_mode_works() {
+ await be_in_folder(inboxFolder);
+ let inboxMsgHdr = mc.window.gFolderDisplay.view.dbView.getMsgHdrAt(0);
+
+ // Collapse everything
+ collapse_folder(smartInboxFolder);
+ assert_folder_collapsed(smartInboxFolder);
+ assert_folder_not_visible(inboxFolder);
+ let rootFolder = folder.server.rootFolder;
+ collapse_folder(rootFolder);
+ assert_folder_collapsed(rootFolder);
+
+ // Move to a different folder
+ await be_in_folder(get_smart_folder_named("Trash"));
+ assert_message_not_in_view(inboxMsgHdr);
+
+ // Try displaying the message
+ display_message_in_folder_tab(inboxMsgHdr);
+
+ // Check that nothing has expanded, and that the right folder is selected
+ assert_folder_mode("smart");
+ assert_folder_collapsed(smartInboxFolder);
+ assert_folder_collapsed(rootFolder);
+ assert_folder_selected_and_displayed(smartInboxFolder);
+ assert_selected_and_displayed(inboxMsgHdr);
+ }
+);
+
+/**
+ * Move back to the all folders mode.
+ */
+add_task(function test_switch_to_all_folders() {
+ // Hide the smart folders view enabled in the previous test. The activeModes
+ // setter should take care of restoring the "all" view and prevent and empty
+ // Folder pane.
+ mc.folderTreeView.activeModes = "smart";
+ assert_folder_mode("all");
+ assert_folder_tree_view_row_count(10);
+});
+
+registerCleanupFunction(function () {
+ // Remove our folders
+ inboxFolder.propagateDelete(folder, true);
+ inboxFolder.propagateDelete(dummyFolder, true);
+ inboxFolder.server.rootFolder.propagateDelete(inbox2Folder, true);
+ assert_folder_tree_view_row_count(7);
+
+ document.getElementById("folderTree").focus();
+
+ Assert.report(
+ false,
+ undefined,
+ undefined,
+ "Test ran to completion successfully"
+ );
+});
diff --git a/comm/mail/test/browser/folder-pane/browser_folderNamesInRecentMode.js b/comm/mail/test/browser/folder-pane/browser_folderNamesInRecentMode.js
new file mode 100644
index 0000000000..a5f99f32d1
--- /dev/null
+++ b/comm/mail/test/browser/folder-pane/browser_folderNamesInRecentMode.js
@@ -0,0 +1,117 @@
+/* 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/. */
+
+/**
+ * Test that the folder names have account name appended when in "recent" view.
+ */
+
+"use strict";
+
+var {
+ assert_folder_at_index_as,
+ assert_folder_mode,
+ assert_folder_tree_view_row_count,
+ be_in_folder,
+ make_message_sets_in_folders,
+ mc,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+add_setup(function () {
+ assert_folder_mode("all");
+ assert_folder_tree_view_row_count(7);
+});
+
+add_task(async function test_folder_names_in_recent_view_mode() {
+ // We need 2 local accounts that have pristine folders with
+ // unmodified times, so that it does not influence the
+ // list of Recent folders. So clear out the most-recently-used time.
+ for (let acc of MailServices.accounts.accounts) {
+ for (let fld of acc.incomingServer.rootFolder.subFolders) {
+ fld.setStringProperty("MRUTime", "0");
+ }
+ }
+
+ let acc1 = MailServices.accounts.accounts[1];
+ let acc2 = MailServices.accounts.accounts[0];
+ let rootFolder1 = acc1.incomingServer.rootFolder;
+ let rootFolder2 = acc2.incomingServer.rootFolder;
+
+ // Create some test folders.
+ rootFolder1.createSubfolder("uniqueName", null);
+ rootFolder1.createSubfolder("duplicatedName", null);
+ rootFolder2.createSubfolder("duplicatedName", null);
+ let inbox2 = rootFolder2.getFolderWithFlags(Ci.nsMsgFolderFlags.Inbox);
+ inbox2.createSubfolder("duplicatedName", null);
+
+ let fUnique = rootFolder1.getChildNamed("uniqueName");
+ let fDup1 = rootFolder1.getChildNamed("duplicatedName");
+ let fDup2 = rootFolder2.getChildNamed("duplicatedName");
+ let fDup3 = inbox2.getChildNamed("duplicatedName");
+
+ // Close the inbox folder if open. This might happen when running multiple
+ // tests from the folder-pane.
+ let index = mc.window.gFolderTreeView.getIndexOfFolder(inbox2);
+ if (index != null) {
+ if (mc.window.gFolderTreeView._rowMap[index].open) {
+ mc.window.gFolderTreeView._toggleRow(index, false);
+ }
+ }
+ assert_folder_tree_view_row_count(10);
+
+ // Create some messages in the folders to make them recently used.
+ await make_message_sets_in_folders([fUnique], [{ count: 1 }]);
+ await be_in_folder(fUnique);
+ await make_message_sets_in_folders([fDup1], [{ count: 1 }]);
+ await be_in_folder(fDup1);
+ await make_message_sets_in_folders([fDup2], [{ count: 2 }]);
+ await be_in_folder(fDup2);
+ await make_message_sets_in_folders([fDup3], [{ count: 3 }]);
+ await be_in_folder(fDup3);
+
+ // Enable the recent folder view.
+ mc.window.gFolderTreeView.activeModes = "recent";
+ // Hide the all folder view by passing the value to the setter, which will
+ // take care of toggling off the view if currently visible.
+ mc.window.gFolderTreeView.activeModes = "all";
+
+ // Check displayed folder names.
+ // In Recent mode the folders are sorted alphabetically and the first index is
+ // the Mode Header item.
+ assert_folder_at_index_as(0, "Recent Folders");
+ assert_folder_at_index_as(1, "duplicatedName - Local Folders (1)");
+ assert_folder_at_index_as(2, "duplicatedName - tinderbox@foo.invalid (3)");
+ assert_folder_at_index_as(3, "duplicatedName - tinderbox@foo.invalid (2)");
+ assert_folder_at_index_as(4, "uniqueName - Local Folders (1)");
+ assert_folder_tree_view_row_count(5);
+
+ // Remove our folders to clean up.
+ rootFolder1.propagateDelete(fUnique, true);
+ rootFolder1.propagateDelete(fDup1, true);
+ rootFolder2.propagateDelete(fDup2, true);
+ rootFolder2.propagateDelete(fDup3, true);
+});
+
+registerCleanupFunction(function () {
+ // Hide the recent folders view enabled in the previous test. The activeModes
+ // setter should take care of restoring the "all" view and prevent and empty
+ // Folder pane.
+ mc.window.gFolderTreeView.activeModes = "recent";
+ assert_folder_mode("all");
+ assert_folder_tree_view_row_count(7);
+
+ document.getElementById("folderTree").focus();
+
+ Assert.report(
+ false,
+ undefined,
+ undefined,
+ "Test ran to completion successfully"
+ );
+});
diff --git a/comm/mail/test/browser/folder-pane/browser_folderPane.js b/comm/mail/test/browser/folder-pane/browser_folderPane.js
new file mode 100644
index 0000000000..5b4ca546ff
--- /dev/null
+++ b/comm/mail/test/browser/folder-pane/browser_folderPane.js
@@ -0,0 +1,136 @@
+/* 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/. */
+
+/*
+ * Tests for the folder pane, in particular the tree view. This is kept separate
+ * from the main folder-display suite so that the folders created by other tests
+ * there don't influence the results here.
+ */
+
+"use strict";
+
+var {
+ FAKE_SERVER_HOSTNAME,
+ assert_folder_mode,
+ assert_folder_tree_view_row_count,
+ be_in_folder,
+ collapse_folder,
+ create_folder,
+ enter_folder,
+ expand_folder,
+ get_about_3pane,
+ mc,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+
+var { MailUtils } = ChromeUtils.import("resource:///modules/MailUtils.jsm");
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+/**
+ * Assert the Folder Pane is in All Folder mode by default. Check that the
+ * correct number of rows for accounts and folders are always shown as new
+ * folders are created, expanded, and collapsed.
+ */
+add_task(async function test_all_folders_toggle_folder_open_state() {
+ // Test that we are in All Folders mode by default
+ assert_folder_mode("all");
+
+ let pop3Server = MailServices.accounts.findServer(
+ "tinderbox",
+ FAKE_SERVER_HOSTNAME,
+ "pop3"
+ );
+ collapse_folder(pop3Server.rootFolder);
+ collapse_folder(MailServices.accounts.localFoldersServer.rootFolder);
+
+ // All folders mode should give us only 2 rows to start
+ // (tinderbox account and local folders)
+ let accounts = 2;
+ assert_folder_tree_view_row_count(accounts);
+
+ let inbox = 1;
+ let trash = 1;
+ let outbox = 1;
+ let archives = 1;
+ let folderPaneA = 1;
+ // Create archives folder - this is ugly, but essentially the same as
+ // what mailWindowOverlay.js does. We can't use the built-in helper
+ // method to create the folder because we need the archive flag to get
+ // set before the folder added notification is sent out, which means
+ // creating the folder object via RDF, setting the flag, and then
+ // creating the storage, which sends the notification.
+ let folder = MailUtils.getOrCreateFolder(
+ pop3Server.rootFolder.URI + "/Archives"
+ );
+ folder.setFlag(Ci.nsMsgFolderFlags.Archive);
+ folder.createStorageIfMissing(null);
+ // After creating Archives, account should have expanded
+ // so that we should have 5 rows visible
+ assert_folder_tree_view_row_count(accounts + inbox + trash + archives);
+ // close the tinderbox server.
+ collapse_folder(pop3Server.rootFolder);
+ let folderA = await create_folder("FolderPaneA");
+ await be_in_folder(folderA);
+
+ // After creating our first folder we should have 6 rows visible
+ assert_folder_tree_view_row_count(
+ accounts + inbox + trash + outbox + folderPaneA
+ );
+
+ let about3Pane = get_about_3pane();
+ let oneFolderCount = about3Pane.folderTree.rowCount;
+
+ // This makes sure the folder can be toggled
+ folderA.createSubfolder("FolderPaneB", null);
+ let folderB = folderA.getChildNamed("FolderPaneB");
+ // Enter folderB, then enter folderA. This makes sure that folderA is not
+ // collapsed.
+ await enter_folder(folderB);
+ await enter_folder(folderA);
+
+ // At this point folderA should be open, so the view should have one more
+ // item than before (FolderPaneB).
+ assert_folder_tree_view_row_count(oneFolderCount + 1);
+
+ // Toggle the open state of folderA
+ collapse_folder(folderA);
+
+ // folderA should be collapsed so we are back to the original count
+ assert_folder_tree_view_row_count(oneFolderCount);
+
+ // Toggle it back to open
+ expand_folder(folderA);
+
+ // folderB should be visible again
+ assert_folder_tree_view_row_count(oneFolderCount + 1);
+
+ // Close folderA and delete folderB.
+ collapse_folder(folderA);
+ MailServices.accounts.localFoldersServer.rootFolder.propagateDelete(
+ folderB,
+ true
+ );
+ // Open folderA again and check folderB is deleted.
+ expand_folder(folderA);
+ assert_folder_tree_view_row_count(oneFolderCount);
+
+ // Clean up
+ expand_folder(pop3Server.rootFolder);
+ folder.clearFlag(Ci.nsMsgFolderFlags.Archive);
+ pop3Server.rootFolder.propagateDelete(folder, true, null);
+ MailServices.accounts.localFoldersServer.rootFolder.propagateDelete(
+ folderA,
+ true
+ );
+
+ Assert.report(
+ false,
+ undefined,
+ undefined,
+ "Test ran to completion successfully"
+ );
+});
diff --git a/comm/mail/test/browser/folder-pane/browser_folderPaneConsumers.js b/comm/mail/test/browser/folder-pane/browser_folderPaneConsumers.js
new file mode 100644
index 0000000000..a6c88f9c7c
--- /dev/null
+++ b/comm/mail/test/browser/folder-pane/browser_folderPaneConsumers.js
@@ -0,0 +1,143 @@
+/* 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/. */
+
+/*
+ * Tests for other dialogs using the tree view implementation in folderPane.js.
+ */
+
+/* globals gFolderTreeView */
+
+"use strict";
+
+var { mc } = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+var { NNTP_PORT, setupLocalServer } = ChromeUtils.import(
+ "resource://testing-common/mozmill/NNTPHelpers.jsm"
+);
+var { plan_for_modal_dialog, wait_for_modal_dialog } = ChromeUtils.import(
+ "resource://testing-common/mozmill/WindowHelpers.jsm"
+);
+var { click_menus_in_sequence } = ChromeUtils.import(
+ "resource://testing-common/mozmill/WindowHelpers.jsm"
+);
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+var nntpAccount;
+
+add_setup(function () {
+ gFolderTreeView.selectFolder(gFolderTreeView._enumerateFolders[1]);
+
+ let server = setupLocalServer(NNTP_PORT);
+ nntpAccount = MailServices.accounts.FindAccountForServer(server);
+});
+
+add_task(async function test_virtual_folder_selection_tree() {
+ plan_for_modal_dialog(
+ "mailnews:virtualFolderProperties",
+ subtest_create_virtual_folder
+ );
+
+ document.getElementById("toolbar-menubar").removeAttribute("autohide");
+
+ EventUtils.synthesizeMouseAtCenter(
+ mc.window.document.getElementById("menu_File"),
+ {},
+ mc.window.document.getElementById("menu_File").ownerGlobal
+ );
+ await click_menus_in_sequence(
+ mc.window.document.getElementById("menu_FilePopup"),
+ [{ id: "menu_New" }, { id: "menu_newVirtualFolder" }]
+ );
+
+ wait_for_modal_dialog("mailnews:virtualFolderProperties");
+});
+
+function subtest_create_virtual_folder(vfc) {
+ // Open the folder chooser.
+ plan_for_modal_dialog(
+ "mailnews:virtualFolderList",
+ subtest_check_virtual_folder_list
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ vfc.window.document.getElementById("folderListPicker"),
+ {},
+ vfc.window.document.getElementById("folderListPicker").ownerGlobal
+ );
+ wait_for_modal_dialog("mailnews:virtualFolderList");
+
+ vfc.window.document.documentElement.querySelector("dialog").cancelDialog();
+}
+
+/**
+ * Bug 464710
+ * Check the folder list picker is not empty.
+ */
+function subtest_check_virtual_folder_list(listc) {
+ let tree = listc.window.document.getElementById("folderPickerTree");
+ // We should see the folders from the 2 base local accounts here.
+ Assert.ok(
+ tree.view.rowCount > 0,
+ "Folder tree was empty in virtual folder selection!"
+ );
+ listc.window.document.documentElement.querySelector("dialog").cancelDialog();
+}
+
+add_task(async function test_offline_sync_folder_selection_tree() {
+ plan_for_modal_dialog("mailnews:synchronizeOffline", subtest_offline_sync);
+
+ document.getElementById("toolbar-menubar").removeAttribute("autohide");
+
+ EventUtils.synthesizeMouseAtCenter(
+ mc.window.document.getElementById("menu_File"),
+ {},
+ mc.window.document.getElementById("menu_File").ownerGlobal
+ );
+ await click_menus_in_sequence(
+ mc.window.document.getElementById("menu_FilePopup"),
+ [{ id: "offlineMenuItem" }, { id: "menu_synchronizeOffline" }]
+ );
+
+ wait_for_modal_dialog("mailnews:synchronizeOffline");
+});
+
+function subtest_offline_sync(osc) {
+ // Open the folder chooser.
+ plan_for_modal_dialog(
+ "mailnews:selectOffline",
+ subtest_check_offline_folder_list
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ osc.window.document.getElementById("select"),
+ {},
+ osc.window.document.getElementById("select").ownerGlobal
+ );
+ wait_for_modal_dialog("mailnews:selectOffline");
+
+ osc.window.document.documentElement.querySelector("dialog").cancelDialog();
+}
+
+/**
+ * Bug 464710
+ * Check the folder list picker is not empty.
+ */
+function subtest_check_offline_folder_list(listc) {
+ let tree = listc.window.document.getElementById("synchronizeTree");
+ // We should see the newsgroups from the NNTP server here.
+ Assert.ok(
+ tree.view.rowCount > 0,
+ "Folder tree was empty in offline sync selection!"
+ );
+ listc.window.document.documentElement.querySelector("dialog").cancelDialog();
+}
+
+registerCleanupFunction(function () {
+ MailServices.accounts.removeAccount(nntpAccount);
+
+ document.getElementById("toolbar-menubar").autohide = true;
+ document.getElementById("folderTree").focus();
+});
diff --git a/comm/mail/test/browser/folder-pane/browser_folderPaneHeader.js b/comm/mail/test/browser/folder-pane/browser_folderPaneHeader.js
new file mode 100644
index 0000000000..1a66df37d5
--- /dev/null
+++ b/comm/mail/test/browser/folder-pane/browser_folderPaneHeader.js
@@ -0,0 +1,945 @@
+/* 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/. */
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+var { add_message_sets_to_folders, be_in_folder, create_thread } =
+ ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+ );
+
+let tabmail,
+ about3Pane,
+ folderPaneHeader,
+ fetchButton,
+ newButton,
+ moreButton,
+ moreContext,
+ fetchContext,
+ folderModesContextMenu,
+ folderModesContextMenuPopup;
+
+add_setup(async function () {
+ tabmail = document.getElementById("tabmail");
+ about3Pane = tabmail.currentAbout3Pane;
+ folderPaneHeader = about3Pane.document.getElementById("folderPaneHeaderBar");
+ fetchButton = folderPaneHeader.querySelector("#folderPaneGetMessages");
+ fetchContext = about3Pane.document.getElementById(
+ "folderPaneGetMessagesContext"
+ );
+ newButton = folderPaneHeader.querySelector("#folderPaneWriteMessage");
+ moreButton = folderPaneHeader.querySelector("#folderPaneMoreButton");
+ moreContext = about3Pane.document.getElementById("folderPaneMoreContext");
+ folderModesContextMenu = about3Pane.document.getElementById(
+ "folderModesContextMenu"
+ );
+ folderModesContextMenuPopup = about3Pane.document.getElementById(
+ "folderModesContextMenuPopup"
+ );
+ registerCleanupFunction(() => {
+ Services.xulStore.removeDocument(
+ "chrome://messenger/content/messenger.xhtml"
+ );
+ });
+});
+
+async function assertAriaLabel(row, expectedLabel) {
+ await BrowserTestUtils.waitForCondition(
+ () => row.getAttribute("aria-label") === expectedLabel,
+ "The selected row aria-label should match the expected value"
+ );
+}
+
+add_task(function testFolderPaneHeaderDefaultState() {
+ Assert.ok(!folderPaneHeader.hidden, "The folder pane header is visible");
+ Assert.ok(!fetchButton.disabled, "The Get Messages button is enabled");
+ Assert.ok(!newButton.disabled, "The New Message button is enabled");
+});
+
+add_task(async function testHideFolderPaneHeader() {
+ let shownPromise = BrowserTestUtils.waitForEvent(moreContext, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(moreButton, {}, about3Pane);
+ await shownPromise;
+
+ let hiddenPromise = BrowserTestUtils.waitForCondition(
+ () => folderPaneHeader.hidden,
+ "The folder pane header is hidden"
+ );
+ moreContext.activateItem(
+ moreContext.querySelector("#folderPaneHeaderHideMenuItem")
+ );
+ await hiddenPromise;
+
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ "folderPaneHeaderBar",
+ "hidden"
+ ) == "true",
+ "The customization data was saved"
+ );
+
+ // Can't access the menubar in macOS tests, so simply simulate a click on the
+ // toolbarbutton inside the app menu to reveal the header. The app menu
+ // behavior is tested later.
+ if (AppConstants.platform == "macosx") {
+ document.getElementById("appmenu_toggleFolderHeader").click();
+ return;
+ }
+
+ let menubar = document.getElementById("toolbar-menubar");
+ menubar.removeAttribute("autohide");
+ menubar.removeAttribute("inactive");
+ await new Promise(resolve => requestAnimationFrame(resolve));
+
+ let viewShownPromise = BrowserTestUtils.waitForEvent(
+ document.getElementById("menu_View_Popup"),
+ "popupshown"
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ document.getElementById("menu_View"),
+ {},
+ window
+ );
+ await viewShownPromise;
+
+ let viewMenuPopup = document.getElementById("menu_View_Popup");
+ Assert.ok(viewMenuPopup.querySelector("#menu_FolderViews"));
+
+ let folderViewShownPromise = BrowserTestUtils.waitForEvent(
+ document.getElementById("menu_FolderViewsPopup"),
+ "popupshown"
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ viewMenuPopup.querySelector("#menu_FolderViews"),
+ {},
+ window
+ );
+ await folderViewShownPromise;
+
+ let toggleFolderHeader = menubar.querySelector(`[name="paneheader"]`);
+ Assert.ok(
+ !toggleFolderHeader.hasAttribute("checked"),
+ "The toggle header menu item is not checked"
+ );
+
+ EventUtils.synthesizeMouseAtCenter(toggleFolderHeader, {}, window);
+ await BrowserTestUtils.waitForCondition(
+ () => toggleFolderHeader.getAttribute("checked") == "true",
+ "The toggle header menu item is checked"
+ );
+
+ let folderViewHiddenPromise = BrowserTestUtils.waitForEvent(
+ document.getElementById("menu_FolderViewsPopup"),
+ "popuphidden"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await folderViewHiddenPromise;
+
+ let viewHiddenPromise = BrowserTestUtils.waitForEvent(
+ viewMenuPopup,
+ "popuphidden"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await viewHiddenPromise;
+
+ await BrowserTestUtils.waitForCondition(
+ () => !folderPaneHeader.hidden,
+ "The folder pane header is visible"
+ );
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ "folderPaneHeaderBar",
+ "hidden"
+ ) == "false",
+ "The customization data was saved"
+ );
+});
+
+add_task(async function testTogglePaneHeaderFromAppMenu() {
+ Assert.ok(
+ !folderPaneHeader.hidden,
+ "Start with a visible folder pane header"
+ );
+
+ async function toggleFolderPaneHeader(shouldBeChecked) {
+ let appMenu = document.getElementById("appMenu-popup");
+ let menuShownPromise = BrowserTestUtils.waitForEvent(appMenu, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(
+ document.getElementById("button-appmenu"),
+ {},
+ window
+ );
+ await menuShownPromise;
+
+ let viewShownPromise = BrowserTestUtils.waitForEvent(
+ appMenu.querySelector("#appMenu-viewView"),
+ "ViewShown"
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ appMenu.querySelector("#appmenu_View"),
+ {},
+ window
+ );
+ await viewShownPromise;
+
+ let toolbarShownPromise = BrowserTestUtils.waitForEvent(
+ appMenu.querySelector("#appMenu-foldersView"),
+ "ViewShown"
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ appMenu.querySelector("#appmenu_FolderViews"),
+ {},
+ window
+ );
+ await toolbarShownPromise;
+
+ let appMenuButton = document.getElementById("appmenu_toggleFolderHeader");
+ Assert.equal(
+ appMenuButton.checked,
+ shouldBeChecked,
+ `The app menu item should ${shouldBeChecked ? "" : "not "}be checked`
+ );
+
+ EventUtils.synthesizeMouseAtCenter(appMenuButton, {}, window);
+
+ let menuHiddenPromise = BrowserTestUtils.waitForEvent(
+ appMenu,
+ "popuphidden"
+ );
+ // Close the appmenu.
+ EventUtils.synthesizeMouseAtCenter(
+ document.getElementById("button-appmenu"),
+ {},
+ window
+ );
+ await menuHiddenPromise;
+ }
+
+ await toggleFolderPaneHeader(true);
+ await toggleFolderPaneHeader(false);
+});
+
+/**
+ * Test the toggle that shows/hides the buttons on the folder pane header from
+ * the context menu.
+ */
+add_task(async function testTogglePaneHeaderButtons() {
+ Assert.ok(!folderPaneHeader.hidden, "The folder pane header is visible");
+ Assert.ok(!fetchButton.hidden, "The Get Messages button is visible");
+ Assert.ok(!newButton.hidden, "The New Message button is visible");
+
+ let folderPaneHdrToggleBtns = [
+ {
+ menuId: "#folderPaneHeaderToggleGetMessages",
+ buttonId: "#folderPaneGetMessages",
+ label: "Get messages",
+ },
+ {
+ menuId: "#folderPaneHeaderToggleNewMessage",
+ buttonId: "#folderPaneWriteMessage",
+ label: "New message",
+ },
+ ];
+
+ for (let toggle of folderPaneHdrToggleBtns) {
+ let toggleMenuItem = moreContext.querySelector(toggle.menuId);
+ let toggleButton = folderPaneHeader.querySelector(toggle.buttonId);
+ let shouldBeChecked = !toggleButton.hidden;
+
+ // Hide the toggle buttons
+ let shownPromise = BrowserTestUtils.waitForEvent(moreContext, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(moreButton, {}, about3Pane);
+ await shownPromise;
+
+ Assert.equal(
+ toggleMenuItem.hasAttribute("checked"),
+ shouldBeChecked,
+ `The "${toggle.label}" menuitem should ${
+ shouldBeChecked ? "" : "not"
+ } be checked`
+ );
+
+ EventUtils.synthesizeMouseAtCenter(toggleMenuItem, {}, about3Pane);
+
+ await BrowserTestUtils.waitForCondition(
+ () => !toggleMenuItem.hasAttribute("checked"),
+ `The ${toggle.label} menu item is unchecked`
+ );
+
+ await BrowserTestUtils.waitForCondition(
+ () => toggleButton.hidden,
+ `The ${toggle.label} button is hidden`
+ );
+
+ let buttonName =
+ toggle.buttonId == "#folderPaneGetMessages"
+ ? "folderPaneGetMessages"
+ : "folderPaneWriteMessage";
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ buttonName,
+ "hidden"
+ ) == "true",
+ "The customization data was saved"
+ );
+
+ let menuHiddenPromise = BrowserTestUtils.waitForEvent(
+ moreContext,
+ "popuphidden"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await menuHiddenPromise;
+
+ // display the toggle buttons
+ EventUtils.synthesizeMouseAtCenter(moreButton, {}, about3Pane);
+ await shownPromise;
+
+ shouldBeChecked = !toggleButton.hidden;
+
+ Assert.equal(
+ toggleMenuItem.hasAttribute("checked"),
+ shouldBeChecked,
+ `The "${toggle.label}" menuitem should ${
+ shouldBeChecked ? "" : "not"
+ } be checked`
+ );
+ EventUtils.synthesizeMouseAtCenter(toggleMenuItem, {}, about3Pane);
+
+ await BrowserTestUtils.waitForCondition(
+ () => toggleMenuItem.hasAttribute("checked"),
+ `The ${toggle.label} menu item is checked`
+ );
+
+ await BrowserTestUtils.waitForCondition(
+ () => !toggleButton.hidden,
+ `The ${toggle.label} button is not hidden`
+ );
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ buttonName,
+ "hidden"
+ ) == "false",
+ "The customization data was saved"
+ );
+
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await menuHiddenPromise;
+ }
+});
+
+/**
+ * Test the default state of the context menu in the about3Pane.
+ */
+add_task(async function testInitialActiveModes() {
+ let shownPromise = BrowserTestUtils.waitForEvent(moreContext, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(moreButton, {}, about3Pane);
+ await shownPromise;
+
+ let shownFolderModesSubMenuPromise = BrowserTestUtils.waitForEvent(
+ folderModesContextMenuPopup,
+ "popupshown"
+ );
+
+ EventUtils.synthesizeMouseAtCenter(folderModesContextMenu, {}, about3Pane);
+ await shownFolderModesSubMenuPromise;
+
+ Assert.equal(
+ about3Pane.folderPane.activeModes.length,
+ 1,
+ "Only one active mode"
+ );
+ Assert.equal(
+ about3Pane.folderPane.activeModes.at(0),
+ "all",
+ "The first item is 'all' value"
+ );
+ Assert.ok(
+ moreContext
+ .querySelector("#folderPaneMoreContextAllFolders")
+ .getAttribute("checked"),
+ "'All' toggle is checked"
+ );
+ Assert.equal(moreContext.state, "open", "The context menu remains open");
+});
+
+/**
+ * Tests that the menu items are correctly checked corresponding to the current
+ * active modes.
+ */
+add_task(async function testFolderModesActivation() {
+ let folderModesArray = [
+ { menuID: "#folderPaneMoreContextUnifiedFolders", modeID: "smart" },
+ { menuID: "#folderPaneMoreContextUnreadFolders", modeID: "unread" },
+ { menuID: "#folderPaneMoreContextFavoriteFolders", modeID: "favorite" },
+ { menuID: "#folderPaneMoreContextRecentFolders", modeID: "recent" },
+ ];
+ let checkedModesCount = 2;
+ for (let mode of folderModesArray) {
+ Assert.ok(
+ !moreContext.querySelector(mode.menuID).hasAttribute("checked"),
+ `"${mode.modeID}" option is not checked`
+ );
+
+ let checkedPromise = TestUtils.waitForCondition(
+ () => moreContext.querySelector(mode.menuID).hasAttribute("checked"),
+ `"${mode.modeID}" option has been checked`
+ );
+ moreContext.activateItem(moreContext.querySelector(mode.menuID));
+ await checkedPromise;
+
+ Assert.equal(
+ about3Pane.folderPane.activeModes.length,
+ checkedModesCount,
+ `Correct amount of active modes after enabling the "${mode.modeID}" mode`
+ );
+ Assert.ok(
+ about3Pane.folderPane.activeModes.includes(mode.modeID),
+ `"${mode.modeID}" mode is included in the active modes array`
+ );
+ checkedModesCount++;
+ }
+ Assert.equal(moreContext.state, "open", "The context menu remains open");
+});
+
+/**
+ * Tests that the menu items are correctly unchecked corresponding to the
+ * current active modes. It verifies that the if every item is unchecked, it
+ * returns to the default active mode value and the corresponding menu item is
+ * checked.
+ */
+add_task(async function testFolderModesDeactivation() {
+ let folderActiveModesArray = [
+ { menuID: "#folderPaneMoreContextAllFolders", modeID: "all" },
+ { menuID: "#folderPaneMoreContextUnifiedFolders", modeID: "smart" },
+ { menuID: "#folderPaneMoreContextUnreadFolders", modeID: "unread" },
+ { menuID: "#folderPaneMoreContextFavoriteFolders", modeID: "favorite" },
+ { menuID: "#folderPaneMoreContextRecentFolders", modeID: "recent" },
+ ];
+ let checkedModesCount = 4;
+ for (let mode of folderActiveModesArray) {
+ Assert.ok(
+ moreContext.querySelector(mode.menuID).hasAttribute("checked"),
+ `"${mode.modeID}" option is checked`
+ );
+
+ let uncheckedPromise = TestUtils.waitForCondition(
+ () => !moreContext.querySelector(mode.menuID).hasAttribute("checked"),
+ `"${mode.modeID}" option has been unchecked`
+ );
+ moreContext.activateItem(moreContext.querySelector(mode.menuID));
+ await uncheckedPromise;
+
+ Assert.ok(
+ !about3Pane.folderPane.activeModes.includes(mode.modeID),
+ `"${mode.modeID}" mode is not included in the active modes array`
+ );
+ if (checkedModesCount > 0) {
+ Assert.equal(
+ about3Pane.folderPane.activeModes.length,
+ checkedModesCount,
+ `Correct amount of active modes after disabling the "${mode.modeID}" mode`
+ );
+ } else {
+ //checks if it automatically checks "all" mode if every other mode was unchecked
+ Assert.equal(
+ about3Pane.folderPane.activeModes.length,
+ 1,
+ `Correct amount of active modes after disabling the "${mode.modeID}" mode`
+ );
+ Assert.equal(
+ about3Pane.folderPane.activeModes.at(0),
+ "all",
+ "The first item is 'all' value"
+ );
+ Assert.ok(
+ moreContext
+ .querySelector("#folderPaneMoreContextAllFolders")
+ .getAttribute("checked"),
+ "'All' toggle is checked"
+ );
+ }
+ checkedModesCount--;
+ }
+ Assert.equal(moreContext.state, "open", "The context menu remains open");
+ let menuHiddenPromise = BrowserTestUtils.waitForEvent(
+ folderModesContextMenuPopup,
+ "popuphidden"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await menuHiddenPromise;
+
+ menuHiddenPromise = BrowserTestUtils.waitForEvent(moreContext, "popuphidden");
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await menuHiddenPromise;
+});
+
+add_task(async function testGetMessageContextMenu() {
+ const shownPromise = BrowserTestUtils.waitForEvent(
+ fetchContext,
+ "popupshown"
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ fetchButton,
+ { type: "contextmenu" },
+ about3Pane
+ );
+ await shownPromise;
+
+ Assert.equal(
+ fetchContext.querySelectorAll("menuitem").length,
+ 2,
+ "2 menuitems should be present in the fetch context"
+ );
+
+ const menuHiddenPromise = BrowserTestUtils.waitForEvent(
+ fetchContext,
+ "popuphidden"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await menuHiddenPromise;
+});
+
+add_task(async function testTotalCountDefaultState() {
+ let totalCountBadge = about3Pane.document.querySelector(".total-count");
+ Assert.ok(
+ !moreContext
+ .querySelector("#folderPaneHeaderToggleTotalCount")
+ .hasAttribute("checked"),
+ "The total count toggle is unchecked"
+ );
+ Assert.ok(totalCountBadge.hidden, "The total count badges are hidden");
+ Assert.notEqual(
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ "totalMsgCount",
+ "visible"
+ ),
+ "true",
+ "The customization data was saved"
+ );
+
+ const rootFolder =
+ MailServices.accounts.accounts[0].incomingServer.rootFolder;
+ const inbox = rootFolder.getFolderWithFlags(Ci.nsMsgFolderFlags.Inbox);
+ await add_message_sets_to_folders([inbox], [create_thread(10)]);
+ await be_in_folder(inbox);
+
+ about3Pane.folderTree.selectedIndex = 1;
+ let row = about3Pane.folderTree.getRowAtIndex(1);
+ await assertAriaLabel(row, "Inbox, 10 unread messages");
+
+ about3Pane.threadTree.selectedIndex = 0;
+ about3Pane.threadTree.expandRowAtIndex(0);
+ await assertAriaLabel(row, "Inbox, 9 unread messages");
+});
+
+add_task(async function testTotalCountVisible() {
+ let totalCountBadge = about3Pane.document.querySelector(".total-count");
+ let shownPromise = BrowserTestUtils.waitForEvent(moreContext, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(moreButton, {}, about3Pane);
+ await shownPromise;
+
+ // Toggle total count ON.
+ let toggleOnPromise = BrowserTestUtils.waitForCondition(
+ () => !totalCountBadge.hidden,
+ "The total count badges are visible"
+ );
+ moreContext.activateItem(
+ moreContext.querySelector("#folderPaneHeaderToggleTotalCount")
+ );
+ await toggleOnPromise;
+ // Check that toggle was successful.
+ Assert.ok(
+ moreContext
+ .querySelector("#folderPaneHeaderToggleTotalCount")
+ .hasAttribute("checked"),
+ "The total count toggle is checked"
+ );
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ "totalMsgCount",
+ "visible"
+ ) == "true",
+ "The customization data was saved"
+ );
+
+ let menuHiddenPromise = BrowserTestUtils.waitForEvent(
+ moreContext,
+ "popuphidden"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await menuHiddenPromise;
+
+ let row = about3Pane.folderTree.getRowAtIndex(1);
+ await assertAriaLabel(row, "Inbox, 9 unread messages, 10 total messages");
+});
+
+add_task(async function testFolderSizeDefaultState() {
+ let folderSizeBadge = about3Pane.document.querySelector(".folder-size");
+ Assert.ok(
+ !moreContext
+ .querySelector("#folderPaneHeaderToggleFolderSize")
+ .hasAttribute("checked"),
+ "The folder size toggle is unchecked"
+ );
+ Assert.ok(folderSizeBadge.hidden, "The folder sizes are hidden");
+ Assert.notEqual(
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ "folderPaneFolderSize",
+ "visible"
+ ),
+ "true",
+ "The folder size xulStore attribute is set to not visible"
+ );
+});
+
+add_task(async function testFolderSizeVisible() {
+ let folderSizeBadge = about3Pane.document.querySelector(".folder-size");
+ let shownPromise = BrowserTestUtils.waitForEvent(moreContext, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(moreButton, {}, about3Pane);
+ await shownPromise;
+
+ // Toggle folder size ON.
+ let toggleOnPromise = BrowserTestUtils.waitForCondition(
+ () => !folderSizeBadge.hidden,
+ "The folder sizes are visible"
+ );
+ moreContext.activateItem(
+ moreContext.querySelector("#folderPaneHeaderToggleFolderSize")
+ );
+ await toggleOnPromise;
+ // Check that toggle on was successful.
+ Assert.ok(
+ moreContext
+ .querySelector("#folderPaneHeaderToggleFolderSize")
+ .hasAttribute("checked"),
+ "The folder size toggle is checked"
+ );
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ "folderPaneFolderSize",
+ "visible"
+ ) == "true",
+ "The folder size xulStore attribute is set to visible"
+ );
+
+ Assert.ok(!folderSizeBadge.hidden, "The folder sizes are visible");
+
+ let menuHiddenPromise = BrowserTestUtils.waitForEvent(
+ moreContext,
+ "popuphidden"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await menuHiddenPromise;
+
+ let row = about3Pane.folderTree.getRowAtIndex(1);
+ await assertAriaLabel(
+ row,
+ `Inbox, 9 unread messages, 10 total messages, ${row.folderSize}`
+ );
+});
+
+add_task(async function testFolderSizeHidden() {
+ let folderSizeBadge = about3Pane.document.querySelector(".folder-size");
+ let shownPromise = BrowserTestUtils.waitForEvent(moreContext, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(moreButton, {}, about3Pane);
+ await shownPromise;
+
+ // Toggle folder sizes OFF.
+ let toggleOffPromise = BrowserTestUtils.waitForCondition(
+ () => folderSizeBadge.hidden,
+ "The folder sizes are hidden"
+ );
+ moreContext.activateItem(
+ moreContext.querySelector("#folderPaneHeaderToggleFolderSize")
+ );
+ await toggleOffPromise;
+
+ // Check that toggle was successful.
+ Assert.ok(
+ !moreContext
+ .querySelector("#folderPaneHeaderToggleFolderSize")
+ .getAttribute("checked"),
+ "The folder size toggle is unchecked"
+ );
+
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ "folderPaneFolderSize",
+ "visible"
+ ) == "false",
+ "The folder size xulStore visible attribute was set to false"
+ );
+
+ Assert.ok(folderSizeBadge.hidden, "The folder sizes are hidden");
+
+ let menuHiddenPromise = BrowserTestUtils.waitForEvent(
+ moreContext,
+ "popuphidden"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await menuHiddenPromise;
+});
+
+add_task(async function testTotalCountHidden() {
+ let totalCountBadge = about3Pane.document.querySelector(".total-count");
+ let shownPromise = BrowserTestUtils.waitForEvent(moreContext, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(moreButton, {}, about3Pane);
+ await shownPromise;
+
+ // Toggle total count OFF.
+ let toggleOffPromise = BrowserTestUtils.waitForCondition(
+ () => totalCountBadge.hidden,
+ "The total count badges are hidden"
+ );
+ moreContext.activateItem(
+ moreContext.querySelector("#folderPaneHeaderToggleTotalCount")
+ );
+ await toggleOffPromise;
+
+ // Check that toggle was successful.
+ Assert.ok(
+ !moreContext
+ .querySelector("#folderPaneHeaderToggleTotalCount")
+ .getAttribute("checked"),
+ "The total count toggle is unchecked"
+ );
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ "totalMsgCount",
+ "visible"
+ ) == "false",
+ "The customization data was saved"
+ );
+
+ let menuHiddenPromise = BrowserTestUtils.waitForEvent(
+ moreContext,
+ "popuphidden"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await menuHiddenPromise;
+
+ let row = about3Pane.folderTree.getRowAtIndex(1);
+ await assertAriaLabel(row, "Inbox, 9 unread messages");
+});
+
+add_task(async function testHideLocalFoldersXULStore() {
+ let shownPromise = BrowserTestUtils.waitForEvent(moreContext, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(moreButton, {}, about3Pane);
+ await shownPromise;
+
+ moreContext.activateItem(
+ moreContext.querySelector("#folderPaneHeaderToggleLocalFolders")
+ );
+
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ "folderPaneLocalFolders",
+ "hidden"
+ ) == "true",
+ "The customization data to hide local folders should be saved"
+ );
+
+ let menuHiddenPromise = BrowserTestUtils.waitForEvent(
+ moreContext,
+ "popuphidden"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await menuHiddenPromise;
+
+ shownPromise = BrowserTestUtils.waitForEvent(moreContext, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(moreButton, {}, about3Pane);
+ await shownPromise;
+
+ Assert.ok(
+ moreContext
+ .querySelector("#folderPaneHeaderToggleLocalFolders")
+ .hasAttribute("checked"),
+ "The hide local folders menuitem should be checked"
+ );
+
+ moreContext.activateItem(
+ moreContext.querySelector("#folderPaneHeaderToggleLocalFolders")
+ );
+
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ "folderPaneLocalFolders",
+ "hidden"
+ ) == "false",
+ "The customization data to hide local folders should be saved"
+ );
+});
+
+/**
+ * Ensure that the various badges and labels are updated and maintained when
+ * folders and modes change in the folder pane.
+ */
+add_task(async function testBadgesPersistentState() {
+ let totalCountBadge = about3Pane.document.querySelector(".total-count");
+ let folderSizeBadge = about3Pane.document.querySelector(".folder-size");
+ // Show total count.
+ let toggleOnPromise = BrowserTestUtils.waitForCondition(
+ () => !totalCountBadge.hidden,
+ "The total count badges are visible"
+ );
+ moreContext.activateItem(
+ moreContext.querySelector("#folderPaneHeaderToggleTotalCount")
+ );
+ await toggleOnPromise;
+
+ // Show folder size.
+ toggleOnPromise = BrowserTestUtils.waitForCondition(
+ () => !folderSizeBadge.hidden,
+ "The folder sizes are visible"
+ );
+ moreContext.activateItem(
+ moreContext.querySelector("#folderPaneHeaderToggleFolderSize")
+ );
+ await toggleOnPromise;
+
+ // Hide local folders.
+ moreContext.activateItem(
+ moreContext.querySelector("#folderPaneHeaderToggleLocalFolders")
+ );
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ Services.xulStore.getValue(
+ "chrome://messenger/content/messenger.xhtml",
+ "folderPaneLocalFolders",
+ "hidden"
+ ) == "true",
+ "The customization data to hide local folders should be saved"
+ );
+ // The test times out on macOS if we don't wait here before dismissing the
+ // context menu. Unknown why.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, 250));
+
+ let menuHiddenPromise = BrowserTestUtils.waitForEvent(
+ moreContext,
+ "popuphidden"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, about3Pane);
+ await menuHiddenPromise;
+
+ // Ensure the badges are still visible.
+ Assert.ok(
+ !totalCountBadge.hidden,
+ "Folder total count badge should be visible"
+ );
+ Assert.ok(!folderSizeBadge.hidden, "Folder size badge should be visible");
+
+ // Create a folder and add messages to that folder to ensure the badges are
+ // visible and they update properly.
+ const rootFolder =
+ MailServices.accounts.accounts[0].incomingServer.rootFolder;
+ rootFolder.createSubfolder("NewlyCreatedTestFolder", null);
+ const folder = rootFolder.getChildNamed("NewlyCreatedTestFolder");
+ await be_in_folder(folder);
+
+ about3Pane.folderTree.selectedIndex = 3;
+ const row = about3Pane.folderTree.getRowAtIndex(3);
+ Assert.equal(
+ row.name,
+ "NewlyCreatedTestFolder",
+ "The correct folder should have been selected"
+ );
+ // Badges shouldn't be hidden even if there's no content.
+ Assert.ok(
+ !row.querySelector(".total-count").hidden,
+ "The total count badge of the newly created folder should be visible"
+ );
+ Assert.ok(
+ !row.querySelector(".folder-size").hidden,
+ "The folder size badge of the newly created folder should be visible"
+ );
+
+ const currentTotal = row.querySelector(".total-count").textContent;
+ const currentSize = row.querySelector(".folder-size").textContent;
+
+ await add_message_sets_to_folders([folder], [create_thread(10)]);
+
+ // Weird issue with the test in which the focus is lost after creating the
+ // messages, and the folder pane doesn't receive the folder size property
+ // changes. This doesn't happen while using the app normally.
+ about3Pane.folderTree.selectedIndex = 0;
+ about3Pane.folderTree.selectedIndex = 3;
+
+ await BrowserTestUtils.waitForCondition(
+ () => currentTotal != row.querySelector(".total-count").textContent,
+ `${currentTotal} != ${
+ row.querySelector(".total-count").textContent
+ } | The total count should have changed after adding messages`
+ );
+
+ await BrowserTestUtils.waitForCondition(
+ () => currentSize != row.querySelector(".folder-size").textContent,
+ `${currentSize} != ${
+ row.querySelector(".folder-size").textContent
+ } | The folder size should have changed after adding messages`
+ );
+});
+
+add_task(async function testActionButtonsState() {
+ // Delete all accounts to start clean.
+ for (let account of MailServices.accounts.accounts) {
+ MailServices.accounts.removeAccount(account, true);
+ }
+
+ // Confirm that we don't have any account in our test run.
+ Assert.equal(
+ MailServices.accounts.accounts.length,
+ 0,
+ "No account currently configured"
+ );
+
+ Assert.ok(fetchButton.disabled, "The Get Messages button is disabled");
+ Assert.ok(newButton.disabled, "The New Message button is disabled");
+
+ // Create a POP server.
+ let popServer = MailServices.accounts
+ .createIncomingServer("nobody", "foo.invalid", "pop3")
+ .QueryInterface(Ci.nsIPop3IncomingServer);
+
+ let identity = MailServices.accounts.createIdentity();
+ identity.email = "tinderbox@foo.invalid";
+
+ let account = MailServices.accounts.createAccount();
+ account.addIdentity(identity);
+ account.incomingServer = popServer;
+
+ await BrowserTestUtils.waitForCondition(
+ () => !fetchButton.disabled,
+ "The Get Messages button is enabled"
+ );
+
+ await BrowserTestUtils.waitForCondition(
+ () => !newButton.disabled,
+ "The New Message button is enabled"
+ );
+});
diff --git a/comm/mail/test/browser/folder-pane/browser_folderPaneModeContextMenu.js b/comm/mail/test/browser/folder-pane/browser_folderPaneModeContextMenu.js
new file mode 100644
index 0000000000..1e571efa40
--- /dev/null
+++ b/comm/mail/test/browser/folder-pane/browser_folderPaneModeContextMenu.js
@@ -0,0 +1,208 @@
+/* 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/. */
+
+let tabmail,
+ about3Pane,
+ folderPane,
+ folderPaneModeContextMenu,
+ folderPaneModeNames,
+ folderPaneModeMoveUpMenuItem,
+ folderPaneModeMoveDownMenuItem;
+
+add_setup(async function () {
+ tabmail = document.getElementById("tabmail");
+ about3Pane = tabmail.currentAbout3Pane;
+ folderPane = about3Pane.folderPane;
+ folderPaneModeContextMenu = about3Pane.document.getElementById(
+ "folderPaneModeContext"
+ );
+ folderPaneModeNames = about3Pane.document.getElementsByClassName("mode-name");
+ folderPaneModeMoveUpMenuItem = about3Pane.document.getElementById(
+ "folderPaneModeMoveUp"
+ );
+ folderPaneModeMoveDownMenuItem = about3Pane.document.getElementById(
+ "folderPaneModeMoveDown"
+ );
+
+ folderPane.activeModes = ["all", "smart", "unread", "favorite", "recent"];
+
+ registerCleanupFunction(() => {
+ Services.xulStore.removeDocument(
+ "chrome://messenger/content/messenger.xhtml"
+ );
+ });
+});
+
+/**
+ * Tests that ability to swap a folder mode for the one above it, and
+ * ensures that if it's the last element, the option to swap is disabled.
+ */
+add_task(async function testMoveFolderModeUp() {
+ // Find the "Recent" folder pane mode text element as that is the
+ // last folder pane mode.
+ const recentFolderModeName = Array.prototype.find.call(
+ folderPaneModeNames,
+ element => element.parentElement.parentElement.dataset.mode === "recent"
+ );
+
+ // Grab the options element which is next to the text element to open
+ // the context menu.
+ const recentFolderModeOptions = recentFolderModeName.nextElementSibling;
+
+ // Make sure the context menu is visible before continuing/
+ const shownPromise = BrowserTestUtils.waitForEvent(
+ folderPaneModeContextMenu,
+ "popupshown"
+ );
+
+ EventUtils.synthesizeMouseAtCenter(recentFolderModeOptions, {}, about3Pane);
+
+ await shownPromise;
+
+ // Assert initial folder mode positions
+ Assert.equal(
+ folderPane.activeModes.at(-1),
+ "recent",
+ "Recent Folders mode is in the incorrect position."
+ );
+ Assert.equal(
+ folderPane.activeModes.at(-2),
+ "favorite",
+ "Favourite mode is in the incorrect position."
+ );
+
+ // Ensure that the move down element is disabled asit is the last element.
+
+ Assert.equal(
+ folderPaneModeMoveDownMenuItem.getAttribute("disabled"),
+ "true",
+ "Move down element is enabled."
+ );
+
+ const hiddenPromise = BrowserTestUtils.waitForEvent(
+ folderPaneModeContextMenu,
+ "popuphidden"
+ );
+
+ folderPaneModeContextMenu.activateItem(folderPaneModeMoveUpMenuItem);
+
+ await hiddenPromise;
+
+ // Folder mode that was moved up should be swapped with the folder mode
+ // above it in the activeModes array.
+ Assert.equal(
+ folderPane.activeModes.at(-1),
+ "favorite",
+ "Folder pane mode was not moved up."
+ );
+ Assert.equal(
+ folderPane.activeModes.at(-2),
+ "recent",
+ "Folder pane mode was not moved down."
+ );
+});
+
+/**
+ * Tests that ability to swap a folder mode for the one below it.
+ */
+add_task(async function testMoveFolderModeDown() {
+ // Find the "Recent" folder pane mode text element as that is the
+ // second last folder pane mode.
+ const recentFolderModeName = Array.prototype.find.call(
+ folderPaneModeNames,
+ element => element.parentElement.parentElement.dataset.mode === "recent"
+ );
+
+ // Grab the options element which is next to the text element to open
+ // the context menu.
+ const recentFolderModeOptions = recentFolderModeName.nextElementSibling;
+
+ // Make sure the context menu is visible before continuing/
+ const shownPromise = BrowserTestUtils.waitForEvent(
+ folderPaneModeContextMenu,
+ "popupshown"
+ );
+
+ EventUtils.synthesizeMouseAtCenter(recentFolderModeOptions, {}, about3Pane);
+
+ await shownPromise;
+
+ // Assert initial folder mode positions
+ Assert.equal(
+ folderPane.activeModes.at(-1),
+ "favorite",
+ "Favourite folder mode is in the incorrect position."
+ );
+ Assert.equal(
+ folderPane.activeModes.at(-2),
+ "recent",
+ "Recent Folders mode is in the incorrect position."
+ );
+
+ const hiddenPromise = BrowserTestUtils.waitForEvent(
+ folderPaneModeContextMenu,
+ "popuphidden"
+ );
+
+ folderPaneModeContextMenu.activateItem(folderPaneModeMoveDownMenuItem);
+
+ await hiddenPromise;
+
+ // Folder mode that was moved down should be swapped with the folder mode
+ // below it in the activeModes array.
+ Assert.equal(
+ folderPane.activeModes.at(-1),
+ "recent",
+ "Folder pane mode was not moved up."
+ );
+ Assert.equal(
+ folderPane.activeModes.at(-2),
+ "favorite",
+ "Folder pane mode was not moved down."
+ );
+});
+
+/**
+ * Tests that the Move Up menu item on a folder pane mode is disabled when
+ * it is the topmost folder pane mode
+ */
+
+add_task(async function testCantMoveFolderPaneModeUp() {
+ // Find the "All" folder pane mode text element as that is the
+ // first folder pane mode.
+ const allFolderModeName = Array.prototype.find.call(
+ folderPaneModeNames,
+ element => element.parentElement.parentElement.dataset.mode === "all"
+ );
+
+ // Grab the options element which is next to the text element to open
+ // the context menu.
+ const allFolderModeOptions = allFolderModeName.nextElementSibling;
+
+ // Make sure the context menu is visible before continuing/
+ const shownPromise = BrowserTestUtils.waitForEvent(
+ folderPaneModeContextMenu,
+ "popupshown"
+ );
+
+ EventUtils.synthesizeMouseAtCenter(allFolderModeOptions, {}, about3Pane);
+
+ await shownPromise;
+
+ Assert.equal(
+ folderPaneModeMoveUpMenuItem.getAttribute("disabled"),
+ "true",
+ "Move down element is enabled."
+ );
+
+ // Make sure the context menu is hidden before continuing
+ const hiddenPromise = BrowserTestUtils.waitForEvent(
+ folderPaneModeContextMenu,
+ "popuphidden"
+ );
+
+ folderPaneModeContextMenu.hidePopup();
+
+ await hiddenPromise;
+});