summaryrefslogtreecommitdiffstats
path: root/comm/mail/test/browser/folder-tree-modes
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/test/browser/folder-tree-modes')
-rw-r--r--comm/mail/test/browser/folder-tree-modes/browser.ini51
-rw-r--r--comm/mail/test/browser/folder-tree-modes/browser_customFolderTreeMode.js142
-rw-r--r--comm/mail/test/browser/folder-tree-modes/browser_customSmartFolder.js211
-rw-r--r--comm/mail/test/browser/folder-tree-modes/browser_modeSwitching.js338
-rw-r--r--comm/mail/test/browser/folder-tree-modes/browser_smartFolders.js179
-rw-r--r--comm/mail/test/browser/folder-tree-modes/browser_unreadFolders.js91
6 files changed, 1012 insertions, 0 deletions
diff --git a/comm/mail/test/browser/folder-tree-modes/browser.ini b/comm/mail/test/browser/folder-tree-modes/browser.ini
new file mode 100644
index 0000000000..9ca3fc18e1
--- /dev/null
+++ b/comm/mail/test/browser/folder-tree-modes/browser.ini
@@ -0,0 +1,51 @@
+[DEFAULT]
+prefs =
+ mail.account.account1.server=server1
+ mail.account.account2.identities=id1,id2
+ mail.account.account2.server=server2
+ mail.accountmanager.accounts=account1,account2
+ mail.accountmanager.defaultaccount=account2
+ mail.accountmanager.localfoldersserver=server1
+ 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.server1.type=none
+ mail.server.server1.userName=nobody
+ 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
+support-files = test-extension/**
+
+[browser_customFolderTreeMode.js]
+skip-if = true # No longer supported.
+[browser_customSmartFolder.js]
+skip-if = true # No longer supported.
+[browser_modeSwitching.js]
+[browser_smartFolders.js]
+[browser_unreadFolders.js]
diff --git a/comm/mail/test/browser/folder-tree-modes/browser_customFolderTreeMode.js b/comm/mail/test/browser/folder-tree-modes/browser_customFolderTreeMode.js
new file mode 100644
index 0000000000..49189c9254
--- /dev/null
+++ b/comm/mail/test/browser/folder-tree-modes/browser_customFolderTreeMode.js
@@ -0,0 +1,142 @@
+/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 custom folder tree modes. The test mode is provided by the test
+ * extension in the test-extension subdirectory.
+ */
+
+"use strict";
+
+var {
+ assert_folder_mode,
+ assert_folder_visible,
+ FAKE_SERVER_HOSTNAME,
+ get_special_folder,
+ mc,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+var { close_window, plan_for_new_window, wait_for_new_window } =
+ ChromeUtils.import("resource://testing-common/mozmill/WindowHelpers.jsm");
+
+var { ExtensionSupport } = ChromeUtils.import(
+ "resource:///modules/ExtensionSupport.jsm"
+);
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+var { MailUtils } = ChromeUtils.import("resource:///modules/MailUtils.jsm");
+
+var gInbox;
+
+add_setup(async function () {
+ let server = MailServices.accounts.findServer(
+ "tinderbox",
+ FAKE_SERVER_HOSTNAME,
+ "pop3"
+ );
+ gInbox = await get_special_folder(Ci.nsMsgFolderFlags.Inbox, false, server);
+
+ ExtensionSupport.registerWindowListener("mochitest", {
+ chromeURLs: ["chrome://messenger/content/messenger.xhtml"],
+ onLoadWindow(aWindow) {
+ let testFolderTreeMode = {
+ __proto__: aWindow.IFolderTreeMode,
+ generateMap(aFTV) {
+ var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+ );
+ // Pick the tinderbox@foo.invalid inbox and use it as the only folder
+ let server = MailServices.accounts.findServer(
+ "tinderbox",
+ "tinderbox123",
+ "pop3"
+ );
+ let item = [];
+ let inbox = new aWindow.FtvItem(
+ server.rootFolder.getChildNamed("Inbox")
+ );
+ inbox.__defineGetter__("children", () => []);
+ item.push(inbox);
+
+ if (aWindow.gFolderTreeView.activeModes.length > 1) {
+ item.unshift(new aWindow.FtvItemHeader("Test%20Mode", "testmode"));
+ }
+
+ return item;
+ },
+ };
+
+ aWindow.gFolderTreeView.registerFolderTreeMode(
+ "testmode",
+ testFolderTreeMode,
+ "Test Mode"
+ );
+ },
+ });
+});
+
+// Provided by the extension in test-extension.
+var kTestModeID = "testmode";
+
+/**
+ * Switch to the mode and verify that it displays correctly.
+ */
+add_task(function test_switch_to_test_mode() {
+ mc.folderTreeView.activeModes = kTestModeID;
+ // Hide the all folder view mode.
+ mc.folderTreeView.activeModes = "all";
+
+ assert_folder_mode(kTestModeID);
+ assert_folder_visible(gInbox);
+});
+
+/**
+ * Open a new 3-pane window while the custom mode is selected, and make sure
+ * that the mode displayed in the new window is the custom mode.
+ */
+add_task(async function test_open_new_window_with_custom_mode() {
+ // Our selection may get lost while changing modes, and be_in_folder is
+ // not sufficient to ensure actual selection.
+ mc.folderTreeView.selectFolder(gInbox);
+
+ plan_for_new_window("mail:3pane");
+ mc.window.MsgOpenNewWindowForFolder(null, -1);
+ let mc2 = wait_for_new_window("mail:3pane");
+
+ await TestUtils.waitForCondition(() => mc2.folderTreeView.isInited);
+ assert_folder_mode(kTestModeID, mc2);
+ assert_folder_visible(gInbox, mc2);
+
+ close_window(mc2);
+});
+
+/**
+ * Switch back to all folders.
+ */
+add_task(function test_switch_to_all_folders() {
+ // Hide the test mode 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 = kTestModeID;
+ assert_folder_mode("all");
+});
+
+registerCleanupFunction(() => {
+ mc.window.gFolderTreeView.unregisterFolderTreeMode(kTestModeID);
+ ExtensionSupport.unregisterWindowListener("mochitest");
+ Assert.report(
+ false,
+ undefined,
+ undefined,
+ "Test ran to completion successfully"
+ );
+
+ // Some tests that open new windows don't return focus to the main window
+ // in a way that satisfies mochitest, and the test times out.
+ Services.focus.focusedWindow = window;
+ window.gFolderDisplay.tree.focus();
+});
diff --git a/comm/mail/test/browser/folder-tree-modes/browser_customSmartFolder.js b/comm/mail/test/browser/folder-tree-modes/browser_customSmartFolder.js
new file mode 100644
index 0000000000..0f0e663445
--- /dev/null
+++ b/comm/mail/test/browser/folder-tree-modes/browser_customSmartFolder.js
@@ -0,0 +1,211 @@
+/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 custom folder tree modes. The test mode is provided by the test
+ * extension in the test-extension subdirectory.
+ */
+
+"use strict";
+
+var {
+ assert_folder_collapsed,
+ assert_folder_displayed,
+ assert_folder_expanded,
+ assert_folder_mode,
+ assert_folder_not_visible,
+ assert_folder_selected_and_displayed,
+ assert_folder_visible,
+ collapse_folder,
+ expand_folder,
+ get_smart_folder_named,
+ inboxFolder,
+ make_message_sets_in_folders,
+ mc,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+
+// spaces in the name are intentional
+var smartParentNameA = "My Smart Folder A";
+var smartParentNameB = "My Smart Folder B";
+
+var rootFolder;
+var inboxSubfolder, subfolderA, subfolderB;
+var smartFolderInbox;
+var smartFolderA;
+
+var nsMsgFolderFlags = Ci.nsMsgFolderFlags;
+
+/**
+ * create two smart folder types and two real folders, one for each
+ * smart folder type
+ */
+add_setup(async function () {
+ rootFolder = inboxFolder.server.rootFolder;
+
+ // register a new smart folder type
+ mc.folderTreeView
+ .getFolderTreeMode("smart")
+ .addSmartFolderType(smartParentNameA, false, false);
+ mc.folderTreeView
+ .getFolderTreeMode("smart")
+ .addSmartFolderType(smartParentNameB, false, false);
+
+ // Create a folder as a subfolder of the inbox
+ inboxFolder.createSubfolder("smartFolderA", null);
+ subfolderA = inboxFolder.getChildNamed("smartFolderA");
+ inboxFolder.createSubfolder("smartFolderB", null);
+ subfolderB = inboxFolder.getChildNamed("smartFolderB");
+
+ // This is how folders are marked to match a custom smart folder
+ // The name is added to a cache, as msgDatabase access in nsITreeView is
+ // bad perf.
+ mc.window.setSmartFolderName(subfolderA, smartParentNameA);
+ mc.window.setSmartFolderName(subfolderB, smartParentNameB);
+
+ // The message itself doesn't really matter, as long as there's at least one
+ // in the folder.
+ await make_message_sets_in_folders([subfolderA], [{ count: 1 }]);
+ await make_message_sets_in_folders([subfolderB], [{ count: 1 }]);
+});
+
+/**
+ * Switch to the smart folder mode, get the smart inbox.
+ */
+add_task(function test_switch_to_smart_folder_mode() {
+ mc.folderTreeView.activeModes = "smart";
+ // Hide the all folders view.
+ mc.folderTreeView.activeModes = "all";
+ assert_folder_mode("smart");
+
+ smartFolderA = get_smart_folder_named(smartParentNameA);
+ SimpleTest.expectUncaughtException();
+ mc.folderTreeView.selectFolder(smartFolderA);
+});
+
+add_task(function test_cache_property() {
+ if (mc.window.getSmartFolderName(subfolderA) != smartParentNameA) {
+ throw new Error("smartFolderName A cache property not set");
+ }
+ if (mc.window.getSmartFolderName(subfolderB) != smartParentNameB) {
+ throw new Error("smartFolderName B cache property not set");
+ }
+});
+
+function _test_smart_folder_type(folder, parentName) {
+ let smartMode = mc.folderTreeView.getFolderTreeMode("smart");
+ let [flag, name] = smartMode._getSmartFolderType(folder);
+ if (flag != 0) {
+ throw new Error(
+ "custom smart folder definition [" + parentName + "] has a flag"
+ );
+ }
+ if (name != parentName) {
+ throw new Error(
+ "custom smart folder [" +
+ folder.name +
+ "] is incorrect [" +
+ name +
+ "] should be [" +
+ parentName +
+ "]"
+ );
+ }
+}
+
+add_task(function test_smart_folder_type() {
+ _test_smart_folder_type(subfolderA, smartParentNameA);
+ _test_smart_folder_type(subfolderB, smartParentNameB);
+});
+
+/**
+ * Test that our custom smart folders exist
+ */
+
+add_task(function test_custom_folder_exists() {
+ assert_folder_mode("smart");
+ assert_folder_displayed(smartFolderA);
+ // this is our custom smart folder parent created in folderPane.js
+ mc.folderTreeView.selectFolder(subfolderA);
+ assert_folder_selected_and_displayed(subfolderA);
+});
+
+function FTVItemHasChild(parentFTVItem, childFolder, recurse) {
+ for (let child of parentFTVItem.children) {
+ if (
+ child._folder.URI == childFolder.URI ||
+ (recurse && FTVItemHasChild(child, childFolder, recurse))
+ ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * test that our real smart folder is in fact a child if the correct
+ * smart folder parent
+ */
+add_task(function test_smart_child_parent_relationship() {
+ let folderIndex = assert_folder_visible(smartFolderA);
+ let folderFTVItem = mc.folderTreeView.getFTVItemForIndex(folderIndex);
+ if (!FTVItemHasChild(folderFTVItem, subfolderA, false)) {
+ throw new Error(
+ "Folder: " +
+ subfolderA.name +
+ " is not a child of our smart parent folder"
+ );
+ }
+ assert_folder_mode("smart");
+});
+
+/**
+ * test that our real smart folder is NOT a child of the smart inbox in the
+ * tree view.
+ */
+add_task(function test_real_child_parent_relationship() {
+ smartFolderInbox = get_smart_folder_named("Inbox");
+ expand_folder(smartFolderInbox);
+ // the real parent should be an Inbox
+ let folderIndex = assert_folder_visible(subfolderA.parent);
+ let folderFTVItem = mc.folderTreeView.getFTVItemForIndex(folderIndex);
+ // in the tree, subfolder is a child of our magic smart folder, and should not
+ // be a child of inbox
+ if (FTVItemHasChild(folderFTVItem, subfolderA, true)) {
+ throw new Error(
+ "Folder: " + subfolderA.name + " should not be a child of an inbox"
+ );
+ }
+ assert_folder_mode("smart");
+});
+
+/**
+ * test collapse/expand states of one of our smart folders
+ */
+add_task(function test_smart_subfolder() {
+ assert_folder_mode("smart");
+ collapse_folder(smartFolderA);
+ assert_folder_collapsed(smartFolderA);
+ assert_folder_not_visible(subfolderA);
+
+ expand_folder(smartFolderA);
+ assert_folder_expanded(smartFolderA);
+ assert_folder_visible(subfolderA);
+});
+
+/**
+ * Switch back to all folders.
+ */
+add_task(function test_return_to_all_folders() {
+ assert_folder_mode("smart");
+ mc.folderTreeView.activeModes = "smart";
+ assert_folder_mode("all");
+});
+
+registerCleanupFunction(function () {
+ inboxFolder.propagateDelete(subfolderA, true);
+ inboxFolder.propagateDelete(subfolderB, true);
+});
diff --git a/comm/mail/test/browser/folder-tree-modes/browser_modeSwitching.js b/comm/mail/test/browser/folder-tree-modes/browser_modeSwitching.js
new file mode 100644
index 0000000000..dee646c754
--- /dev/null
+++ b/comm/mail/test/browser/folder-tree-modes/browser_modeSwitching.js
@@ -0,0 +1,338 @@
+/* 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 the ability to switch between multiple folder modes.
+ */
+
+"use strict";
+
+var {
+ assert_folder_visible,
+ inboxFolder,
+ make_message_sets_in_folders,
+ mc,
+ toggle_main_menu,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+var { MailTelemetryForTests } = ChromeUtils.import(
+ "resource:///modules/MailGlue.jsm"
+);
+var { TelemetryTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TelemetryTestUtils.sys.mjs"
+);
+var { click_menus_in_sequence, click_through_appmenu, close_popup_sequence } =
+ ChromeUtils.import("resource://testing-common/mozmill/WindowHelpers.jsm");
+
+var rootFolder;
+var unreadFolder;
+var favoriteFolder;
+var modeList_menu;
+var modeList_appmenu;
+var view_menu;
+var view_menupopup;
+var appmenu_button;
+var appmenu_mainView;
+var appmenu_popup;
+var menu_state;
+var about3Pane;
+
+add_setup(async function () {
+ rootFolder = inboxFolder.server.rootFolder;
+
+ // Create one folder with unread messages and one favorite folder.
+ inboxFolder.createSubfolder("UnreadFolder", null);
+ unreadFolder = inboxFolder.getChildNamed("UnreadFolder");
+
+ inboxFolder.createSubfolder("FavoriteFolder", null);
+ favoriteFolder = inboxFolder.getChildNamed("FavoriteFolder");
+
+ await make_message_sets_in_folders([unreadFolder], [{ count: 1 }]);
+ favoriteFolder.setFlag(Ci.nsMsgFolderFlags.Favorite);
+
+ modeList_menu = mc.window.document.getElementById("menu_FolderViewsPopup");
+ modeList_appmenu = mc.window.document.getElementById("appMenu-foldersView");
+
+ view_menu = mc.window.document.getElementById("menu_View");
+ view_menupopup = mc.window.document.getElementById("menu_View_Popup");
+ appmenu_button = mc.window.document.getElementById("button-appmenu");
+ appmenu_mainView = mc.window.document.getElementById("appMenu-mainView");
+ appmenu_popup = mc.window.document.getElementById("appMenu-popup");
+
+ // Main menu is needed for this whole test file.
+ menu_state = toggle_main_menu(true);
+
+ about3Pane = document.getElementById("tabmail").currentAbout3Pane;
+
+ Services.xulStore.removeDocument(
+ "chrome://messenger/content/messenger.xhtml"
+ );
+ Services.telemetry.clearScalars();
+});
+
+/**
+ * Check whether the expected folder mode is selected in menus and internally.
+ *
+ * @param {string} aMode - The name of the expected mode.
+ */
+async function assert_mode_selected(aMode) {
+ if (aMode != "compact") {
+ // "compact" isn't really a mode, we're just using this function because
+ // it tests everything we want to test.
+ Assert.ok(about3Pane.folderPane.activeModes.includes(aMode));
+ }
+
+ // We need to open the menu because only then the right mode is set in them.
+ if (["linux", "win"].includes(AppConstants.platform)) {
+ // On OS X the main menu seems not accessible for clicking from tests.
+ EventUtils.synthesizeMouseAtCenter(view_menu, { clickCount: 1 }, mc.window);
+ let popuplist = await click_menus_in_sequence(
+ view_menupopup,
+ [{ id: modeList_menu.parentNode.id }],
+ true
+ );
+ for (let mode of about3Pane.folderPane.activeModes) {
+ Assert.ok(
+ modeList_menu.querySelector(`[value="${mode}"]`).hasAttribute("checked")
+ );
+ }
+ close_popup_sequence(popuplist);
+ }
+
+ EventUtils.synthesizeMouseAtCenter(appmenu_button, {}, mc.window);
+ click_through_appmenu(
+ [{ id: "appmenu_View" }, { id: "appmenu_FolderViews" }],
+ null,
+ mc.window
+ );
+ for (let mode of about3Pane.folderPane.activeModes) {
+ Assert.ok(
+ modeList_appmenu
+ .querySelector(`[value="${mode}"]`)
+ .hasAttribute("checked")
+ );
+ }
+ appmenu_popup.hidePopup();
+}
+
+/**
+ * Check whether the expected folder mode is unselected in menus and internally.
+ *
+ * @param {string} mode - The name of the missing mode.
+ */
+async function assert_mode_not_selected(mode) {
+ Assert.ok(!about3Pane.folderPane.activeModes.includes(mode));
+
+ // We need to open the menu because only then the right mode is set in them.
+ if (["linux", "win"].includes(AppConstants.platform)) {
+ // On OS X the main menu seems not accessible for clicking from tests.
+ EventUtils.synthesizeMouseAtCenter(view_menu, { clickCount: 1 }, mc.window);
+ let popuplist = await click_menus_in_sequence(
+ view_menupopup,
+ [{ id: modeList_menu.parentNode.id }],
+ true
+ );
+ Assert.ok(
+ !modeList_menu.querySelector(`[value="${mode}"]`).hasAttribute("checked")
+ );
+ close_popup_sequence(popuplist);
+ }
+
+ EventUtils.synthesizeMouseAtCenter(appmenu_button, {}, mc.window);
+ click_through_appmenu(
+ [{ id: "appmenu_View" }, { id: "appmenu_FolderViews" }],
+ null,
+ mc.window
+ );
+ Assert.ok(
+ !modeList_appmenu.querySelector(`[value="${mode}"]`).hasAttribute("checked")
+ );
+ appmenu_popup.hidePopup();
+}
+
+/**
+ * Toggle the folder mode by clicking in the menu.
+ *
+ * @param mode The base name of the mode to select.
+ */
+function select_mode_in_menu(mode) {
+ EventUtils.synthesizeMouseAtCenter(appmenu_button, {}, mc.window);
+ click_through_appmenu(
+ [{ id: "appmenu_View" }, { id: "appmenu_FolderViews" }],
+ { value: mode },
+ mc.window
+ );
+ appmenu_popup.hidePopup();
+}
+
+/**
+ * Check the all folders mode.
+ */
+async function subtest_toggle_all_folders(show) {
+ let mode = "all";
+ select_mode_in_menu(mode);
+
+ if (show) {
+ await assert_mode_selected(mode);
+ } else {
+ await assert_mode_not_selected(mode);
+ }
+}
+
+/**
+ * Check the unread folders mode.
+ */
+async function subtest_toggle_unread_folders(show) {
+ let mode = "unread";
+ select_mode_in_menu(mode);
+
+ if (show) {
+ await assert_mode_selected(mode);
+
+ // Mode is hierarchical, parent folders are shown.
+ assert_folder_visible(inboxFolder.server.rootFolder);
+ assert_folder_visible(inboxFolder);
+ assert_folder_visible(unreadFolder);
+ } else {
+ await assert_mode_not_selected(mode);
+ }
+}
+
+/**
+ * Check the favorite folders mode.
+ */
+async function subtest_toggle_favorite_folders(show) {
+ let mode = "favorite";
+ select_mode_in_menu(mode);
+
+ if (show) {
+ await assert_mode_selected(mode);
+
+ // Mode is hierarchical, parent folders are shown.
+ assert_folder_visible(inboxFolder.server.rootFolder);
+ assert_folder_visible(inboxFolder);
+ assert_folder_visible(favoriteFolder);
+ } else {
+ await assert_mode_not_selected(mode);
+ }
+}
+
+/**
+ * Check the recent folders mode.
+ */
+async function subtest_toggle_recent_folders(show) {
+ let mode = "recent";
+ select_mode_in_menu(mode);
+
+ if (show) {
+ await assert_mode_selected(mode);
+ } else {
+ await assert_mode_not_selected(mode);
+ }
+}
+
+/**
+ * Check the smart folders mode.
+ */
+async function subtest_toggle_smart_folders(show) {
+ let mode = "smart";
+ select_mode_in_menu(mode);
+
+ if (show) {
+ await assert_mode_selected(mode);
+ } else {
+ await assert_mode_not_selected(mode);
+ }
+}
+
+/**
+ * Toggle the compact mode.
+ */
+async function subtest_toggle_compact(compact) {
+ let mode = "compact";
+ select_mode_in_menu(mode);
+
+ if (compact) {
+ await assert_mode_selected(mode);
+ } else {
+ await assert_mode_not_selected(mode);
+ }
+}
+
+/**
+ * Toggle the compact mode.
+ */
+async function subtest_toggle_tags(show) {
+ let mode = "tags";
+ select_mode_in_menu(mode);
+
+ if (show) {
+ await assert_mode_selected(mode);
+ } else {
+ await assert_mode_not_selected(mode);
+ }
+}
+
+/**
+ * Check that the current mode(s) are accurately recorded in telemetry.
+ * Note that `reportUIConfiguration` usually only runs at start-up.
+ */
+function check_scalars(expected) {
+ MailTelemetryForTests.reportUIConfiguration();
+ let scalarName = "tb.ui.configuration.folder_tree_modes";
+ let scalars = TelemetryTestUtils.getProcessScalars("parent");
+ if (expected) {
+ TelemetryTestUtils.assertScalar(scalars, scalarName, expected);
+ } else {
+ TelemetryTestUtils.assertScalarUnset(scalars, scalarName);
+ }
+}
+
+/**
+ * Toggle folder modes through different means and sequences.
+ */
+add_task(async function test_toggling_modes() {
+ check_scalars();
+
+ await subtest_toggle_all_folders(true);
+ await subtest_toggle_smart_folders(true);
+ check_scalars("all,smart");
+
+ await subtest_toggle_tags(true);
+ check_scalars("all,smart,tags");
+
+ await subtest_toggle_unread_folders(true);
+ await subtest_toggle_favorite_folders(true);
+ await subtest_toggle_recent_folders(true);
+ check_scalars("all,smart,tags,unread,favorite,recent");
+
+ await subtest_toggle_compact(true);
+ check_scalars("all,smart,tags,unread,favorite,recent (compact)");
+
+ await subtest_toggle_unread_folders(false);
+ check_scalars("all,smart,tags,favorite,recent (compact)");
+
+ await subtest_toggle_compact(false);
+ check_scalars("all,smart,tags,favorite,recent");
+
+ await subtest_toggle_favorite_folders(false);
+ check_scalars("all,smart,tags,recent");
+
+ await subtest_toggle_all_folders(false);
+ await subtest_toggle_recent_folders(false);
+ await subtest_toggle_smart_folders(false);
+ await subtest_toggle_tags(false);
+
+ // Confirm that the all folders mode is visible even after all the modes have
+ // been deselected in order to ensure that the Folder Pane is never empty.
+ await assert_mode_selected("all");
+ check_scalars("all");
+});
+
+registerCleanupFunction(function () {
+ inboxFolder.propagateDelete(unreadFolder, true);
+ inboxFolder.propagateDelete(favoriteFolder, true);
+ toggle_main_menu(menu_state);
+});
diff --git a/comm/mail/test/browser/folder-tree-modes/browser_smartFolders.js b/comm/mail/test/browser/folder-tree-modes/browser_smartFolders.js
new file mode 100644
index 0000000000..47fdca0058
--- /dev/null
+++ b/comm/mail/test/browser/folder-tree-modes/browser_smartFolders.js
@@ -0,0 +1,179 @@
+/* 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 smart folder mode works properly.
+ */
+
+"use strict";
+
+var {
+ archive_selected_messages,
+ expand_folder,
+ FAKE_SERVER_HOSTNAME,
+ get_about_3pane,
+ get_smart_folder_named,
+ get_special_folder,
+ inboxFolder,
+ make_message_sets_in_folders,
+ select_click_row,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+var about3Pane;
+var rootFolder;
+var inboxSubfolder;
+var trashFolder;
+var trashSubfolder;
+
+var smartInboxFolder;
+
+var inboxSet;
+
+add_setup(async function () {
+ about3Pane = get_about_3pane();
+ rootFolder = inboxFolder.server.rootFolder;
+ // Create a folder as a subfolder of the inbox
+ inboxFolder.createSubfolder("SmartFoldersA", null);
+ inboxSubfolder = inboxFolder.getChildNamed("SmartFoldersA");
+
+ trashFolder = inboxFolder.server.rootFolder.getFolderWithFlags(
+ Ci.nsMsgFolderFlags.Trash
+ );
+ trashFolder.createSubfolder("SmartFoldersB", null);
+ trashSubfolder = trashFolder.getChildNamed("SmartFoldersB");
+
+ // The message itself doesn't really matter, as long as there's at least one
+ // in the folder.
+ [inboxSet] = await make_message_sets_in_folders(
+ [inboxFolder],
+ [{ count: 1 }]
+ );
+ await make_message_sets_in_folders([inboxSubfolder], [{ count: 1 }]);
+
+ // Switch to the smart folder mode.
+ about3Pane.folderPane.activeModes = ["smart"];
+
+ // The smart inbox may not have been created at setup time, so get it now.
+ smartInboxFolder = get_smart_folder_named("Inbox");
+});
+
+/**
+ * Test that smart folders are updated when the folders they should be
+ * searching over are added/removed or have the relevant flag set/cleared.
+ */
+add_task(async function test_folder_flag_changes() {
+ expand_folder(smartInboxFolder);
+ // Now attempt to select the folder.
+ about3Pane.displayFolder(inboxSubfolder);
+ // Need to archive two messages in two different accounts in order to
+ // create a smart Archives folder.
+ select_click_row(0);
+ archive_selected_messages();
+ let pop3Server = MailServices.accounts.findServer(
+ "tinderbox",
+ FAKE_SERVER_HOSTNAME,
+ "pop3"
+ );
+ let pop3Inbox = await get_special_folder(
+ Ci.nsMsgFolderFlags.Inbox,
+ false,
+ pop3Server
+ );
+ await make_message_sets_in_folders([pop3Inbox], [{ count: 1 }]);
+ about3Pane.displayFolder(pop3Inbox);
+ select_click_row(0);
+ archive_selected_messages();
+
+ let smartArchiveFolder = get_smart_folder_named("Archives");
+ let archiveScope =
+ "|" +
+ smartArchiveFolder.msgDatabase.dBFolderInfo.getCharProperty(
+ "searchFolderUri"
+ ) +
+ "|";
+ // We should have both this account, and a folder corresponding
+ // to this year in the scope.
+ rootFolder = inboxFolder.server.rootFolder;
+ let archiveFolder = rootFolder.getChildNamed("Archives");
+ assert_folder_and_children_in_scope(archiveFolder, archiveScope);
+ archiveFolder = pop3Server.rootFolder.getChildNamed("Archives");
+ assert_folder_and_children_in_scope(archiveFolder, archiveScope);
+
+ // Remove the archive flag, and make sure the archive folder and
+ // its children are no longer in the search scope.
+ archiveFolder.clearFlag(Ci.nsMsgFolderFlags.Archive);
+
+ // Refresh the archive scope because clearing the flag should have
+ // changed it.
+ archiveScope =
+ "|" +
+ smartArchiveFolder.msgDatabase.dBFolderInfo.getCharProperty(
+ "searchFolderUri"
+ ) +
+ "|";
+
+ // figure out what we expect the archiveScope to now be.
+ rootFolder = inboxFolder.server.rootFolder;
+ let localArchiveFolder = rootFolder.getChildNamed("Archives");
+ let desiredScope = "|" + localArchiveFolder.URI + "|";
+ for (let folder of localArchiveFolder.descendants) {
+ desiredScope += folder.URI + "|";
+ }
+
+ Assert.equal(
+ archiveScope,
+ desiredScope,
+ "archive scope after removing folder"
+ );
+ assert_folder_and_children_not_in_scope(archiveFolder, archiveScope);
+});
+
+function assert_folder_and_children_in_scope(folder, searchScope) {
+ let folderURI = "|" + folder.URI + "|";
+ assert_uri_found(folderURI, searchScope);
+ for (let f of folder.descendants) {
+ assert_uri_found(f.URI, searchScope);
+ }
+}
+
+function assert_folder_and_children_not_in_scope(folder, searchScope) {
+ let folderURI = "|" + folder.URI + "|";
+ assert_uri_not_found(folderURI, searchScope);
+ for (let f of folder.descendants) {
+ assert_uri_not_found(f.URI, searchScope);
+ }
+}
+
+function assert_uri_found(folderURI, scopeList) {
+ if (!scopeList.includes(folderURI)) {
+ throw new Error("scope " + scopeList + "doesn't contain " + folderURI);
+ }
+}
+
+function assert_uri_not_found(folderURI, scopeList) {
+ if (scopeList.includes(folderURI)) {
+ throw new Error(
+ "scope " + scopeList + "contains " + folderURI + " but shouldn't"
+ );
+ }
+}
+
+registerCleanupFunction(async function () {
+ about3Pane.folderPane.activeModes = ["all"];
+ inboxFolder.propagateDelete(inboxSubfolder, true);
+ inboxFolder.deleteMessages(
+ [...inboxFolder.messages],
+ top.msgWindow,
+ false,
+ false,
+ null,
+ false
+ );
+ trashFolder.propagateDelete(trashSubfolder, true);
+});
diff --git a/comm/mail/test/browser/folder-tree-modes/browser_unreadFolders.js b/comm/mail/test/browser/folder-tree-modes/browser_unreadFolders.js
new file mode 100644
index 0000000000..ffc6dc96ac
--- /dev/null
+++ b/comm/mail/test/browser/folder-tree-modes/browser_unreadFolders.js
@@ -0,0 +1,91 @@
+/* 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 unread folder mode works properly. This includes making
+ * sure that the selected folder is maintained correctly when the view
+ * is rebuilt because a folder has become newly unread.
+ */
+
+"use strict";
+
+var {
+ assert_folder_visible,
+ be_in_folder,
+ delete_messages,
+ get_about_3pane,
+ inboxFolder,
+ make_message_sets_in_folders,
+ mc,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+
+var about3Pane;
+var rootFolder;
+var inboxSubfolder;
+var trashFolder;
+var trashSubfolder;
+var inboxSet;
+
+add_setup(async function () {
+ about3Pane = get_about_3pane();
+ rootFolder = inboxFolder.server.rootFolder;
+
+ // Create a folder as a subfolder of the inbox
+ inboxFolder.createSubfolder("UnreadFoldersA", null);
+ inboxSubfolder = inboxFolder.getChildNamed("UnreadFoldersA");
+
+ trashFolder = inboxFolder.server.rootFolder.getFolderWithFlags(
+ Ci.nsMsgFolderFlags.Trash
+ );
+ trashFolder.createSubfolder("UnreadFoldersB", null);
+ trashSubfolder = trashFolder.getChildNamed("UnreadFoldersB");
+
+ // The message itself doesn't really matter, as long as there's at least one
+ // in the folder.
+ [inboxSet] = await make_message_sets_in_folders(
+ [inboxFolder],
+ [{ count: 1 }]
+ );
+ await make_message_sets_in_folders([inboxSubfolder], [{ count: 1 }]);
+
+ // Switch to the unread folder mode.
+ await be_in_folder(inboxFolder);
+ about3Pane.folderPane.activeModes = ["unread"];
+});
+
+/**
+ * Test that inbox and inboxSubfolder are in view
+ */
+add_task(async function test_folder_population() {
+ about3Pane.folderTree.expandRowAtIndex(0);
+ await new Promise(resolve => setTimeout(resolve));
+ assert_folder_visible(inboxFolder);
+
+ about3Pane.folderTree.expandRowAtIndex(1);
+ await new Promise(resolve => setTimeout(resolve));
+ assert_folder_visible(inboxSubfolder);
+});
+
+/**
+ * Test that a folder newly getting unread messages doesn't
+ * change the selected folder in unread folders mode.
+ */
+add_task(async function test_newly_added_folder() {
+ let [newSet] = await make_message_sets_in_folders(
+ [trashFolder],
+ [{ count: 1 }]
+ );
+ assert_folder_visible(trashFolder);
+ Assert.equal(about3Pane.folderTree.selectedIndex, 0);
+ await delete_messages(newSet);
+});
+
+registerCleanupFunction(async function () {
+ inboxFolder.propagateDelete(inboxSubfolder, true);
+ await delete_messages(inboxSet);
+ trashFolder.propagateDelete(trashSubfolder, true);
+ about3Pane.folderPane.activeModes = ["all"];
+});