/* 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 the warning notification that appears when there are too many public * recipients. */ "use strict"; var { MailServices } = ChromeUtils.import( "resource:///modules/MailServices.jsm" ); var { close_compose_window, open_compose_new_mail, open_compose_with_reply_to_all, setup_msg_contents, } = ChromeUtils.import("resource://testing-common/mozmill/ComposeHelpers.jsm"); var { close_window } = ChromeUtils.import( "resource://testing-common/mozmill/WindowHelpers.jsm" ); var { add_message_to_folder, assert_selected_and_displayed, be_in_folder, create_message, mc, select_click_row, } = ChromeUtils.import( "resource://testing-common/mozmill/FolderDisplayHelpers.jsm" ); let publicRecipientLimit = Services.prefs.getIntPref( "mail.compose.warn_public_recipients.threshold" ); requestLongerTimeout(5); /** * Test we only show one warning when "To" recipients goes over the limit * for a reply all. */ add_task(async function testWarningShowsOnceWhenToFieldOverLimit() { // Now set up an account with some identities. let account = MailServices.accounts.createAccount(); account.incomingServer = MailServices.accounts.createIncomingServer( "nobody", "BCC Reply Testing", "pop3" ); let folder = account.incomingServer.rootFolder .QueryInterface(Ci.nsIMsgLocalMailFolder) .createLocalSubfolder("Msgs4Reply"); let identity = MailServices.accounts.createIdentity(); identity.email = "bcc@example.com"; account.addIdentity(identity); registerCleanupFunction(() => { MailServices.accounts.removeAccount(account, true); }); let i = 1; let msg0 = create_message({ from: "Homer ", to: "test@example.org," .repeat(publicRecipientLimit + 100) .replace(/test@/g, () => `test${i++}@`), cc: "Lisa ", subject: "msg over the limit for bulk warning", }); await add_message_to_folder([folder], msg0); await be_in_folder(folder); let msg = select_click_row(0); assert_selected_and_displayed(mc, msg); let cwc = open_compose_with_reply_to_all(); await BrowserTestUtils.waitForCondition( () => cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), `Timeout waiting for warning shown when "To" recipients >= ${publicRecipientLimit}` ); Assert.equal( 1, cwc.window.document.querySelectorAll( `notification-message[value="warnPublicRecipientsNotification"]` ).length, "should have exactly one notification about it" ); close_compose_window(cwc); }); /** * Test the warning displays when the "To" recipients list hits the limit. */ add_task(async function testWarningShowsWhenToFieldHitsLimit() { let cwc = open_compose_new_mail(); let i = 1; setup_msg_contents( cwc, "test@example.org," .repeat(publicRecipientLimit) .replace(/test@/g, () => `test${i++}@`), "Testing To Field", "" ); await BrowserTestUtils.waitForCondition( () => cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), `Timeout waiting for warning shown when "To" recipients >= ${publicRecipientLimit}` ); close_compose_window(cwc); }); /** * Test the warning displays when the "Cc" recipients list hits the limit. */ add_task(async function testWarningShowsWhenCcFieldHitLimit() { let cwc = open_compose_new_mail(); // Click on the Cc recipient label. EventUtils.synthesizeMouseAtCenter( cwc.window.document.getElementById("addr_ccShowAddressRowButton"), {}, cwc.window ); // The Cc field should now be visible. Assert.ok( !cwc.window.document .getElementById("ccAddrInput") .closest(".address-row") .classList.contains("hidden"), "The Cc field is visible" ); let i = 1; setup_msg_contents( cwc, "test@example.org," .repeat(publicRecipientLimit) .replace(/test@/g, () => `test${i++}@`), "Testing Cc Field", "", "ccAddrInput" ); await BrowserTestUtils.waitForCondition( () => cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), `Timeout waiting for warning shown when "Cc" recipients >= ${publicRecipientLimit}` ); close_compose_window(cwc); }); /** * Test the warning displays when both the "To" and "Cc" recipients lists * combined hit the limit. */ add_task(async function testWarningShowsWhenToAndCcFieldHitLimit() { let cwc = open_compose_new_mail(); let i = 1; setup_msg_contents( cwc, "test@example.org," .repeat(publicRecipientLimit - 1) .replace(/test@/g, () => `test${i++}@`), "Testing To and Cc Fields", "" ); // Click on the Cc recipient label. EventUtils.synthesizeMouseAtCenter( cwc.window.document.getElementById("addr_ccShowAddressRowButton"), {}, cwc.window ); // The Cc field should now be visible. Assert.ok( !cwc.window.document .getElementById("ccAddrInput") .closest(".address-row") .classList.contains("hidden"), "The Cc field is visible" ); setup_msg_contents(cwc, "test@example.org", "", "", "ccAddrInput"); await BrowserTestUtils.waitForCondition( () => cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), `Timeout waiting for warning shown "To" and "Cc" recipients >= ${publicRecipientLimit}` ); close_compose_window(cwc); }); /** * Test the "To" recipients are moved to the "Bcc" field when the user selects * that option. */ add_task(async function testToRecipientsMovedToBcc() { let cwc = open_compose_new_mail(); let i = 1; setup_msg_contents( cwc, "test@example.org," .repeat(publicRecipientLimit) .replace(/test@/g, () => `test${i++}@`), "Testing move to Bcc", "" ); await BrowserTestUtils.waitForCondition( () => cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), `Timeout waiting for warnPublicRecipientsNotification` ); let notificationHidden = BrowserTestUtils.waitForCondition( () => !cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), "public recipients warning was not removed in time" ); let notification = cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ); EventUtils.synthesizeMouseAtCenter( notification.buttonContainer.firstElementChild, {}, cwc.window ); Assert.equal( cwc.window.document.querySelectorAll( "#bccAddrContainer > mail-address-pill" ).length, publicRecipientLimit, "Bcc field populated with addresses" ); Assert.equal( cwc.window.document.querySelectorAll("#toAddrContainer > mail-address-pill") .length, 0, "addresses removed from the To field" ); await notificationHidden; close_compose_window(cwc); }); /** * Test that all the "To" recipients are moved to the "Bcc" field when the * address count is over the limit. */ add_task(async function testAllToRecipientsMovedToBccWhenOverLimit() { let cwc = open_compose_new_mail(); let limit = publicRecipientLimit + 1; let i = 1; setup_msg_contents( cwc, "test@example.org,".repeat(limit).replace(/test@/g, () => `test${i++}@`), "Testing move to Bcc", "" ); await BrowserTestUtils.waitForCondition( () => cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), `Timeout waiting for warnPublicRecipientsNotification` ); let notificationHidden = BrowserTestUtils.waitForCondition( () => !cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), "public recipients warning was not removed in time" ); let notification = cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ); EventUtils.synthesizeMouseAtCenter( notification.buttonContainer.firstElementChild, {}, cwc.window ); Assert.equal( cwc.window.document.querySelectorAll( "#bccAddrContainer > mail-address-pill" ).length, limit, "Bcc field populated with addresses" ); Assert.equal( cwc.window.document.querySelectorAll("#toAddrContainer > mail-address-pill") .length, 0, "addresses removed from the To field" ); await notificationHidden; close_compose_window(cwc); }); /** * Test the "Cc" recipients are moved to the "Bcc" field when the user selects * that option. */ add_task(async function testCcRecipientsMovedToBcc() { let cwc = open_compose_new_mail(); // Click on the Cc recipient label. EventUtils.synthesizeMouseAtCenter( cwc.window.document.getElementById("addr_ccShowAddressRowButton"), {}, cwc.window ); // The Cc field should now be visible. Assert.ok( !cwc.window.document .getElementById("ccAddrInput") .closest(".address-row") .classList.contains("hidden"), "The Cc field is visible" ); let i = 1; setup_msg_contents( cwc, "test@example.org," .repeat(publicRecipientLimit) .replace(/test@/g, () => `test${i++}@`), "Testing move to Bcc", "" ); await BrowserTestUtils.waitForCondition( () => cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), `Timeout waiting for warnPublicRecipientsNotification` ); let notificationHidden = BrowserTestUtils.waitForCondition( () => !cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), "public recipients warning was not removed in time" ); let notification = cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ); EventUtils.synthesizeMouseAtCenter( notification.buttonContainer.firstElementChild, {}, cwc.window ); Assert.equal( cwc.window.document.querySelectorAll( "#bccAddrContainer > mail-address-pill" ).length, publicRecipientLimit, "Bcc field populated with addresses" ); Assert.equal( cwc.window.document.querySelectorAll("#ccAddrContainer > mail-address-pill") .length, 0, "addresses removed from the Cc field" ); await notificationHidden; close_compose_window(cwc); }); /** * Test that all the "Cc" recipients are moved to the "Bcc" field when the * address count is over the limit. */ add_task(async function testAllCcRecipientsMovedToBccWhenOverLimit() { let cwc = open_compose_new_mail(); let limit = publicRecipientLimit + 1; // Click on the Cc recipient label. EventUtils.synthesizeMouseAtCenter( cwc.window.document.getElementById("addr_ccShowAddressRowButton"), {}, cwc.window ); // The Cc field should now be visible. Assert.ok( !cwc.window.document .getElementById("ccAddrInput") .closest(".address-row") .classList.contains("hidden"), "The Cc field is visible" ); let i = 1; setup_msg_contents( cwc, "test@example.org,".repeat(limit).replace(/test@/g, () => `test${i++}@`), "Testing move to Bcc", "" ); await BrowserTestUtils.waitForCondition( () => cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), `Timeout waiting for warnPublicRecipientsNotification` ); let notificationHidden = BrowserTestUtils.waitForCondition( () => !cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), "public recipients warning was not removed in time" ); let notification = cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ); EventUtils.synthesizeMouseAtCenter( notification.buttonContainer.firstElementChild, {}, cwc.window ); Assert.equal( cwc.window.document.querySelectorAll( "#bccAddrContainer > mail-address-pill" ).length, limit, "Bcc field populated with addresses" ); Assert.equal( cwc.window.document.querySelectorAll("#ccAddrContainer > mail-address-pill") .length, 0, "addresses removed from the Cc field" ); await notificationHidden; close_compose_window(cwc); }); /** * Test that both the "To" and "Cc" recipients are moved to the "Bcc" field when * the user selects that option. */ add_task(async function testToAndCcRecipientsMovedToBcc() { let cwc = open_compose_new_mail(); let i = 1; setup_msg_contents( cwc, "test@example.org," .repeat(publicRecipientLimit - 1) .replace(/test@/g, () => `test${i++}@`), "Testing move to Bcc", "" ); // Click on the Cc recipient label. EventUtils.synthesizeMouseAtCenter( cwc.window.document.getElementById("addr_ccShowAddressRowButton"), {}, cwc.window ); // The Cc field should now be visible. Assert.ok( !cwc.window.document .getElementById("ccAddrInput") .closest(".address-row") .classList.contains("hidden"), "The Cc field is visible" ); setup_msg_contents(cwc, "test@example.org", "", ""); await BrowserTestUtils.waitForCondition( () => cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), `Timeout waiting for warnPublicRecipientsNotification` ); let notificationHidden = BrowserTestUtils.waitForCondition( () => !cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), "public recipients warning was not removed in time" ); let notification = cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ); EventUtils.synthesizeMouseAtCenter( notification.buttonContainer.firstElementChild, {}, cwc.window ); Assert.equal( cwc.window.document.querySelectorAll( "#bccAddrContainer > mail-address-pill" ).length, publicRecipientLimit, "Bcc field populated with addresses" ); Assert.equal( cwc.window.document.querySelectorAll("#toAddrContainer > mail-address-pill") .length, 0, "addresses removed from the To field" ); Assert.equal( cwc.window.document.querySelectorAll("#ccAddrContainer > mail-address-pill") .length, 0, "addresses removed from the Cc field" ); await notificationHidden; close_compose_window(cwc); }); /** * Test the warning is removed when the user chooses to "Keep Recipients Public". */ add_task(async function testWarningRemovedWhenKeepPublic() { let cwc = open_compose_new_mail(); let i = 1; setup_msg_contents( cwc, "test@example.org," .repeat(publicRecipientLimit) .replace(/test@/g, () => `test${i++}@`), "Testing dismissal", "" ); await BrowserTestUtils.waitForCondition( () => cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), `Timeout waiting for warnPublicRecipientsNotification` ); let notificationHidden = BrowserTestUtils.waitForCondition( () => !cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), "public recipients warning was not removed in time" ); let notification = cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ); EventUtils.synthesizeMouseAtCenter( notification.buttonContainer.lastElementChild, {}, cwc.window ); await notificationHidden; Assert.equal( cwc.window.document.querySelectorAll("#toAddrContainer > mail-address-pill") .length, publicRecipientLimit, "addresses were not removed from the field" ); Assert.equal( cwc.window.document.querySelectorAll( "#bccAddrContainer > mail-address-pill" ).length, 0, "no addresses added to the Bcc field" ); close_compose_window(cwc); }); /** * Test that the warning is not shown again if the user dismisses it. */ add_task(async function testWarningNotShownAfterDismissal() { let cwc = open_compose_new_mail(); let i = 1; setup_msg_contents( cwc, "test@example.org," .repeat(publicRecipientLimit) .replace(/test@/g, () => `test${i++}@`), "Testing dismissal", "" ); await BrowserTestUtils.waitForCondition( () => cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), `Timeout waiting for warnPublicRecipientsNotification` ); let notificationHidden = BrowserTestUtils.waitForCondition( () => !cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), "public recipients warning was not removed in time" ); let notification = cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ); EventUtils.synthesizeMouseAtCenter(notification.closeButton, {}, cwc.window); await notificationHidden; let input = cwc.window.document.getElementById("toAddrInput"); input.focus(); let recipString = "test@example.org," .repeat(publicRecipientLimit) .replace(/test@/g, () => `test${i++}@`); EventUtils.sendString(recipString, cwc.window); // Wait a little in case the notification bar mistakenly appears. // eslint-disable-next-line mozilla/no-arbitrary-setTimeout await new Promise(resolve => setTimeout(resolve, 500)); Assert.ok( !cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), "public recipients warning did not appear after dismissal" ); close_compose_window(cwc); }); /** * Tests that the individual addresses of a mailing list are considered. */ add_task(async function testMailingListMembersCounted() { let book = MailServices.ab.getDirectoryFromId( MailServices.ab.newAddressBook("Mochitest", null, 101) ); let list = Cc["@mozilla.org/addressbook/directoryproperty;1"].createInstance( Ci.nsIAbDirectory ); list.isMailList = true; list.dirName = "Test List"; list = book.addMailList(list); for (let i = 0; i < publicRecipientLimit; i++) { let card = Cc["@mozilla.org/addressbook/cardproperty;1"].createInstance( Ci.nsIAbCard ); card.primaryEmail = `test${i}@example`; list.addCard(card); } list.editMailListToDatabase(null); let cwc = open_compose_new_mail(); setup_msg_contents(cwc, "Test List", "Testing mailing lists", ""); await BrowserTestUtils.waitForCondition( () => cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ), `Timeout waiting for warnPublicRecipientsNotification` ); let notification = cwc.window.gComposeNotification.getNotificationWithValue( "warnPublicRecipientsNotification" ); Assert.equal( notification.messageText.textContent, `The ${publicRecipientLimit} recipients in To and Cc will see each other’s address. You can avoid disclosing recipients by using Bcc instead.`, "total count equals all addresses plus list expanded" ); MailServices.ab.deleteAddressBook(book.URI); close_compose_window(cwc); });