summaryrefslogtreecommitdiffstats
path: root/comm/mail/test/browser/composition/browser_sendFormat.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/test/browser/composition/browser_sendFormat.js')
-rw-r--r--comm/mail/test/browser/composition/browser_sendFormat.js565
1 files changed, 565 insertions, 0 deletions
diff --git a/comm/mail/test/browser/composition/browser_sendFormat.js b/comm/mail/test/browser/composition/browser_sendFormat.js
new file mode 100644
index 0000000000..8877b4d8a5
--- /dev/null
+++ b/comm/mail/test/browser/composition/browser_sendFormat.js
@@ -0,0 +1,565 @@
+/* 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 resulting send format of a message dependent on using HTML features
+ * in the composition.
+ */
+
+"use strict";
+
+requestLongerTimeout(4);
+
+var {
+ open_compose_from_draft,
+ open_compose_new_mail,
+ open_compose_with_reply,
+ FormatHelper,
+} = ChromeUtils.import("resource://testing-common/mozmill/ComposeHelpers.jsm");
+
+var {
+ be_in_folder,
+ empty_folder,
+ get_special_folder,
+ get_about_message,
+ open_message_from_file,
+ select_click_row,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+
+var sendFormatPreference;
+var htmlAsPreference;
+var draftsFolder;
+var outboxFolder;
+
+add_setup(async () => {
+ sendFormatPreference = Services.prefs.getIntPref("mail.default_send_format");
+ htmlAsPreference = Services.prefs.getIntPref("mailnews.display.html_as");
+ // Show all parts to a message in the message display.
+ // This allows us to see if a message contains both a plain text and a HTML
+ // part.
+ Services.prefs.setIntPref("mailnews.display.html_as", 4);
+ draftsFolder = await get_special_folder(Ci.nsMsgFolderFlags.Drafts, true);
+ outboxFolder = await get_special_folder(Ci.nsMsgFolderFlags.Queue, true);
+});
+
+registerCleanupFunction(async function () {
+ Services.prefs.setIntPref("mail.default_send_format", sendFormatPreference);
+ Services.prefs.setIntPref("mailnews.display.html_as", htmlAsPreference);
+ await empty_folder(draftsFolder);
+ await empty_folder(outboxFolder);
+});
+
+async function checkMsgFile(aFilePath, aConvertibility) {
+ let file = new FileUtils.File(getTestFilePath(`data/${aFilePath}`));
+ let messageController = await open_message_from_file(file);
+
+ // Creating a reply should not affect convertibility.
+ let composeWindow = open_compose_with_reply(messageController).window;
+
+ Assert.equal(composeWindow.gMsgCompose.bodyConvertible(), aConvertibility);
+
+ await BrowserTestUtils.closeWindow(composeWindow);
+ await BrowserTestUtils.closeWindow(messageController.window);
+}
+
+/**
+ * Tests nodeTreeConvertible() can be called from JavaScript.
+ */
+add_task(async function test_msg_nodeTreeConvertible() {
+ let msgCompose = Cc["@mozilla.org/messengercompose/compose;1"].createInstance(
+ Ci.nsIMsgCompose
+ );
+
+ let textDoc = new DOMParser().parseFromString(
+ "<p>Simple Text</p>",
+ "text/html"
+ );
+ Assert.equal(
+ msgCompose.nodeTreeConvertible(textDoc.documentElement),
+ Ci.nsIMsgCompConvertible.Plain
+ );
+
+ let htmlDoc = new DOMParser().parseFromString(
+ '<p>Complex <span style="font-weight: bold">Text</span></p>',
+ "text/html"
+ );
+ Assert.equal(
+ msgCompose.nodeTreeConvertible(htmlDoc.documentElement),
+ Ci.nsIMsgCompConvertible.No
+ );
+});
+
+/**
+ * Tests that we only open one compose window for one instance of a draft.
+ */
+add_task(async function test_msg_convertibility() {
+ await checkMsgFile("./format1-plain.eml", Ci.nsIMsgCompConvertible.Plain);
+
+ // Bug 1385636
+ await checkMsgFile(
+ "./format1-altering.eml",
+ Ci.nsIMsgCompConvertible.Altering
+ );
+
+ // Bug 584313
+ await checkMsgFile("./format2-style-attr.eml", Ci.nsIMsgCompConvertible.No);
+ await checkMsgFile("./format3-style-tag.eml", Ci.nsIMsgCompConvertible.No);
+});
+
+/**
+ * Map from a nsIMsgCompSendFormat to the id of the corresponding menuitem in
+ * the Options, Send Format menu.
+ *
+ * @type {Map<nsIMsgCompSendFormat, string>}
+ */
+var sendFormatToMenuitem = new Map([
+ [Ci.nsIMsgCompSendFormat.PlainText, "format_plain"],
+ [Ci.nsIMsgCompSendFormat.HTML, "format_html"],
+ [Ci.nsIMsgCompSendFormat.Both, "format_both"],
+ [Ci.nsIMsgCompSendFormat.Auto, "format_auto"],
+]);
+
+/**
+ * Verify that the correct send format menu item is checked.
+ *
+ * @param {Window} composeWindow - The compose window.
+ * @param {nsIMsgCompSendFormat} expectFormat - The expected checked format
+ * option. Either Auto, PlainText, HTML, or Both.
+ * @param {string} msg - A message to use in assertions.
+ */
+function assertSendFormatInMenu(composeWindow, expectFormat, msg) {
+ for (let [format, menuitemId] of sendFormatToMenuitem.entries()) {
+ let menuitem = composeWindow.document.getElementById(menuitemId);
+ let checked = expectFormat == format;
+ Assert.equal(
+ menuitem.getAttribute("checked") == "true",
+ checked,
+ `${menuitemId} should ${checked ? "not " : ""}be checked: ${msg}`
+ );
+ }
+}
+
+const PLAIN_MESSAGE_BODY = "Plain message body";
+const BOLD_MESSAGE_BODY = "Bold message body";
+const BOLD_MESSAGE_BODY_AS_PLAIN = `*${BOLD_MESSAGE_BODY}*`;
+
+/**
+ * Set the default send format and create a new message in the compose window.
+ *
+ * @param {nsIMsgCompSendFormat} preference - The default send format to set via
+ * a preference before opening the window.
+ * @param {boolean} useBold - Whether to use bold text in the message's body.
+ *
+ * @returns {Window} - The opened compose window, pre-filled with a message.
+ */
+async function newMessage(preference, useBold) {
+ Services.prefs.setIntPref("mail.default_send_format", preference);
+
+ let composeWindow = open_compose_new_mail().window;
+ assertSendFormatInMenu(
+ composeWindow,
+ preference,
+ "Send format should initially match preference"
+ );
+
+ // Focus should be on "To" field.
+ EventUtils.sendString("recipient@server.net", composeWindow);
+ await TestUtils.waitForTick();
+ EventUtils.synthesizeKey("KEY_Enter", {}, composeWindow);
+ await TestUtils.waitForTick();
+ EventUtils.synthesizeKey("KEY_Enter", {}, composeWindow);
+ await TestUtils.waitForTick();
+ // Focus should be in the "Subject" field.
+ EventUtils.sendString(
+ `${useBold ? "rich" : "plain"} message with preference ${preference}`,
+ composeWindow
+ );
+ await TestUtils.waitForTick();
+ EventUtils.synthesizeKey("KEY_Enter", {}, composeWindow);
+ await TestUtils.waitForTick();
+
+ // Focus should be in the body.
+ let formatHelper = new FormatHelper(composeWindow);
+ if (useBold) {
+ EventUtils.synthesizeMouseAtCenter(
+ formatHelper.boldButton,
+ {},
+ composeWindow
+ );
+ await TestUtils.waitForTick();
+ await formatHelper.typeInMessage(BOLD_MESSAGE_BODY);
+ } else {
+ await formatHelper.typeInMessage(PLAIN_MESSAGE_BODY);
+ }
+
+ return composeWindow;
+}
+
+/**
+ * Set the send format to something else via the application menu.
+ *
+ * @param {Window} composeWindow - The compose window to set the format in.
+ * @param {nsIMsgCompSendFormat} sendFormat - The send format to set. Either
+ * Auto, PlainText, HTML, or Both.
+ */
+async function setSendFormat(composeWindow, sendFormat) {
+ async function openMenu(menu) {
+ let openPromise = BrowserTestUtils.waitForEvent(menu, "popupshown");
+ menu.openMenu(true);
+ await openPromise;
+ }
+ let optionsMenu = composeWindow.document.getElementById("optionsMenu");
+ let sendFormatMenu =
+ composeWindow.document.getElementById("outputFormatMenu");
+ let menuitem = composeWindow.document.getElementById(
+ sendFormatToMenuitem.get(sendFormat)
+ );
+
+ await openMenu(optionsMenu);
+ await openMenu(sendFormatMenu);
+
+ let closePromise = BrowserTestUtils.waitForEvent(optionsMenu, "popuphidden");
+ sendFormatMenu.menupopup.activateItem(menuitem);
+ await closePromise;
+ assertSendFormatInMenu(
+ composeWindow,
+ sendFormat,
+ "Send format should change to the selected format"
+ );
+}
+
+/**
+ * Verify the actual sent message of a composed message.
+ *
+ * @param {Window} composeWindow - The compose window that contains the message
+ * we want to send.
+ * @param {object} expectMessage - The expected sent message.
+ * @param {boolean} expectMessage.isBold - Whether the message uses a bold
+ * message, rather than the plain message.
+ * @param {boolean} expectMessage.plain - Whether the message has a plain part.
+ * @param {boolean} expectMessage.html - Whether the message has a html part.
+ * @param {string} msg - A message to use in assertions.
+ */
+async function assertSentMessage(composeWindow, expectMessage, msg) {
+ let { isBold, plain, html } = expectMessage;
+
+ // Send later.
+ let closePromise = BrowserTestUtils.windowClosed(composeWindow);
+ EventUtils.synthesizeKey(
+ "KEY_Enter",
+ { accelKey: true, shiftKey: true },
+ composeWindow
+ );
+ await closePromise;
+
+ // Open the "sent" message.
+ await be_in_folder(outboxFolder);
+ // Should be the last message in the tree.
+ select_click_row(-1);
+
+ // Test that the sent content type is either text/plain, text/html or
+ // multipart/alternative.
+ // TODO: Is there a better way to expose the content-type of the displayed
+ // message?
+ let contentType =
+ get_about_message().currentHeaderData["content-type"].headerValue;
+ if (plain && html) {
+ Assert.ok(
+ contentType.startsWith("multipart/alternative"),
+ `Sent contentType "${contentType}" should be multipart: ${msg}`
+ );
+ } else if (plain) {
+ Assert.ok(
+ contentType.startsWith("text/plain"),
+ `Sent contentType "${contentType}" should be plain text only: ${msg}`
+ );
+ } else if (html) {
+ Assert.ok(
+ contentType.startsWith("text/html"),
+ `Sent contentType "${contentType}" should be html only: ${msg}`
+ );
+ } else {
+ throw new Error("Expected message is missing either plain or html parts");
+ }
+
+ // Assert the html and plain text parts are either hidden or shown.
+ // NOTE: We have set the mailnews.display.html_as preference to show all parts
+ // of the message, which means it will show both the plain text and html parts
+ // if both were sent.
+ let messageBody =
+ get_about_message().document.getElementById("messagepane").contentDocument
+ .body;
+ let plainBody = messageBody.querySelector(".moz-text-flowed");
+ let htmlBody = messageBody.querySelector(".moz-text-html");
+ Assert.equal(
+ !!plain,
+ !!plainBody,
+ `Message should ${plain ? "" : "not "}have a Plain part: ${msg}`
+ );
+ Assert.equal(
+ !!html,
+ !!htmlBody,
+ `Message should ${html ? "" : "not "}have a HTML part: ${msg}`
+ );
+
+ if (plain) {
+ Assert.ok(
+ BrowserTestUtils.is_visible(plainBody),
+ `Plain part should be visible: ${msg}`
+ );
+ Assert.equal(
+ plainBody.textContent.trim(),
+ isBold ? BOLD_MESSAGE_BODY_AS_PLAIN : PLAIN_MESSAGE_BODY,
+ `Plain text content should match: ${msg}`
+ );
+ }
+
+ if (html) {
+ Assert.ok(
+ BrowserTestUtils.is_visible(htmlBody),
+ `HTML part should be visible: ${msg}`
+ );
+ Assert.equal(
+ htmlBody.textContent.trim(),
+ isBold ? BOLD_MESSAGE_BODY : PLAIN_MESSAGE_BODY,
+ `HTML text content should match: ${msg}`
+ );
+ }
+}
+
+async function saveDraft(composeWindow) {
+ let oldDraftsCounts = draftsFolder.getTotalMessages(false);
+ // Save as draft.
+ EventUtils.synthesizeKey("s", { accelKey: true }, composeWindow);
+ await TestUtils.waitForCondition(
+ () => composeWindow.gSaveOperationInProgress,
+ "Should start save operation"
+ );
+ await TestUtils.waitForCondition(
+ () => !composeWindow.gSaveOperationInProgress && !composeWindow.gWindowLock,
+ "Waiting for the save operation to complete"
+ );
+ await TestUtils.waitForCondition(
+ () => draftsFolder.getTotalMessages(false) > oldDraftsCounts,
+ "message saved to drafts folder"
+ );
+ await BrowserTestUtils.closeWindow(composeWindow);
+}
+
+async function assertDraftFormat(expectSavedFormat) {
+ await be_in_folder(draftsFolder);
+ select_click_row(0);
+
+ let newComposeWindow = open_compose_from_draft().window;
+ assertSendFormatInMenu(
+ newComposeWindow,
+ expectSavedFormat,
+ "Send format of the opened draft should match the saved format"
+ );
+ return newComposeWindow;
+}
+
+add_task(async function test_preference_send_format() {
+ // Sending a plain message.
+ for (let { preference, sendsPlain, sendsHtml } of [
+ {
+ preference: Ci.nsIMsgCompSendFormat.Auto,
+ sendsPlain: true,
+ sendsHtml: false,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.PlainText,
+ sendsPlain: true,
+ sendsHtml: false,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.HTML,
+ sendsPlain: false,
+ sendsHtml: true,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.Both,
+ sendsPlain: true,
+ sendsHtml: true,
+ },
+ ]) {
+ info(`Testing preference ${preference} with a plain message`);
+ let composeWindow = await newMessage(preference, false);
+ await assertSentMessage(
+ composeWindow,
+ { plain: sendsPlain, html: sendsHtml, isBold: false },
+ `Plain message with preference ${preference}`
+ );
+ }
+ // Sending a bold message.
+ for (let { preference, sendsPlain, sendsHtml } of [
+ {
+ preference: Ci.nsIMsgCompSendFormat.Auto,
+ sendsPlain: true,
+ sendsHtml: true,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.PlainText,
+ sendsPlain: true,
+ sendsHtml: false,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.HTML,
+ sendsPlain: false,
+ sendsHtml: true,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.Both,
+ sendsPlain: true,
+ sendsHtml: true,
+ },
+ ]) {
+ info(`Testing preference ${preference} with a bold message`);
+ let composeWindow = await newMessage(preference, true);
+ await assertSentMessage(
+ composeWindow,
+ { plain: sendsPlain, html: sendsHtml, isBold: true },
+ `Bold message with preference ${preference}`
+ );
+ }
+});
+
+add_task(async function test_setting_send_format() {
+ for (let { preference, sendFormat, boldMessage, sendsPlain, sendsHtml } of [
+ {
+ preference: Ci.nsIMsgCompSendFormat.Auto,
+ boldMessage: true,
+ sendFormat: Ci.nsIMsgCompSendFormat.HTML,
+ sendsPlain: false,
+ sendsHtml: true,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.Auto,
+ boldMessage: true,
+ sendFormat: Ci.nsIMsgCompSendFormat.PlainText,
+ sendsPlain: true,
+ sendsHtml: false,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.PlainText,
+ boldMessage: false,
+ sendFormat: Ci.nsIMsgCompSendFormat.Both,
+ sendsPlain: true,
+ sendsHtml: true,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.HTML,
+ boldMessage: false,
+ sendFormat: Ci.nsIMsgCompSendFormat.Auto,
+ sendsPlain: true,
+ sendsHtml: false,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.Both,
+ boldMessage: false,
+ sendFormat: Ci.nsIMsgCompSendFormat.HTML,
+ sendsPlain: false,
+ sendsHtml: true,
+ },
+ ]) {
+ info(
+ `Testing changing format from preference ${preference} to ${sendFormat}`
+ );
+ let composeWindow = await newMessage(preference, boldMessage);
+ await setSendFormat(composeWindow, sendFormat);
+ await assertSentMessage(
+ composeWindow,
+ { isBold: boldMessage, plain: sendsPlain, html: sendsHtml },
+ `${boldMessage ? "Bold" : "Plain"} message set as ${sendFormat}`
+ );
+ }
+}).__skipMe = AppConstants.platform == "macosx";
+// Can't click menu bar on Mac to change the send format.
+
+add_task(async function test_saving_draft_with_set_format() {
+ for (let { preference, sendFormat, sendsPlain, sendsHtml } of [
+ {
+ preference: Ci.nsIMsgCompSendFormat.Auto,
+ sendFormat: Ci.nsIMsgCompSendFormat.PlainText,
+ sendsPlain: true,
+ sendsHtml: false,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.PlainText,
+ sendFormat: Ci.nsIMsgCompSendFormat.Auto,
+ sendsPlain: true,
+ sendsHtml: true,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.Both,
+ sendFormat: Ci.nsIMsgCompSendFormat.HTML,
+ sendsPlain: false,
+ sendsHtml: true,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.HTML,
+ sendFormat: Ci.nsIMsgCompSendFormat.Both,
+ sendsPlain: true,
+ sendsHtml: true,
+ },
+ ]) {
+ info(`Testing draft saved as ${sendFormat}`);
+ let composeWindow = await newMessage(preference, true);
+ await setSendFormat(composeWindow, sendFormat);
+ await saveDraft(composeWindow);
+ // Draft keeps the set format when opened.
+ composeWindow = await assertDraftFormat(sendFormat);
+ await assertSentMessage(
+ composeWindow,
+ { isBold: true, plain: sendsPlain, html: sendsHtml },
+ `Bold draft message set as ${sendFormat}`
+ );
+ }
+}).__skipMe = AppConstants.platform == "macosx";
+// Can't click menu bar on Mac to change the send format.
+
+add_task(async function test_saving_draft_with_new_preference() {
+ for (let { preference, newPreference, sendsPlain, sendsHtml } of [
+ {
+ preference: Ci.nsIMsgCompSendFormat.Auto,
+ newPreference: Ci.nsIMsgCompSendFormat.HTML,
+ sendsPlain: true,
+ sendsHtml: false,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.PlainText,
+ newPreference: Ci.nsIMsgCompSendFormat.Both,
+ sendsPlain: true,
+ sendsHtml: false,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.Both,
+ newPreference: Ci.nsIMsgCompSendFormat.Auto,
+ sendsPlain: true,
+ sendsHtml: true,
+ },
+ {
+ preference: Ci.nsIMsgCompSendFormat.HTML,
+ newPreference: Ci.nsIMsgCompSendFormat.PlainText,
+ sendsPlain: false,
+ sendsHtml: true,
+ },
+ ]) {
+ info(`Testing changing preference from ${preference} to ${newPreference}`);
+ let composeWindow = await newMessage(preference, false);
+ await saveDraft(composeWindow);
+ // Re-open, with a new default preference set, to make sure the draft has
+ // the send format set earlier saved in its headers.
+ Services.prefs.setIntPref("mail.default_send_format", newPreference);
+ // Draft keeps the old preference.
+ composeWindow = await assertDraftFormat(preference);
+ await assertSentMessage(
+ composeWindow,
+ { isBold: false, plain: sendsPlain, html: sendsHtml },
+ `Plain draft message with preference ${preference}`
+ );
+ }
+});