From cd85f7928bc1f573f101ed35a204aca555a4cd91 Mon Sep 17 00:00:00 2001 From: Geoff Lankow Date: Mon, 4 Dec 2023 12:12:50 +0200 Subject: [PATCH] Bug 1851536 - Test items on the mail context menu, part 2. r=aleca This tests items on the menu that open a compose window. Differential Revision: https://phabricator.services.mozilla.com/D195066 --HG-- extra : amend_source : d55de3f430a8bb9b2d36f7d10b190f0034de67be --- mail/base/test/NNTPServer.sys.mjs | 7 +- mail/base/test/browser/browser.ini | 2 + .../browser/browser_mailContext_compose.js | 407 ++++++++++++++++++ 3 files changed, 415 insertions(+), 1 deletion(-) create mode 100644 mail/base/test/browser/browser_mailContext_compose.js diff --git a/mail/base/test/NNTPServer.sys.mjs b/mail/base/test/NNTPServer.sys.mjs index 47f4e868b0..15f5abcc17 100644 --- a/mail/base/test/NNTPServer.sys.mjs +++ b/mail/base/test/NNTPServer.sys.mjs @@ -50,7 +50,12 @@ export class NNTPServer { */ addMessages(group, messages) { messages.forEach(message => { - const article = new NewsArticle(message.toMessageString()); + message = message.toMessageString(); + // The NNTP daemon needs a trailing empty line. + if (!message.endsWith("\r\n")) { + message += "\r\n"; + } + const article = new NewsArticle(message); article.groups = [group]; this.daemon.addArticle(article); }); diff --git a/mail/base/test/browser/browser.ini b/mail/base/test/browser/browser.ini index 9b2e7cdde0..34d2924f59 100644 --- a/mail/base/test/browser/browser.ini +++ b/mail/base/test/browser/browser.ini @@ -36,6 +36,8 @@ skip-if = os == 'mac' [browser_linkHandler.js] [browser_mailContext.js] tags = contextmenu +[browser_mailContext_compose.js] +tags = contextmenu [browser_mailContext_messageContent.js] skip-if = headless tags = contextmenu diff --git a/mail/base/test/browser/browser_mailContext_compose.js b/mail/base/test/browser/browser_mailContext_compose.js new file mode 100644 index 0000000000..cb31539fd6 --- /dev/null +++ b/mail/base/test/browser/browser_mailContext_compose.js @@ -0,0 +1,407 @@ +/* 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 that composition items on the mail context menu work. + */ + +requestLongerTimeout(2); + +const { MessageGenerator } = ChromeUtils.import( + "resource://testing-common/mailnews/MessageGenerator.jsm" +); +const { NNTPServer } = ChromeUtils.importESModule( + "resource://testing-common/NNTPServer.sys.mjs" +); +const { PromiseTestUtils } = ChromeUtils.import( + "resource://testing-common/mailnews/PromiseTestUtils.jsm" +); + +const tabmail = document.getElementById("tabmail"); +const about3Pane = tabmail.currentAbout3Pane; +const { displayFolder, messageBrowser, threadTree } = about3Pane; + +let testMessages, draftMessage, templateMessage, nntpMessage; + +add_setup(async function () { + const generator = new MessageGenerator(); + + MailServices.accounts.createLocalMailAccount(); + const account = MailServices.accounts.accounts[0]; + account.addIdentity(MailServices.accounts.createIdentity()); + const rootFolder = account.incomingServer.rootFolder.QueryInterface( + Ci.nsIMsgLocalMailFolder + ); + + const testFolder = rootFolder + .createLocalSubfolder("mailContext compose") + .QueryInterface(Ci.nsIMsgLocalMailFolder); + testFolder.addMessageBatch( + generator + .makeMessages({ count: 5, msgsPerThread: 5 }) + .map(message => message.toMessageString()) + ); + testFolder.addMessage( + generator + .makeMessage({ + clobberHeaders: { "List-Post": "" }, + }) + .toMessageString() + ); + testMessages = [...testFolder.messages]; + + const draftsFolder = rootFolder + .createLocalSubfolder("mailContext composeDrafts") + .QueryInterface(Ci.nsIMsgLocalMailFolder); + draftsFolder.setFlag(Ci.nsMsgFolderFlags.Drafts); + draftsFolder.addMessage(generator.makeMessage().toMessageString()); + draftMessage = draftsFolder.messages.getNext(); + + const templatesFolder = rootFolder + .createLocalSubfolder("mailContext composeTemplates") + .QueryInterface(Ci.nsIMsgLocalMailFolder); + templatesFolder.setFlag(Ci.nsMsgFolderFlags.Templates); + templatesFolder.addMessage(generator.makeMessage().toMessageString()); + templateMessage = templatesFolder.messages.getNext(); + + const nntpServer = new NNTPServer(this); + nntpServer.addGroup("mailContext.compose"); + nntpServer.addMessages("mailContext.compose", [generator.makeMessage()]); + const nntpAccount = MailServices.accounts.createAccount(); + nntpAccount.incomingServer = MailServices.accounts.createIncomingServer( + `${nntpAccount.key}user`, + "localhost", + "nntp" + ); + nntpAccount.incomingServer.port = nntpServer.port; + const nntpRootFolder = nntpAccount.incomingServer.rootFolder; + nntpRootFolder.createSubfolder("mailContext.compose", null); + const nntpFolder = nntpRootFolder.getChildNamed("mailContext.compose"); + const urlListener = new PromiseTestUtils.PromiseUrlListener(); + nntpAccount.incomingServer.getNewMessages( + nntpFolder, + window.msgWindow, + urlListener + ); + await urlListener.promise; + nntpMessage = nntpFolder.messages.getNext(); + + tabmail.currentAbout3Pane.restoreState({ + folderURI: testFolder.URI, + messagePaneVisible: true, + }); + + registerCleanupFunction(() => { + MailServices.accounts.removeAccount(account, false); + MailServices.accounts.removeAccount(nntpAccount, false); + Services.prefs.clearUserPref("mail.tabs.loadInBackground"); + Services.prefs.clearUserPref("mail.forward_message_mode"); + }); +}); + +/** + * Tests the mailContext menu on the thread tree. + */ +add_task(async function testThreadPane() { + const mailContext = about3Pane.document.getElementById("mailContext"); + + async function openMenu() { + console.log(threadTree.currentIndex); + EventUtils.synthesizeMouseAtCenter( + threadTree.getRowAtIndex(threadTree.currentIndex), + { type: "contextmenu" }, + about3Pane + ); + await BrowserTestUtils.waitForPopupEvent(mailContext, "shown"); + return mailContext; + } + + await subtestSingleMessage({ + async openMessage(message) { + displayFolder(message.folder); + threadTree.selectedIndex = about3Pane.gDBView.findIndexOfMsgHdr( + message, + true + ); + await messageLoadedIn(messageBrowser); + }, + openMenu, + closeMessage() {}, + }); + + displayFolder(testMessages[0].folder); + goDoCommand("cmd_expandAllThreads"); + threadTree.selectedIndices = [0, 5]; + await promiseComposeWindow( + openMenu, + "mailContext-multiForwardAsAttachment", + Ci.nsIMsgCompType.ForwardAsAttachment, + { + attachments: [testMessages[0].subject, testMessages[5].subject], + } + ); +}); + +/** + * Tests the mailContext menu on the message pane. + */ +add_task(async function testMessagePane() { + const aboutMessage = messageBrowser.contentWindow; + const mailContext = about3Pane.document.getElementById("mailContext"); + + await subtestSingleMessage({ + async openMessage(message) { + displayFolder(message.folder); + threadTree.selectedIndex = about3Pane.gDBView.findIndexOfMsgHdr( + message, + true + ); + await messageLoadedIn(messageBrowser); + }, + async openMenu() { + BrowserTestUtils.synthesizeMouseAtCenter( + "body", + { type: "contextmenu" }, + aboutMessage.getMessagePaneBrowser() + ); + await BrowserTestUtils.waitForPopupEvent(mailContext, "shown"); + return mailContext; + }, + closeMessage() {}, + }); +}); + +/** + * Tests the mailContext menu on the message pane of a message in a tab. + */ +add_task(async function testMessageTab() { + await subtestSingleMessage({ + async openMessage(message) { + const tabPromise = BrowserTestUtils.waitForEvent( + tabmail.tabContainer, + "TabOpen" + ); + window.OpenMessageInNewTab(message, { background: false }); + const { + detail: { tabInfo }, + } = await tabPromise; + await messageLoadedIn(tabInfo.chromeBrowser); + + this.tabInfo = tabInfo; + }, + async openMenu() { + const aboutMessage = tabmail.currentAboutMessage; + const mailContext = aboutMessage.document.getElementById("mailContext"); + + BrowserTestUtils.synthesizeMouseAtCenter( + "body", + { type: "contextmenu" }, + aboutMessage.getMessagePaneBrowser() + ); + await BrowserTestUtils.waitForPopupEvent(mailContext, "shown"); + return mailContext; + }, + closeMessage() { + tabmail.closeTab(this.tabInfo); + }, + }); +}); + +/** + * Tests the mailContext menu on the message pane of a message in a window. + */ +add_task(async function testMessageWindow() { + await subtestSingleMessage({ + async openMessage(message) { + const winPromise = BrowserTestUtils.domWindowOpenedAndLoaded(); + window.MsgOpenNewWindowForMessage(message); + const win = await winPromise; + await messageLoadedIn(win.messageBrowser); + await SimpleTest.promiseFocus(win); + + this.win = win; + }, + async openMenu() { + const aboutMessage = this.win.messageBrowser.contentWindow; + const mailContext = aboutMessage.document.getElementById("mailContext"); + + await SimpleTest.promiseFocus(this.win); + BrowserTestUtils.synthesizeMouseAtCenter( + "body", + { type: "contextmenu" }, + aboutMessage.getMessagePaneBrowser() + ); + await BrowserTestUtils.waitForPopupEvent(mailContext, "shown"); + return mailContext; + }, + async closeMessage() { + await BrowserTestUtils.closeWindow(this.win); + }, + }); +}); + +async function promiseComposeWindow( + openMenuCallback, + itemId, + expectedType, + { to = [], replyTo = [], attachments = [] } = {} +) { + const composeWindowPromise = BrowserTestUtils.domWindowOpenedAndLoaded( + null, + win => + win.document.documentURI === + "chrome://messenger/content/messengercompose/messengercompose.xhtml" + ); + const mailContext = await openMenuCallback(); + const item = mailContext.querySelector("#" + itemId); + if (item.parentNode != mailContext) { + item.closest("menu").openMenu(true); + await BrowserTestUtils.waitForPopupEvent( + item.closest("menupopup"), + "shown" + ); + } + mailContext.activateItem(item); + await BrowserTestUtils.waitForPopupEvent(mailContext, "hidden"); + + const composeWindow = await composeWindowPromise; + await SimpleTest.promiseFocus(composeWindow); + await TestUtils.waitForCondition(() => composeWindow.gLoadingComplete); + + Assert.equal(composeWindow.gComposeType, expectedType); + + const toPills = composeWindow.document.querySelectorAll( + "#toAddrContainer > mail-address-pill" + ); + Assert.equal(toPills.length, to.length); + for (let i = 0; i < to.length; i++) { + Assert.equal( + toPills[i].label, + MailServices.headerParser.parseEncodedHeader(to[i])[0].toString() + ); + } + const replyToPills = composeWindow.document.querySelectorAll( + "#replyAddrContainer > mail-address-pill" + ); + Assert.equal(replyToPills.length, replyTo.length); + for (let i = 0; i < replyTo.length; i++) { + Assert.equal( + replyToPills[i].label, + MailServices.headerParser.parseEncodedHeader(replyTo[i])[0].toString() + ); + } + + Assert.equal(composeWindow.gAttachmentBucket.itemCount, attachments.length); + for (let i = 0; i < attachments.length; i++) { + Assert.equal( + composeWindow.gAttachmentBucket.getItemAtIndex(i).getAttribute("name"), + attachments[i] + ".eml" + ); + } + + await BrowserTestUtils.closeWindow(composeWindow); + await SimpleTest.promiseFocus(composeWindow.opener); +} + +async function subtestSingleMessage(callbacks) { + const openMessage = callbacks.openMessage.bind(callbacks); + const openMenu = callbacks.openMenu.bind(callbacks); + const closeMessage = callbacks.closeMessage.bind(callbacks); + + await openMessage(testMessages[0]); + await promiseComposeWindow( + openMenu, + "mailContext-replySender", + Ci.nsIMsgCompType.ReplyToSender, + { to: [testMessages[0].author] } + ); + await promiseComposeWindow( + openMenu, + "mailContext-replyAll", + Ci.nsIMsgCompType.ReplyAll, + { to: [testMessages[0].author, testMessages[0].recipients] } + ); + + Services.prefs.setIntPref("mail.forward_message_mode", 0); + await promiseComposeWindow( + openMenu, + "mailContext-forward", + Ci.nsIMsgCompType.ForwardAsAttachment, + { attachments: [testMessages[0].subject] } + ); + await promiseComposeWindow( + openMenu, + "mailContext-forwardAsInline", + Ci.nsIMsgCompType.ForwardInline + ); + + Services.prefs.setIntPref("mail.forward_message_mode", 1); + await promiseComposeWindow( + openMenu, + "mailContext-forward", + Ci.nsIMsgCompType.ForwardInline + ); + await promiseComposeWindow( + openMenu, + "mailContext-forwardAsAttachment", + Ci.nsIMsgCompType.ForwardAsAttachment, + { attachments: [testMessages[0].subject] } + ); + + await promiseComposeWindow( + openMenu, + "mailContext-redirect", + Ci.nsIMsgCompType.Redirect, + { replyTo: [testMessages[0].author] } + ); + + await promiseComposeWindow( + openMenu, + "mailContext-editAsNew", + Ci.nsIMsgCompType.EditAsNew, + { to: [testMessages[0].recipients] } + ); + await closeMessage(); + + await openMessage(testMessages[5]); + await promiseComposeWindow( + openMenu, + "mailContext-replyList", + Ci.nsIMsgCompType.ReplyToList, + { to: ["list@example.com"] } + ); + await closeMessage(); + + await openMessage(draftMessage); + await promiseComposeWindow( + openMenu, + "mailContext-editDraftMsg", + Ci.nsIMsgCompType.Draft, + { to: [draftMessage.recipients] } + ); + await closeMessage(); + + await openMessage(templateMessage); + await promiseComposeWindow( + openMenu, + "mailContext-newMsgFromTemplate", + Ci.nsIMsgCompType.Template, + { to: [templateMessage.recipients] } + ); + await promiseComposeWindow( + openMenu, + "mailContext-editTemplateMsg", + Ci.nsIMsgCompType.EditTemplate, + { to: [templateMessage.recipients] } + ); + await closeMessage(); + + await openMessage(nntpMessage); + await promiseComposeWindow( + openMenu, + "mailContext-replyNewsgroup", + Ci.nsIMsgCompType.ReplyToGroup + ); + await closeMessage(); +}