diff options
Diffstat (limited to 'comm/mail/test/browser/folder-pane')
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; +}); |