Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Double timeout for code coverage runs.
if (AppConstants.MOZ_CODE_COVERAGE) {
requestLongerTimeout(2);
}
/*
* Test rearanging tabs via drag'n'drop.
*/
var {
assert_number_of_tabs_open,
assert_selected_and_displayed,
be_in_folder,
close_popup,
create_folder,
make_message_sets_in_folders,
open_folder_in_new_window,
open_selected_message_in_new_tab,
select_click_row,
switch_tab,
wait_for_message_display_completion,
} = ChromeUtils.importESModule(
);
var {
drag_n_drop_element,
synthesize_drag_end,
synthesize_drag_start,
synthesize_drag_over,
} = ChromeUtils.importESModule(
);
var { promise_new_window } = ChromeUtils.importESModule(
);
var folder;
var msgHdrsInFolder = [];
// The number of messages in folder.
var NUM_MESSAGES_IN_FOLDER = 15;
add_setup(async function () {
folder = await create_folder("MessageFolder");
await make_message_sets_in_folders(
[folder],
[{ count: NUM_MESSAGES_IN_FOLDER }]
);
msgHdrsInFolder = [...folder.messages];
folder.markAllMessagesRead(null);
await be_in_folder(folder);
});
registerCleanupFunction(async function () {
folder.deleteSelf(null);
});
/**
* Tests reordering tabs by drag'n'drop within the tabbar
*
* It opens additional movable and closable tabs. The picks the first
* movable tab and drops it onto the third movable tab.
*/
add_task(async function test_tab_reorder_tabbar() {
const tabmail = document.getElementById("tabmail");
// Ensure only one tab is open, otherwise our test most likey fail anyway.
tabmail.closeOtherTabs(0);
assert_number_of_tabs_open(1);
await be_in_folder(folder);
// Open four tabs
for (let idx = 0; idx < 4; idx++) {
await select_click_row(idx);
await open_selected_message_in_new_tab(true);
}
// Check if every thing is correctly initialized
assert_number_of_tabs_open(5);
Assert.ok(
tabmail.tabModes.mailMessageTab.tabs[0] == tabmail.tabInfo[1],
" tabMode.tabs and tabInfo out of sync"
);
Assert.ok(
tabmail.tabModes.mailMessageTab.tabs[1] ==
document.getElementById("tabmail").tabInfo[2],
" tabMode.tabs and tabInfo out of sync"
);
Assert.ok(
tabmail.tabModes.mailMessageTab.tabs[2] == tabmail.tabInfo[3],
" tabMode.tabs and tabInfo out of sync"
);
// Start dragging the first tab
await switch_tab(1);
await assert_selected_and_displayed(msgHdrsInFolder[0]);
const tab1 = tabmail.tabContainer.allTabs[1];
const tab3 = tabmail.tabContainer.allTabs[3];
drag_n_drop_element(
tab1,
window,
tab3,
window,
0.75,
0.0,
tabmail.tabContainer
);
await wait_for_message_display_completion(window);
// if every thing went well...
assert_number_of_tabs_open(5);
// ... we should find tab1 at the third position...
Assert.equal(tab1, tabmail.tabContainer.allTabs[3], "Moving tab1 failed");
await switch_tab(3);
await assert_selected_and_displayed(msgHdrsInFolder[0]);
// ... while tab3 moves one up and gets second.
Assert.ok(tab3 == tabmail.tabContainer.allTabs[2], "Moving tab3 failed");
await switch_tab(2);
await assert_selected_and_displayed(msgHdrsInFolder[2]);
// we have one "message" tab and three "folder" tabs, thus tabInfo[1-3] and
// tabMode["message"].tabs[0-2] have to be same, otherwise something went
// wrong while moving tabs around
Assert.ok(
tabmail.tabModes.mailMessageTab.tabs[0] == tabmail.tabInfo[1],
" tabMode.tabs and tabInfo out of sync"
);
Assert.ok(
tabmail.tabModes.mailMessageTab.tabs[1] == tabmail.tabInfo[2],
" tabMode.tabs and tabInfo out of sync"
);
Assert.ok(
tabmail.tabModes.mailMessageTab.tabs[2] == tabmail.tabInfo[3],
" tabMode.tabs and tabInfo out of sync"
);
teardownTest();
});
/**
* Tests drag'n'drop tab reordering between windows
*/
add_task(async function test_tab_reorder_window() {
const tabmail = document.getElementById("tabmail");
// Ensure only one tab is open, otherwise our test most likey fail anyway.
tabmail.closeOtherTabs(0);
assert_number_of_tabs_open(1);
let mc2 = null;
await be_in_folder(folder);
// Open a new tab...
await select_click_row(1);
await open_selected_message_in_new_tab(false);
assert_number_of_tabs_open(2);
await switch_tab(1);
await assert_selected_and_displayed(msgHdrsInFolder[1]);
// ...and then a new 3 pane as our drop target.
mc2 = await open_folder_in_new_window(folder);
const tabmail2 = mc2.document.getElementById("tabmail");
await TestUtils.waitForCondition(
() => tabmail2.currentAbout3Pane.gDBView,
"waiting for the new window to be ready"
);
// Start dragging the first tab ...
const tabA = tabmail.tabContainer.allTabs[1];
Assert.ok(tabA, "No movable Tab");
// We drop onto the Folder Tab, it is guaranteed to exist.
const tabB = tabmail2.tabContainer.allTabs[0];
Assert.ok(tabB, "No movable Tab");
drag_n_drop_element(tabA, window, tabB, mc2, 0.75, 0.0, tabmail.tabContainer);
Assert.ok(
tabmail.tabContainer.allTabs.length == 1,
"tab should be removed from the old window"
);
Assert.ok(
tabmail2.tabContainer.allTabs.length == 2,
"a new tab should have opened in then new window"
);
Assert.equal(
tabmail2.tabInfo[1].mode.name,
"mailMessageTab",
"new tab should be a message tab"
);
Assert.equal(
tabmail2.currentTabInfo,
tabmail2.tabInfo[1],
"new tab should be selected"
);
await TestUtils.waitForCondition(
() => tabmail2.currentAboutMessage.gDBView,
"waiting for the new tab to be ready"
);
await assert_selected_and_displayed(mc2, msgHdrsInFolder[1]);
teardownTest();
});
/**
* Tests detaching tabs into windows via drag'n'drop
*/
add_task(async function test_tab_reorder_detach() {
const tabmail = document.getElementById("tabmail");
// Ensure only one tab is open, otherwise our test most likey fail anyway.
tabmail.closeOtherTabs(0);
assert_number_of_tabs_open(1);
let mc2 = null;
await be_in_folder(folder);
// Open a new tab...
await select_click_row(2);
await open_selected_message_in_new_tab(false);
assert_number_of_tabs_open(2);
// ... if every thing works we should expect a new window...
const newWindowPromise = promise_new_window("mail:3pane");
// ... now start dragging
tabmail.switchToTab(1);
const tab1 = tabmail.tabContainer.allTabs[1];
const dropContent = document.getElementById("tabpanelcontainer");
const dt = synthesize_drag_start(window, tab1, tabmail.tabContainer);
synthesize_drag_over(window, dropContent, dt);
// notify tab1 drag has ended
const dropRect = dropContent.getBoundingClientRect();
synthesize_drag_end(window, dropContent, tab1, dt, {
screenX: dropContent.screenX + dropRect.width / 2,
screenY: dropContent.screenY + dropRect.height / 2,
});
// ... and wait for the new window
mc2 = await newWindowPromise;
const tabmail2 = mc2.document.getElementById("tabmail");
await TestUtils.waitForCondition(
() => tabmail2.tabInfo[1]?.chromeBrowser,
"waiting for a second tab to open in the new window"
);
await wait_for_message_display_completion(mc2, true);
Assert.ok(
tabmail.tabContainer.allTabs.length == 1,
"tab should be removed from the old window"
);
Assert.ok(
tabmail2.tabContainer.allTabs.length == 2,
"a new tab should have opened in then new window"
);
Assert.equal(
tabmail2.currentTabInfo,
tabmail2.tabInfo[1],
"new tab should be selected"
);
await TestUtils.waitForCondition(
() => tabmail2.currentAboutMessage?.gDBView,
"waiting for the new tab to be ready"
);
await assert_selected_and_displayed(mc2, msgHdrsInFolder[2]);
teardownTest();
});
/**
* Test undo of recently closed tabs.
*/
add_task(async function test_tab_undo() {
const tabmail = document.getElementById("tabmail");
// Ensure only one tab is open, otherwise our test most likey fail anyway.
tabmail.closeOtherTabs(0);
assert_number_of_tabs_open(1);
await be_in_folder(folder);
// Open five tabs...
for (let idx = 0; idx < 5; idx++) {
await select_click_row(idx);
await open_selected_message_in_new_tab(true);
}
assert_number_of_tabs_open(6);
await switch_tab(2);
await assert_selected_and_displayed(msgHdrsInFolder[1]);
tabmail.closeTab(2);
// This tab should not be added to recently closed tabs...
// ... thus it can't be restored
tabmail.closeTab(2, true);
tabmail.closeTab(2);
assert_number_of_tabs_open(3);
await assert_selected_and_displayed(window, msgHdrsInFolder[4]);
tabmail.undoCloseTab();
await wait_for_message_display_completion();
assert_number_of_tabs_open(4);
await assert_selected_and_displayed(window, msgHdrsInFolder[3]);
// msgHdrsInFolder[2] won't be restored, it was closed with disabled undo.
tabmail.undoCloseTab();
await wait_for_message_display_completion();
assert_number_of_tabs_open(5);
await assert_selected_and_displayed(window, msgHdrsInFolder[1]);
teardownTest();
});
async function _synthesizeRecentlyClosedMenu() {
const tab = document.getElementById("tabmail").tabContainer.allTabs[1];
EventUtils.synthesizeMouseAtCenter(
tab,
{ type: "contextmenu", button: 2 },
tab.ownerGlobal
);
const tabContextMenu = document.getElementById("tabContextMenu");
await BrowserTestUtils.waitForPopupEvent(tabContextMenu, "shown");
const recentlyClosedTabs = document.getElementById(
"tabContextMenuRecentlyClosed"
);
recentlyClosedTabs.openMenu(true);
await BrowserTestUtils.waitForPopupEvent(
recentlyClosedTabs.menupopup,
"shown"
);
return recentlyClosedTabs;
}
async function _teardownRecentlyClosedMenu() {
const menu = document.getElementById("tabContextMenu");
await close_popup(window, menu);
}
/**
* Tests the recently closed tabs menu.
*/
add_task(async function test_tab_recentlyClosed() {
const tabmail = document.getElementById("tabmail");
// Ensure only one tab is open, otherwise our test most likey fail anyway.
tabmail.closeOtherTabs(0, true);
assert_number_of_tabs_open(1);
// We start with a clean tab history.
tabmail.clearRecentlyClosedTabs();
Assert.equal(tabmail.recentlyClosedTabs.length, 0);
// The history is cleaned so let's open 15 tabs...
await be_in_folder(folder);
for (let idx = 0; idx < 15; idx++) {
await select_click_row(idx);
await open_selected_message_in_new_tab(true);
}
assert_number_of_tabs_open(16);
await switch_tab(2);
await assert_selected_and_displayed(msgHdrsInFolder[1]);
// ... and store the tab titles, to ensure they match with the menu items.
const tabTitles = [];
for (let idx = 0; idx < 16; idx++) {
tabTitles.unshift(tabmail.tabInfo[idx].title);
}
// Start the test by closing all tabs except the first two tabs...
for (let idx = 0; idx < 14; idx++) {
tabmail.closeTab(2);
}
assert_number_of_tabs_open(2);
// ...then open the context menu.
const menu = await _synthesizeRecentlyClosedMenu();
// Check if the context menu was populated correctly...
Assert.equal(menu.itemCount, 12, "Failed to populate context menu");
for (let idx = 0; idx < 10; idx++) {
Assert.equal(
tabTitles[idx],
menu.getItemAtIndex(idx).label,
`Tab Title ${idx} does not match Menu item`
);
}
// Restore the most recently closed tab
let tabOpenPromise = BrowserTestUtils.waitForEvent(
tabmail.tabContainer,
"TabOpen"
);
menu.menupopup.activateItem(menu.getItemAtIndex(0));
await _teardownRecentlyClosedMenu();
await new Promise(resolve => setTimeout(resolve));
await tabOpenPromise;
await wait_for_message_display_completion(window);
assert_number_of_tabs_open(3);
await assert_selected_and_displayed(msgHdrsInFolder[14]);
// The context menu should now contain one item less.
await _synthesizeRecentlyClosedMenu();
Assert.equal(menu.itemCount, 11, "Failed to populate context menu again");
for (let idx = 0; idx < 9; idx++) {
Assert.equal(
tabTitles[idx + 1],
menu.getItemAtIndex(idx).label,
`Tab Title ${idx} does not match Menu item 2`
);
}
// Now we restore an "random" tab.
tabOpenPromise = BrowserTestUtils.waitForEvent(
tabmail.tabContainer,
"TabOpen"
);
menu.menupopup.activateItem(menu.getItemAtIndex(5));
await _teardownRecentlyClosedMenu();
await new Promise(resolve => setTimeout(resolve));
await tabOpenPromise;
await wait_for_message_display_completion(window);
assert_number_of_tabs_open(4);
await assert_selected_and_displayed(msgHdrsInFolder[8]);
// finally restore all tabs
await _synthesizeRecentlyClosedMenu();
Assert.equal(menu.itemCount, 10, "Failed to populate context menu 3");
Assert.equal(
tabTitles[1],
menu.getItemAtIndex(0).label,
"Second tab title does not match menu item"
);
Assert.equal(
tabTitles[7],
menu.getItemAtIndex(5).label,
"Eigth tab title does not match menu item"
);
tabOpenPromise = BrowserTestUtils.waitForEvent(
tabmail.tabContainer,
"TabOpen"
);
menu.menupopup.activateItem(menu.getItemAtIndex(menu.itemCount - 1));
await _teardownRecentlyClosedMenu();
await new Promise(resolve => setTimeout(resolve));
await tabOpenPromise;
await wait_for_message_display_completion(window);
// out of the 16 tab, we closed all except two. As the history can store
// only 10 items we have to endup with exactly 10 + 2 tabs.
assert_number_of_tabs_open(12);
teardownTest();
});
function teardownTest() {
// Some test cases open new windows, thus we need to ensure all
// opened windows get closed.
for (const win of Services.wm.getEnumerator("mail:3pane")) {
if (win != window) {
win.close();
}
}
// clean up the tabbbar
document.getElementById("tabmail").closeOtherTabs(0);
assert_number_of_tabs_open(1);
}