summaryrefslogtreecommitdiffstats
path: root/comm/mail/base/test/browser/browser_searchMessages.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/base/test/browser/browser_searchMessages.js')
-rw-r--r--comm/mail/base/test/browser/browser_searchMessages.js460
1 files changed, 460 insertions, 0 deletions
diff --git a/comm/mail/base/test/browser/browser_searchMessages.js b/comm/mail/base/test/browser/browser_searchMessages.js
new file mode 100644
index 0000000000..4207b0019c
--- /dev/null
+++ b/comm/mail/base/test/browser/browser_searchMessages.js
@@ -0,0 +1,460 @@
+/* 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/. */
+
+const { mailTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/MailTestUtils.jsm"
+);
+const { MessageGenerator } = ChromeUtils.import(
+ "resource://testing-common/mailnews/MessageGenerator.jsm"
+);
+const { PromiseTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/PromiseTestUtils.jsm"
+);
+
+const tabmail = document.getElementById("tabmail");
+let rootFolder, testFolder, otherFolder;
+
+add_setup(async function () {
+ const generator = new MessageGenerator();
+
+ MailServices.accounts.createLocalMailAccount();
+ const account = MailServices.accounts.accounts[0];
+ account.addIdentity(MailServices.accounts.createIdentity());
+ rootFolder = account.incomingServer.rootFolder;
+ rootFolder.QueryInterface(Ci.nsIMsgLocalMailFolder);
+ testFolder = rootFolder.createLocalSubfolder("searchMessagesFolder");
+ testFolder.QueryInterface(Ci.nsIMsgLocalMailFolder);
+ const messageStrings = generator
+ .makeMessages({ count: 20 })
+ .map(message => message.toMboxString());
+ testFolder.addMessageBatch(messageStrings);
+ otherFolder = rootFolder.createLocalSubfolder("searchMessagesOtherFolder");
+
+ tabmail.currentAbout3Pane.paneLayout.messagePaneVisible = true;
+ Services.xulStore.removeDocument(
+ "chrome://messenger/content/SearchDialog.xhtml"
+ );
+
+ registerCleanupFunction(() => {
+ MailServices.accounts.removeAccount(account, false);
+ });
+});
+
+add_task(async function () {
+ const windowOpenedPromise = BrowserTestUtils.domWindowOpenedAndLoaded(
+ null,
+ w =>
+ w.document.documentURI == "chrome://messenger/content/SearchDialog.xhtml"
+ );
+ goDoCommand("cmd_searchMessages");
+ const win = await windowOpenedPromise;
+ const doc = win.document;
+
+ await SimpleTest.promiseFocus(win);
+
+ const searchButton = doc.getElementById("search-button");
+ const clearButton = doc.querySelector(
+ "#searchTerms > vbox > hbox:nth-child(2) > button"
+ );
+ const searchTermList = doc.getElementById("searchTermList");
+ const threadTree = doc.getElementById("threadTree");
+ const columns = threadTree.columns;
+ const picker = threadTree.querySelector("treecolpicker");
+ const popup = picker.querySelector("menupopup");
+ const openButton = doc.getElementById("openButton");
+ const deleteButton = doc.getElementById("deleteButton");
+ const fileMessageButton = doc.getElementById("fileMessageButton");
+ const fileMessagePopup = fileMessageButton.querySelector("menupopup");
+ const openInFolderButton = doc.getElementById("openInFolderButton");
+ const saveAsVFButton = doc.getElementById("saveAsVFButton");
+ const statusText = doc.getElementById("statusText");
+
+ const treeClick = mailTestUtils.treeClick.bind(
+ null,
+ EventUtils,
+ win,
+ threadTree
+ );
+
+ // Test search criteria. The search results are deterministic unless
+ // MessageGenerator is changed.
+
+ await TestUtils.waitForCondition(
+ () => searchTermList.itemCount == 1,
+ "waiting for a search term to exist"
+ );
+ const searchTerm0 = searchTermList.getItemAtIndex(0);
+ const input0 = searchTerm0.querySelector("search-value input");
+ const button0 = searchTerm0.querySelector("button.small-button:first-child");
+
+ // Row 0 will look for subjects including "hovercraft".
+ Assert.equal(input0.value, "");
+ input0.focus();
+ EventUtils.sendString("hovercraft", win);
+
+ // Add another row.
+ EventUtils.synthesizeMouseAtCenter(button0, {}, win);
+ await TestUtils.waitForCondition(
+ () => searchTermList.itemCount == 2,
+ "waiting for a second search term to exist"
+ );
+
+ const searchTerm1 = searchTermList.getItemAtIndex(1);
+ const menulist = searchTerm1.querySelector("search-attribute menulist");
+ const menuitem = menulist.querySelector(`menuitem[value="1"]`);
+ const input1 = searchTerm1.querySelector("search-value input");
+
+ // Change row 1's search attribute.
+ EventUtils.synthesizeMouseAtCenter(menulist, {}, win);
+ await BrowserTestUtils.waitForPopupEvent(menulist, "shown");
+ menulist.menupopup.activateItem(menuitem);
+ await BrowserTestUtils.waitForPopupEvent(menulist, "hidden");
+
+ // Row 1 will look for the sender Emily Ekberg.
+ Assert.equal(input1.value, "");
+ EventUtils.synthesizeMouseAtCenter(input1, {}, win);
+ EventUtils.sendString("emily@ekberg.invalid", win);
+
+ // Search. Emily didn't send a message about hovercraft, so no results.
+ EventUtils.synthesizeMouseAtCenter(searchButton, {}, win);
+ // Allows 5 seconds for expected statusText to appear.
+ await TestUtils.waitForCondition(
+ () => statusText.value == "No matches found",
+ "waiting for status text to update"
+ );
+
+ // Change the search from AND to OR.
+ EventUtils.synthesizeMouseAtCenter(
+ doc.querySelector(`#booleanAndGroup > radio[value="or"]`),
+ {},
+ win
+ );
+ // Change the subject search to something more common.
+ input0.select();
+ EventUtils.sendString("in", win);
+
+ // Search. 10 messages should be found.
+ EventUtils.synthesizeMouseAtCenter(searchButton, {}, win);
+ await TestUtils.waitForCondition(
+ () => threadTree.view.rowCount == 10,
+ "waiting for tree view to be filled"
+ );
+ // statusText changes on 500 ms time base.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, 500));
+ await TestUtils.waitForCondition(
+ () => statusText.value == "10 matches found",
+ "waiting for status text to update"
+ );
+
+ // Test tree sort column and direction.
+
+ EventUtils.synthesizeMouseAtCenter(columns.subjectCol.element, {}, win);
+ Assert.equal(
+ columns.subjectCol.element.getAttribute("sortDirection"),
+ "ascending"
+ );
+ EventUtils.synthesizeMouseAtCenter(columns.dateCol.element, {}, win);
+ Assert.equal(
+ columns.dateCol.element.getAttribute("sortDirection"),
+ "ascending"
+ );
+ EventUtils.synthesizeMouseAtCenter(columns.dateCol.element, {}, win);
+ Assert.equal(
+ columns.dateCol.element.getAttribute("sortDirection"),
+ "descending"
+ );
+
+ // Test tree column visibility and order.
+
+ checkTreeColumnsInOrder(threadTree, [
+ "flaggedCol",
+ "attachmentCol",
+ "subjectCol",
+ "unreadButtonColHeader",
+ "correspondentCol",
+ "junkStatusCol",
+ "dateCol",
+ "locationCol",
+ ]);
+ EventUtils.synthesizeMouseAtCenter(picker, {}, win);
+ await BrowserTestUtils.waitForPopupEvent(popup, "shown");
+ popup.activateItem(
+ popup.querySelector(`[colindex="${columns.selectCol.index}"]`)
+ );
+ popup.activateItem(
+ popup.querySelector(`[colindex="${columns.deleteCol.index}"]`)
+ );
+ popup.hidePopup();
+ await BrowserTestUtils.waitForPopupEvent(popup, "hidden");
+ // Wait for macOS to catch up.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, 500));
+ checkTreeColumnsInOrder(threadTree, [
+ "selectCol",
+ "flaggedCol",
+ "attachmentCol",
+ "subjectCol",
+ "unreadButtonColHeader",
+ "correspondentCol",
+ "junkStatusCol",
+ "dateCol",
+ "locationCol",
+ "deleteCol",
+ ]);
+
+ threadTree._reorderColumn(
+ columns.deleteCol.element,
+ columns.selectCol.element,
+ false
+ );
+ threadTree.invalidate();
+ // Wait for macOS to catch up.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, 500));
+ checkTreeColumnsInOrder(threadTree, [
+ "selectCol",
+ "deleteCol",
+ "flaggedCol",
+ "attachmentCol",
+ "subjectCol",
+ "unreadButtonColHeader",
+ "correspondentCol",
+ "junkStatusCol",
+ "dateCol",
+ "locationCol",
+ ]);
+
+ // Test message selection with the select column.
+
+ treeClick(0, "subjectCol", {});
+ await TestUtils.waitForCondition(
+ () => threadTree.view.selection.count == 1,
+ "waiting for first message to be selected"
+ );
+ Assert.ok(!openButton.disabled);
+ Assert.ok(!deleteButton.disabled);
+ Assert.ok(!fileMessageButton.disabled);
+ Assert.ok(!openInFolderButton.disabled);
+ treeClick(1, "selectCol", {});
+ await TestUtils.waitForCondition(
+ () => threadTree.view.selection.count == 2,
+ "waiting for second message to be selected"
+ );
+ Assert.ok(!openButton.disabled);
+ Assert.ok(!deleteButton.disabled);
+ Assert.ok(!fileMessageButton.disabled);
+ Assert.ok(openInFolderButton.disabled);
+ treeClick(1, "selectCol", {});
+ await TestUtils.waitForCondition(
+ () => threadTree.view.selection.count == 1,
+ "waiting for second message to be unselected"
+ );
+ Assert.ok(!openButton.disabled);
+ Assert.ok(!deleteButton.disabled);
+ Assert.ok(!fileMessageButton.disabled);
+ Assert.ok(!openInFolderButton.disabled);
+ treeClick(0, "selectCol", {});
+ await TestUtils.waitForCondition(
+ () => threadTree.view.selection.count == 0,
+ "waiting for first message to be selected"
+ );
+ Assert.ok(openButton.disabled);
+ Assert.ok(deleteButton.disabled);
+ Assert.ok(fileMessageButton.disabled);
+ Assert.ok(openInFolderButton.disabled);
+
+ // Opening messages.
+
+ // Test opening a message with the "Open" button.
+ treeClick(0, "subjectCol", {});
+ let tabOpenPromise = BrowserTestUtils.waitForEvent(window, "TabOpen");
+ EventUtils.synthesizeMouseAtCenter(openButton, {}, win);
+ const {
+ detail: { tabInfo: tab1 },
+ } = await tabOpenPromise;
+ await BrowserTestUtils.waitForEvent(tab1.chromeBrowser, "MsgLoaded");
+ Assert.equal(tab1.mode.name, "mailMessageTab");
+
+ await SimpleTest.promiseFocus(win);
+
+ // Test opening a message with a double click.
+ tabOpenPromise = BrowserTestUtils.waitForEvent(window, "TabOpen");
+ treeClick(0, "subjectCol", { clickCount: 2 });
+ const {
+ detail: { tabInfo: tab2 },
+ } = await tabOpenPromise;
+ await BrowserTestUtils.waitForEvent(tab2.chromeBrowser, "MsgLoaded");
+ Assert.equal(tab2.mode.name, "mailMessageTab");
+
+ await SimpleTest.promiseFocus(win);
+
+ // Test opening a message with the keyboard.
+ tabOpenPromise = BrowserTestUtils.waitForEvent(window, "TabOpen");
+ threadTree.focus();
+ EventUtils.synthesizeKey("VK_RETURN", {}, win);
+ const {
+ detail: { tabInfo: tab3 },
+ } = await tabOpenPromise;
+ await BrowserTestUtils.waitForEvent(tab3.chromeBrowser, "MsgLoaded");
+ Assert.equal(tab3.mode.name, "mailMessageTab");
+
+ await SimpleTest.promiseFocus(win);
+
+ // Test opening a message with the "Open in Folder" button.
+ const tabSelectPromise = BrowserTestUtils.waitForEvent(window, "TabSelect");
+ EventUtils.synthesizeMouseAtCenter(openInFolderButton, {}, win);
+ const {
+ detail: { tabInfo: tab0 },
+ } = await tabSelectPromise;
+ await BrowserTestUtils.waitForEvent(tab0.chromeBrowser, "MsgLoaded");
+ Assert.equal(tab0, tabmail.tabInfo[0]);
+
+ tabmail.closeOtherTabs(tab0);
+
+ await SimpleTest.promiseFocus(win);
+
+ // Deleting messages.
+
+ // Test deleting a message with the delete column.
+ let deletePromise = PromiseTestUtils.promiseFolderEvent(
+ testFolder,
+ "DeleteOrMoveMsgCompleted"
+ );
+ treeClick(0, "deleteCol", {});
+ await deletePromise;
+ await TestUtils.waitForCondition(
+ () => threadTree.view.rowCount == 9,
+ "waiting for row to be removed from tree view"
+ );
+
+ // Test deleting a message with the "Delete" button.
+ deletePromise = PromiseTestUtils.promiseFolderEvent(
+ testFolder,
+ "DeleteOrMoveMsgCompleted"
+ );
+ EventUtils.synthesizeMouseAtCenter(deleteButton, {}, win);
+ await deletePromise;
+ await TestUtils.waitForCondition(
+ () => threadTree.view.rowCount == 8,
+ "waiting for row to be removed from tree view"
+ );
+
+ // Test deleting a message with the keyboard.
+ treeClick(0, "subjectCol", {});
+ deletePromise = PromiseTestUtils.promiseFolderEvent(
+ testFolder,
+ "DeleteOrMoveMsgCompleted"
+ );
+ EventUtils.synthesizeKey("VK_DELETE", { shiftKey: true }, win);
+ await deletePromise;
+ await TestUtils.waitForCondition(
+ () => threadTree.view.rowCount == 7,
+ "waiting for row to be removed from tree view"
+ );
+
+ // Moving messages.
+
+ // Test moving a message to another folder with the "Move To" button.
+ treeClick(0, "subjectCol", {});
+ const movePromise = PromiseTestUtils.promiseFolderEvent(
+ testFolder,
+ "DeleteOrMoveMsgCompleted"
+ );
+
+ EventUtils.synthesizeMouseAtCenter(fileMessageButton, {}, win);
+ await BrowserTestUtils.waitForPopupEvent(fileMessagePopup, "shown");
+ const rootFolderMenu = [...fileMessagePopup.children].find(
+ i => i._folder == rootFolder
+ );
+ rootFolderMenu.openMenu(true);
+ await BrowserTestUtils.waitForPopupEvent(rootFolderMenu.menupopup, "shown");
+ const otherFolderItem = [...rootFolderMenu.menupopup.children].find(
+ i => i._folder == otherFolder
+ );
+ rootFolderMenu.menupopup.activateItem(otherFolderItem);
+ await BrowserTestUtils.waitForPopupEvent(fileMessagePopup, "hidden");
+
+ await movePromise;
+ await TestUtils.waitForCondition(
+ () => threadTree.view.rowCount == 6,
+ "waiting for row to be removed from tree view"
+ );
+
+ // TODO: Test dragging a message to another folder.
+
+ // Test the "Save as Search Folder" button.
+
+ const virtualFolderDialogPromise = BrowserTestUtils.promiseAlertDialogOpen(
+ undefined,
+ "chrome://messenger/content/virtualFolderProperties.xhtml",
+ {
+ async callback(vfWin) {
+ await SimpleTest.promiseFocus(vfWin);
+ await BrowserTestUtils.closeWindow(vfWin);
+ },
+ }
+ );
+ EventUtils.synthesizeMouseAtCenter(saveAsVFButton, {}, win);
+ await virtualFolderDialogPromise;
+
+ await SimpleTest.promiseFocus(win);
+
+ // Test clearing the search.
+
+ EventUtils.synthesizeMouseAtCenter(clearButton, {}, win);
+ await TestUtils.waitForCondition(
+ () => searchTermList.itemCount == 1,
+ "waiting for search term list to be cleared"
+ );
+ await TestUtils.waitForCondition(
+ () => threadTree.view.rowCount == 0,
+ "waiting for tree view to be cleared"
+ );
+
+ const newSearchTerm0 = searchTermList.getItemAtIndex(0);
+ Assert.notEqual(newSearchTerm0, searchTerm0);
+ const newInput0 = newSearchTerm0.querySelector("search-value input");
+ Assert.equal(newInput0.value, "");
+
+ await BrowserTestUtils.closeWindow(win);
+
+ // Open the window again, and check the tree columns are as we left them.
+
+ const window2OpenedPromise = BrowserTestUtils.domWindowOpenedAndLoaded(
+ null,
+ w =>
+ w.document.documentURI == "chrome://messenger/content/SearchDialog.xhtml"
+ );
+ goDoCommand("cmd_searchMessages");
+ const win2 = await window2OpenedPromise;
+ const doc2 = win.document;
+ await SimpleTest.promiseFocus(win2);
+
+ const threadTree2 = doc2.getElementById("threadTree");
+
+ checkTreeColumnsInOrder(threadTree2, [
+ "selectCol",
+ "deleteCol",
+ "flaggedCol",
+ "attachmentCol",
+ "subjectCol",
+ "unreadButtonColHeader",
+ "correspondentCol",
+ "junkStatusCol",
+ "dateCol",
+ "locationCol",
+ ]);
+
+ await BrowserTestUtils.closeWindow(win2);
+});
+
+function checkTreeColumnsInOrder(tree, expectedOrder) {
+ Assert.deepEqual(
+ Array.from(tree.querySelectorAll("treecol:not([hidden])"))
+ .sort((a, b) => a.ordinal - b.ordinal)
+ .map(c => c.id),
+ expectedOrder
+ );
+}