/* 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 deleting a message in a given tab or window properly updates both * that tab/window as well as all other tabs/windows. We also test that the * message tab title updates appropriately through all of this. We do all of * this both for tabs that have ever been opened in the foreground, and tabs * that haven't (and thus might have fake selections). */ "use strict"; var { assert_selected_and_displayed, assert_tab_titled_from, be_in_folder, close_message_window, close_tab, create_folder, get_about_3pane, get_about_message, make_message_sets_in_folders, mc, open_selected_message_in_new_tab, open_selected_message_in_new_window, press_delete, select_click_row, select_control_click_row, select_shift_click_row, switch_tab, } = ChromeUtils.import( "resource://testing-common/mozmill/FolderDisplayHelpers.jsm" ); var { plan_for_window_close, wait_for_window_close } = ChromeUtils.import( "resource://testing-common/mozmill/WindowHelpers.jsm" ); var folder, lastMessageFolder, oneBeforeFolder, oneAfterFolder, multipleDeletionFolder1, multipleDeletionFolder2, multipleDeletionFolder3, multipleDeletionFolder4; // Adjust timeout to take care of code coverage runs needing twice as long. requestLongerTimeout(AppConstants.MOZ_CODE_COVERAGE ? 4 : 2); add_setup(async function () { folder = await create_folder("DeletionA"); lastMessageFolder = await create_folder("DeletionB"); oneBeforeFolder = await create_folder("DeletionC"); oneAfterFolder = await create_folder("DeletionD"); multipleDeletionFolder1 = await create_folder("DeletionE"); multipleDeletionFolder2 = await create_folder("DeletionF"); multipleDeletionFolder3 = await create_folder("DeletionG"); multipleDeletionFolder4 = await create_folder("DeletionH"); // we want exactly as many messages as we plan to delete, so that we can test // that the message window and tabs close when they run out of things to // to display. await make_message_sets_in_folders([folder], [{ count: 4 }]); // since we don't test window close here, it doesn't really matter how many // messages these have await make_message_sets_in_folders([lastMessageFolder], [{ count: 4 }]); await make_message_sets_in_folders([oneBeforeFolder], [{ count: 10 }]); await make_message_sets_in_folders([oneAfterFolder], [{ count: 10 }]); await make_message_sets_in_folders( [multipleDeletionFolder1], [{ count: 30 }] ); // We're depending on selecting the last message here, so these do matter await make_message_sets_in_folders( [multipleDeletionFolder2], [{ count: 10 }] ); await make_message_sets_in_folders( [multipleDeletionFolder3], [{ count: 10 }] ); await make_message_sets_in_folders( [multipleDeletionFolder4], [{ count: 10 }] ); }); var tabFolder, tabMessage, tabMessageBackground, curMessage, nextMessage; /** * The message window controller. Short names because controllers get used a * lot. */ var msgc; /** * Open up the message at aIndex in all our display mechanisms, and check to see * if the displays are all correct. This also sets up all our globals. */ async function _open_message_in_all_four_display_mechanisms_helper( aFolder, aIndex ) { // - Select the message in this tab. tabFolder = await be_in_folder(aFolder); curMessage = select_click_row(aIndex); assert_selected_and_displayed(curMessage); // - Open the tab with the message tabMessage = await open_selected_message_in_new_tab(); assert_selected_and_displayed(curMessage); assert_tab_titled_from(tabMessage, curMessage); // go back to the folder tab await switch_tab(tabFolder); // - Open another tab with the message, this time in the background tabMessageBackground = await open_selected_message_in_new_tab(true); assert_tab_titled_from(tabMessageBackground, curMessage); // - Open the window with the message // need to go back to the folder tab. (well, should.) await switch_tab(tabFolder); msgc = await open_selected_message_in_new_window(); assert_selected_and_displayed(msgc, curMessage); } // Check whether this message is displayed in the folder tab var VERIFY_FOLDER_TAB = 0x1; // Check whether this message is displayed in the foreground message tab var VERIFY_MESSAGE_TAB = 0x2; // Check whether this message is displayed in the background message tab var VERIFY_BACKGROUND_MESSAGE_TAB = 0x4; // Check whether this message is displayed in the message window var VERIFY_MESSAGE_WINDOW = 0x8; var VERIFY_ALL = 0xf; /** * Verify that the message is displayed in the given tabs. The index is * optional. */ async function _verify_message_is_displayed_in(aFlags, aMessage, aIndex) { if (aFlags & VERIFY_FOLDER_TAB) { await switch_tab(tabFolder); Assert.equal( get_about_message().gMessage, aMessage, "folder tab shows the correct message" ); assert_selected_and_displayed(aMessage); if (aIndex !== undefined) { assert_selected_and_displayed(aIndex); } } if (aFlags & VERIFY_MESSAGE_TAB) { // Verify the title first assert_tab_titled_from(tabMessage, aMessage); await switch_tab(tabMessage); // Verify the title again, just in case Assert.equal( get_about_message().gMessageURI, aMessage.folder.getUriForMsg(aMessage) ); assert_tab_titled_from(tabMessage, aMessage); Assert.equal( get_about_message().gMessage, aMessage, "message tab shows the correct message" ); assert_selected_and_displayed(aMessage); if (aIndex !== undefined) { assert_selected_and_displayed(aIndex); } } if (aFlags & VERIFY_BACKGROUND_MESSAGE_TAB) { // Only verify the title assert_tab_titled_from(tabMessageBackground, aMessage); } if (aFlags & VERIFY_MESSAGE_WINDOW) { Assert.equal( get_about_message(msgc.window).gMessage, aMessage, "message window shows the correct message" ); assert_selected_and_displayed(msgc, aMessage); if (aIndex !== undefined) { assert_selected_and_displayed(msgc, aIndex); } } } /** * Have a message displayed in a folder tab, message tab (foreground and * background), and message window. The idea is that as we delete from the * various sources, they should all advance in lock-step through their messages, * simplifying our lives (but making us explode forevermore the first time any * of the tests fail.) */ add_task( async function test_open_first_message_in_all_four_display_mechanisms() { await _open_message_in_all_four_display_mechanisms_helper(folder, 0); } ); /** * Perform a deletion from the folder tab, verify the others update correctly * (advancing to the next message). */ add_task(async function test_delete_in_folder_tab() { let about3Pane = get_about_3pane(); // - plan to end up on the guy who is currently at index 1 curMessage = about3Pane.gDBView.getMsgHdrAt(1); // while we're at it, figure out who is at 2 for the next step nextMessage = about3Pane.gDBView.getMsgHdrAt(2); // - delete the message press_delete(); // - verify all displays await _verify_message_is_displayed_in(VERIFY_ALL, curMessage, 0); }); /** * Perform a deletion from the message tab, verify the others update correctly * (advancing to the next message). */ add_task(async function test_delete_in_message_tab() { await switch_tab(tabMessage); // nextMessage is the guy we want to see once the delete completes. press_delete(); curMessage = nextMessage; // - verify all displays await _verify_message_is_displayed_in(VERIFY_ALL, curMessage, 0); // figure out the next guy... nextMessage = get_about_message().gDBView.getMsgHdrAt(1); if (!nextMessage) { throw new Error("We ran out of messages early?"); } }); /** * Perform a deletion from the message window, verify the others update * correctly (advancing to the next message). */ add_task(async function test_delete_in_message_window() { // - delete press_delete(msgc); curMessage = nextMessage; // - verify all displays await _verify_message_is_displayed_in(VERIFY_ALL, curMessage, 0); }); /** * Delete the last message in that folder, which should close all message * displays. */ add_task(async function test_delete_last_message_closes_message_displays() { // - since we have both foreground and background message tabs, we don't need // to open yet another tab to test // - prep for the message window disappearing plan_for_window_close(msgc); // - let's arbitrarily perform the deletion on this message tab await switch_tab(tabMessage); press_delete(); // - the message window should have gone away... // (this also helps ensure that the 3pane gets enough event loop time to do // all that it needs to accomplish) wait_for_window_close(msgc); msgc = null; // - and we should now be on the folder tab and there should be no other tabs if (mc.window.document.getElementById("tabmail").tabInfo.length != 1) { throw new Error("There should only be one tab left!"); } // the below check is implied by the previous check if things are sane-ish if ( mc.window.document.getElementById("tabmail").currentTabInfo != tabFolder ) { throw new Error("We should be on the folder tab!"); } }); /* * Now we retest everything, but while deleting the last message in our * selection. We need to make sure we select the previously next-to-last message * in that case. */ /** * Have the last message displayed in a folder tab, message tab (foreground and * background), and message window. The idea is that as we delete from the * various sources, they should all advance in lock-step through their messages, * simplifying our lives (but making us explode forevermore the first time any * of the tests fail.) */ add_task( async function test_open_last_message_in_all_four_display_mechanisms() { // since we have four messages, index 3 is the last message. await _open_message_in_all_four_display_mechanisms_helper( lastMessageFolder, 3 ); } ); /** * Perform a deletion from the folder tab, verify the others update correctly * (advancing to the next message). */ add_task(async function test_delete_last_message_in_folder_tab() { let about3Pane = get_about_3pane(); // - plan to end up on the guy who is currently at index 2 curMessage = about3Pane.gDBView.getMsgHdrAt(2); // while we're at it, figure out who is at 1 for the next step nextMessage = about3Pane.gDBView.getMsgHdrAt(1); // - delete the message press_delete(); // - verify all displays await _verify_message_is_displayed_in(VERIFY_ALL, curMessage, 2); }); /** * Perform a deletion from the message tab, verify the others update correctly * (advancing to the next message). */ add_task(async function test_delete_last_message_in_message_tab() { // (we're still on the message tab, and nextMessage is the guy we want to see // once the delete completes.) press_delete(); curMessage = nextMessage; // - verify all displays await _verify_message_is_displayed_in(VERIFY_ALL, curMessage, 1); // figure out the next guy... nextMessage = get_about_message().gDBView.getMsgHdrAt(0); if (!nextMessage) { throw new Error("We ran out of messages early?"); } }); /** * Perform a deletion from the message window, verify the others update * correctly (advancing to the next message). */ add_task(async function test_delete_last_message_in_message_window() { // Vary this up. Switch to the folder tab instead of staying on the message // tab await switch_tab(tabFolder); // - delete press_delete(msgc); curMessage = nextMessage; // - verify all displays await _verify_message_is_displayed_in(VERIFY_ALL, curMessage, 0); // - clean up, close the message window and displays close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); }); /* * Our next job is to open up a message, then delete the message one before it * in another view. The other selections shouldn't be affected. */ /** * Test "one before" deletion in the folder tab. */ add_task(async function test_delete_one_before_message_in_folder_tab() { // Open up message 4 in message tabs and a window (we'll delete message 3). await _open_message_in_all_four_display_mechanisms_helper(oneBeforeFolder, 4); let expectedMessage = get_about_3pane().gDBView.getMsgHdrAt(4); select_click_row(3); press_delete(); // The message tab, background message tab and window shouldn't have changed await _verify_message_is_displayed_in( VERIFY_MESSAGE_TAB | VERIFY_BACKGROUND_MESSAGE_TAB | VERIFY_MESSAGE_WINDOW, expectedMessage ); // Clean up, close everything close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); }); /** * Test "one before" deletion in the message tab. */ add_task(async function test_delete_one_before_message_in_message_tab() { // Open up 3 in a message tab, then select and open up 4 in a background tab // and window. select_click_row(3); tabMessage = await open_selected_message_in_new_tab(true); let expectedMessage = select_click_row(4); tabMessageBackground = await open_selected_message_in_new_tab(true); msgc = await open_selected_message_in_new_window(true); // Switch to the message tab, and delete. await switch_tab(tabMessage); press_delete(); // The folder tab, background message tab and window shouldn't have changed await _verify_message_is_displayed_in( VERIFY_FOLDER_TAB | VERIFY_BACKGROUND_MESSAGE_TAB | VERIFY_MESSAGE_WINDOW, expectedMessage ); // Clean up, close everything close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); }); /** * Test "one before" deletion in the message window. */ add_task(async function test_delete_one_before_message_in_message_window() { // Open up 3 in a message window, then select and open up 4 in a background // and a foreground tab. select_click_row(3); msgc = await open_selected_message_in_new_window(); let expectedMessage = select_click_row(4); tabMessage = await open_selected_message_in_new_tab(); await switch_tab(tabFolder); tabMessageBackground = await open_selected_message_in_new_tab(true); // Press delete in the message window. press_delete(msgc); // The folder tab, message tab and background message tab shouldn't have // changed await _verify_message_is_displayed_in( VERIFY_FOLDER_TAB | VERIFY_MESSAGE_TAB | VERIFY_BACKGROUND_MESSAGE_TAB, expectedMessage ); // Clean up, close everything close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); }); /* * Now do all of that again, but this time delete the message _after_ the open one. */ /** * Test "one after" deletion in the folder tab. */ add_task(async function test_delete_one_after_message_in_folder_tab() { // Open up message 4 in message tabs and a window (we'll delete message 5). await _open_message_in_all_four_display_mechanisms_helper(oneAfterFolder, 4); let expectedMessage = get_about_3pane().gDBView.getMsgHdrAt(4); select_click_row(5); press_delete(); // The message tab, background message tab and window shouldn't have changed await _verify_message_is_displayed_in( VERIFY_MESSAGE_TAB | VERIFY_BACKGROUND_MESSAGE_TAB | VERIFY_MESSAGE_WINDOW, expectedMessage ); // Clean up, close everything close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); }); /** * Test "one after" deletion in the message tab. */ add_task(async function test_delete_one_after_message_in_message_tab() { // Open up 5 in a message tab, then select and open up 4 in a background tab // and window. select_click_row(5); tabMessage = await open_selected_message_in_new_tab(true); let expectedMessage = select_click_row(4); tabMessageBackground = await open_selected_message_in_new_tab(true); msgc = await open_selected_message_in_new_window(true); // Switch to the message tab, and delete. await switch_tab(tabMessage); press_delete(); // The folder tab, background message tab and window shouldn't have changed await _verify_message_is_displayed_in( VERIFY_FOLDER_TAB | VERIFY_BACKGROUND_MESSAGE_TAB | VERIFY_MESSAGE_WINDOW, expectedMessage ); // Clean up, close everything close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); }); /** * Test "one after" deletion in the message window. */ add_task(async function test_delete_one_after_message_in_message_window() { // Open up 5 in a message window, then select and open up 4 in a background // and a foreground tab. select_click_row(5); msgc = await open_selected_message_in_new_window(); let expectedMessage = select_click_row(4); tabMessage = await open_selected_message_in_new_tab(); await switch_tab(tabFolder); tabMessageBackground = await open_selected_message_in_new_tab(true); // Press delete in the message window. press_delete(msgc); // The folder tab, message tab and background message tab shouldn't have // changed await _verify_message_is_displayed_in( VERIFY_FOLDER_TAB | VERIFY_MESSAGE_TAB | VERIFY_BACKGROUND_MESSAGE_TAB, expectedMessage ); // Clean up, close everything close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); }); /* * Delete multiple messages in a folder tab. Make sure message displays at the * beginning, middle and end of a selection work out. */ /** * Test deleting multiple messages in a folder tab, with message displays open * to the beginning of a selection. */ add_task( async function test_delete_multiple_messages_with_first_selected_message_open() { // Open up 2 in a message tab, background tab, and message window. await _open_message_in_all_four_display_mechanisms_helper( multipleDeletionFolder1, 2 ); // We'll select 2-5, 8, 9 and 10. We expect 6 to be the next displayed // message. select_click_row(2); select_shift_click_row(5); select_control_click_row(8); select_control_click_row(9); select_control_click_row(10); let expectedMessage = get_about_3pane().gDBView.getMsgHdrAt(6); // Delete the selected messages press_delete(); // All the displays should now be showing the expectedMessage await _verify_message_is_displayed_in(VERIFY_ALL, expectedMessage); // Clean up, close everything close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); } ); /** * Test deleting multiple messages in a folder tab, with message displays open * to somewhere in the middle of a selection. */ add_task( async function test_delete_multiple_messages_with_nth_selected_message_open() { // Open up 9 in a message tab, background tab, and message window. await _open_message_in_all_four_display_mechanisms_helper( multipleDeletionFolder1, 9 ); // We'll select 2-5, 8, 9 and 10. We expect 11 to be the next displayed // message. select_click_row(2); select_shift_click_row(5); select_control_click_row(8); select_control_click_row(9); select_control_click_row(10); let expectedMessage = get_about_3pane().gDBView.getMsgHdrAt(11); // Delete the selected messages press_delete(); // The folder tab should now be showing message 2 assert_selected_and_displayed(2); // The other displays should now be showing the expectedMessage await _verify_message_is_displayed_in( VERIFY_MESSAGE_TAB | VERIFY_BACKGROUND_MESSAGE_TAB | VERIFY_MESSAGE_WINDOW, expectedMessage ); // Clean up, close everything close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); } ); /** * Test deleting multiple messages in a folder tab, with message displays open * to the end of a selection. */ add_task( async function test_delete_multiple_messages_with_last_selected_message_open() { // Open up 10 in a message tab, background tab, and message window. await _open_message_in_all_four_display_mechanisms_helper( multipleDeletionFolder1, 9 ); // We'll select 2-5, 8, 9 and 10. We expect 11 to be the next displayed // message. select_click_row(2); select_shift_click_row(5); select_control_click_row(8); select_control_click_row(9); select_control_click_row(10); let expectedMessage = get_about_3pane().gDBView.getMsgHdrAt(11); // Delete the selected messages press_delete(); // The folder tab should now be showing message 2 assert_selected_and_displayed(2); // The other displays should now be showing the expectedMessage await _verify_message_is_displayed_in( VERIFY_MESSAGE_TAB | VERIFY_BACKGROUND_MESSAGE_TAB | VERIFY_MESSAGE_WINDOW, expectedMessage ); // Clean up, close everything close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); } ); /** * Test deleting multiple messages in a folder tab (including the last one!), * with message displays open to the beginning of a selection. */ add_task( async function test_delete_multiple_messages_including_the_last_one_with_first_open() { // 10 messages in this folder. Open up message 1 everywhere. await _open_message_in_all_four_display_mechanisms_helper( multipleDeletionFolder2, 1 ); // We'll select 1-4, 7, 8 and 9. We expect 5 to be the next displayed message. select_click_row(1); select_shift_click_row(4); select_control_click_row(7); select_control_click_row(8); select_control_click_row(9); let expectedMessage = get_about_3pane().gDBView.getMsgHdrAt(5); // Delete the selected messages press_delete(); // All the displays should now be showing the expectedMessage await _verify_message_is_displayed_in(VERIFY_ALL, expectedMessage); // Clean up, close everything close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); } ); /** * Test deleting multiple messages in a folder tab (including the last one!), * with message displays open to the middle of a selection. */ add_task( async function test_delete_multiple_messages_including_the_last_one_with_nth_open() { // 10 messages in this folder. Open up message 7 everywhere. await _open_message_in_all_four_display_mechanisms_helper( multipleDeletionFolder3, 7 ); // We'll select 1-4, 7, 8 and 9. We expect 6 to be the next displayed message. select_click_row(1); select_shift_click_row(4); select_control_click_row(7); select_control_click_row(8); select_control_click_row(9); let expectedMessage = get_about_3pane().gDBView.getMsgHdrAt(6); // Delete the selected messages press_delete(); // The folder tab should now be showing message 1 assert_selected_and_displayed(1); // The other displays should now be showing the expectedMessage await _verify_message_is_displayed_in( VERIFY_MESSAGE_TAB | VERIFY_BACKGROUND_MESSAGE_TAB | VERIFY_MESSAGE_WINDOW, expectedMessage ); // Clean up, close everything close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); } ); /** * Test deleting multiple messages in a folder tab (including the last one!), * with message displays open to the end of a selection. */ add_task( async function test_delete_multiple_messages_including_the_last_one_with_last_open() { // 10 messages in this folder. Open up message 9 everywhere. await _open_message_in_all_four_display_mechanisms_helper( multipleDeletionFolder4, 9 ); // We'll select 1-4, 7, 8 and 9. We expect 6 to be the next displayed message. select_click_row(1); select_shift_click_row(4); select_control_click_row(7); select_control_click_row(8); select_control_click_row(9); let expectedMessage = get_about_3pane().gDBView.getMsgHdrAt(6); // Delete the selected messages press_delete(); // The folder tab should now be showing message 1 assert_selected_and_displayed(1); // The other displays should now be showing the expectedMessage await _verify_message_is_displayed_in( VERIFY_MESSAGE_TAB | VERIFY_BACKGROUND_MESSAGE_TAB | VERIFY_MESSAGE_WINDOW, expectedMessage ); // Clean up, close everything close_message_window(msgc); close_tab(tabMessage); close_tab(tabMessageBackground); await switch_tab(tabFolder); } );