summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/extensions/test/browser/browser_ext_compose_sendMessage.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /comm/mail/components/extensions/test/browser/browser_ext_compose_sendMessage.js
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/mail/components/extensions/test/browser/browser_ext_compose_sendMessage.js')
-rw-r--r--comm/mail/components/extensions/test/browser/browser_ext_compose_sendMessage.js733
1 files changed, 733 insertions, 0 deletions
diff --git a/comm/mail/components/extensions/test/browser/browser_ext_compose_sendMessage.js b/comm/mail/components/extensions/test/browser/browser_ext_compose_sendMessage.js
new file mode 100644
index 0000000000..4fd983e8e5
--- /dev/null
+++ b/comm/mail/components/extensions/test/browser/browser_ext_compose_sendMessage.js
@@ -0,0 +1,733 @@
+/* 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/. */
+
+var { ExtensionSupport } = ChromeUtils.import(
+ "resource:///modules/ExtensionSupport.jsm"
+);
+var { localAccountUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/LocalAccountUtils.jsm"
+);
+// Import the smtp server scripts
+var {
+ nsMailServer,
+ gThreadManager,
+ fsDebugNone,
+ fsDebugAll,
+ fsDebugRecv,
+ fsDebugRecvSend,
+} = ChromeUtils.import("resource://testing-common/mailnews/Maild.jsm");
+var { SmtpDaemon, SMTP_RFC2821_handler } = ChromeUtils.import(
+ "resource://testing-common/mailnews/Smtpd.jsm"
+);
+var { AuthPLAIN, AuthLOGIN, AuthCRAM } = ChromeUtils.import(
+ "resource://testing-common/mailnews/Auth.jsm"
+);
+
+// Setup the daemon and server
+function setupServerDaemon(handler) {
+ if (!handler) {
+ handler = function (d) {
+ return new SMTP_RFC2821_handler(d);
+ };
+ }
+ var server = new nsMailServer(handler, new SmtpDaemon());
+ return server;
+}
+
+function getBasicSmtpServer(port = 1, hostname = "localhost") {
+ let server = localAccountUtils.create_outgoing_server(
+ port,
+ "user",
+ "password",
+ hostname
+ );
+
+ // Override the default greeting so we get something predictable
+ // in the ELHO message
+ Services.prefs.setCharPref("mail.smtpserver.default.hello_argument", "test");
+
+ return server;
+}
+
+function getSmtpIdentity(senderName, smtpServer) {
+ // Set up the identity.
+ let identity = MailServices.accounts.createIdentity();
+ identity.email = senderName;
+ identity.smtpServerKey = smtpServer.key;
+
+ return identity;
+}
+
+function tracksentMessages(aSubject, aTopic, aMsgID) {
+ // The aMsgID starts with < and ends with > which is not used by the API.
+ let headerMessageId = aMsgID.replace(/^<|>$/g, "");
+ gSentMessages.push(headerMessageId);
+}
+
+var gServer;
+var gOutbox;
+var gSentMessages = [];
+let gPopAccount;
+let gLocalAccount;
+
+add_setup(() => {
+ gServer = setupServerDaemon();
+ gServer.start();
+
+ // Test needs a non-local default account to be able to send messages.
+ gPopAccount = createAccount("pop3");
+ gLocalAccount = createAccount("local");
+ MailServices.accounts.defaultAccount = gPopAccount;
+
+ let identity = getSmtpIdentity(
+ "identity@foo.invalid",
+ getBasicSmtpServer(gServer.port)
+ );
+ gPopAccount.addIdentity(identity);
+ gPopAccount.defaultIdentity = identity;
+
+ // Test is using the Sent folder and Outbox folder of the local account.
+ let rootFolder = gLocalAccount.incomingServer.rootFolder;
+ rootFolder.createSubfolder("Sent", null);
+ MailServices.accounts.setSpecialFolders();
+ gOutbox = rootFolder.getChildNamed("Outbox");
+
+ Services.obs.addObserver(tracksentMessages, "mail:composeSendSucceeded");
+
+ registerCleanupFunction(() => {
+ gServer.stop();
+ Services.obs.removeObserver(tracksentMessages, "mail:composeSendSucceeded");
+ });
+});
+
+add_task(async function test_no_permission() {
+ let files = {
+ "background.js": async () => {
+ let details = {
+ to: ["send@test.invalid"],
+ subject: "Test send",
+ };
+
+ // Open a compose window with a message.
+ let tab = await browser.compose.beginNew(details);
+
+ // Send now. It should fail due to the missing compose.send permission.
+ await browser.test.assertThrows(
+ () => browser.compose.sendMessage(tab.id),
+ /browser.compose.sendMessage is not a function/,
+ "browser.compose.sendMessage() should reject, if the permission compose.send is not granted."
+ );
+
+ // Clean up.
+ let removedWindowPromise = window.waitForEvent("windows.onRemoved");
+ browser.tabs.remove(tab.id);
+ await removedWindowPromise;
+
+ browser.test.notifyPass("finished");
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["compose"],
+ },
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("finished");
+ await extension.unload();
+});
+
+add_task(async function test_fail() {
+ let files = {
+ "background.js": async () => {
+ let details = {
+ to: ["send@test.invalid"],
+ subject: "Test send",
+ };
+
+ // Open a compose window with a message.
+ let createdWindowPromise = window.waitForEvent("windows.onCreated");
+ await browser.compose.beginNew(details);
+ let [createdWindow] = await createdWindowPromise;
+ browser.test.assertEq("messageCompose", createdWindow.type);
+
+ await window.sendMessage("checkWindow", details);
+
+ let [tab] = await browser.tabs.query({ windowId: createdWindow.id });
+
+ browser.compose.onBeforeSend.addListener(() => {
+ return { cancel: true };
+ });
+
+ // Add onAfterSend listener
+ let collectedEventsMap = new Map();
+ function onAfterSendListener(tab, info) {
+ collectedEventsMap.set(tab.id, info);
+ }
+ browser.compose.onAfterSend.addListener(onAfterSendListener);
+
+ // Send now. It should fail due to the aborting onBeforeSend listener.
+ await browser.test.assertRejects(
+ browser.compose.sendMessage(tab.id),
+ /Send aborted by an onBeforeSend event/,
+ "browser.compose.sendMessage() should reject, if the message could not be send."
+ );
+
+ // Check onAfterSend listener
+ browser.compose.onAfterSend.removeListener(onAfterSendListener);
+ browser.test.assertEq(
+ 1,
+ collectedEventsMap.size,
+ "Should have received the correct number of onAfterSend events"
+ );
+ browser.test.assertEq(
+ "Send aborted by an onBeforeSend event",
+ collectedEventsMap.get(tab.id).error,
+ "Should have received the correct error"
+ );
+
+ // Clean up.
+ let removedWindowPromise = window.waitForEvent("windows.onRemoved");
+ browser.windows.remove(createdWindow.id);
+ await removedWindowPromise;
+
+ browser.test.notifyPass("finished");
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["compose", "compose.send"],
+ },
+ });
+
+ extension.onMessage("checkWindow", async expected => {
+ await checkComposeHeaders(expected);
+ extension.sendMessage();
+ });
+
+ extension.onMessage("getSentMessages", async () => {
+ extension.sendMessage(gSentMessages);
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("finished");
+ await extension.unload();
+});
+
+add_task(async function test_send() {
+ let files = {
+ "background.js": async () => {
+ let details = {
+ to: ["send@test.invalid"],
+ subject: "Test send",
+ };
+
+ // Open a compose window with a message.
+ let createdWindowPromise = window.waitForEvent("windows.onCreated");
+ await browser.compose.beginNew(details);
+ let [createdWindow] = await createdWindowPromise;
+ browser.test.assertEq("messageCompose", createdWindow.type);
+
+ await window.sendMessage("checkWindow", details);
+
+ let [tab] = await browser.tabs.query({ windowId: createdWindow.id });
+
+ // Add onAfterSend listener
+ let collectedEventsMap = new Map();
+ function onAfterSendListener(tab, info) {
+ collectedEventsMap.set(tab.id, info);
+ }
+ browser.compose.onAfterSend.addListener(onAfterSendListener);
+
+ // Send now.
+ let removedWindowPromise = window.waitForEvent("windows.onRemoved");
+ let rv = await browser.compose.sendMessage(tab.id);
+ let [sentMessages] = await window.sendMessage("getSentMessages");
+
+ browser.test.assertEq(
+ 1,
+ sentMessages.length,
+ "Number of total messages sent should be correct."
+ );
+ browser.test.assertEq(
+ "sendNow",
+ rv.mode,
+ "The mode of the last message operation should be correct."
+ );
+ browser.test.assertEq(
+ sentMessages[0],
+ rv.headerMessageId,
+ "The headerMessageId of last message sent should be correct."
+ );
+ browser.test.assertEq(
+ sentMessages[0],
+ rv.messages[0].headerMessageId,
+ "The headerMessageId in the copy of last message sent should be correct."
+ );
+
+ // Window should have closed after send.
+ await removedWindowPromise;
+
+ // Check onAfterSend listener
+ browser.compose.onAfterSend.removeListener(onAfterSendListener);
+ browser.test.assertEq(
+ 1,
+ collectedEventsMap.size,
+ "Should have received the correct number of onAfterSend events"
+ );
+ browser.test.assertTrue(
+ collectedEventsMap.has(tab.id),
+ "The received event should belong to the correct tab."
+ );
+ browser.test.assertEq(
+ "sendNow",
+ collectedEventsMap.get(tab.id).mode,
+ "The received event should have the correct mode."
+ );
+ browser.test.assertEq(
+ rv.headerMessageId,
+ collectedEventsMap.get(tab.id).headerMessageId,
+ "The received event should have the correct headerMessageId."
+ );
+ browser.test.assertEq(
+ rv.headerMessageId,
+ collectedEventsMap.get(tab.id).messages[0].headerMessageId,
+ "The message in the received event should have the correct headerMessageId."
+ );
+
+ browser.test.notifyPass("finished");
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["compose", "compose.send"],
+ },
+ });
+
+ extension.onMessage("checkWindow", async expected => {
+ await checkComposeHeaders(expected);
+ extension.sendMessage();
+ });
+
+ extension.onMessage("getSentMessages", async () => {
+ extension.sendMessage(gSentMessages);
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("finished");
+ await extension.unload();
+});
+
+add_task(async function test_sendDefault() {
+ let files = {
+ "background.js": async () => {
+ let details = {
+ to: ["sendDefault@test.invalid"],
+ subject: "Test sendDefault",
+ };
+
+ // Open a compose window with a message.
+ let createdWindowPromise = window.waitForEvent("windows.onCreated");
+ await browser.compose.beginNew(details);
+ let [createdWindow] = await createdWindowPromise;
+ browser.test.assertEq("messageCompose", createdWindow.type);
+
+ await window.sendMessage("checkWindow", details);
+
+ let [tab] = await browser.tabs.query({ windowId: createdWindow.id });
+
+ // Send via default mode, which should be sendNow.
+ let removedWindowPromise = window.waitForEvent("windows.onRemoved");
+ let rv = await browser.compose.sendMessage(tab.id, { mode: "default" });
+ let [sentMessages] = await window.sendMessage("getSentMessages");
+
+ browser.test.assertEq(
+ 2,
+ sentMessages.length,
+ "Number of total messages sent should be correct."
+ );
+ browser.test.assertEq(
+ "sendNow",
+ rv.mode,
+ "The mode of the last message operation should be correct."
+ );
+ browser.test.assertEq(
+ sentMessages[1],
+ rv.headerMessageId,
+ "The headerMessageId of last message sent should be correct."
+ );
+ browser.test.assertEq(
+ sentMessages[1],
+ rv.messages[0].headerMessageId,
+ "The headerMessageId in the copy of last message sent should be correct."
+ );
+
+ // Window should have closed after send.
+ await removedWindowPromise;
+
+ browser.test.notifyPass("finished");
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["compose", "compose.send"],
+ },
+ });
+
+ extension.onMessage("checkWindow", async expected => {
+ await checkComposeHeaders(expected);
+ extension.sendMessage();
+ });
+
+ extension.onMessage("getSentMessages", async () => {
+ extension.sendMessage(gSentMessages);
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("finished");
+ await extension.unload();
+ gServer.resetTest();
+});
+
+add_task(async function test_sendNow() {
+ let files = {
+ "background.js": async () => {
+ let details = {
+ to: ["sendNow@test.invalid"],
+ subject: "Test sendNow",
+ };
+
+ // Open a compose window with a message.
+ let createdWindowPromise = window.waitForEvent("windows.onCreated");
+ await browser.compose.beginNew(details);
+ let [createdWindow] = await createdWindowPromise;
+ browser.test.assertEq("messageCompose", createdWindow.type);
+
+ await window.sendMessage("checkWindow", details);
+
+ let [tab] = await browser.tabs.query({ windowId: createdWindow.id });
+
+ // Send via sendNow mode.
+ let removedWindowPromise = window.waitForEvent("windows.onRemoved");
+ let rv = await browser.compose.sendMessage(tab.id, { mode: "sendNow" });
+ let [sentMessages] = await window.sendMessage("getSentMessages");
+
+ browser.test.assertEq(
+ 3,
+ sentMessages.length,
+ "Number of total messages sent should be correct."
+ );
+ browser.test.assertEq(
+ "sendNow",
+ rv.mode,
+ "The mode of the last message operation should be correct."
+ );
+ browser.test.assertEq(
+ sentMessages[2],
+ rv.headerMessageId,
+ "The headerMessageId of last message sent should be correct."
+ );
+ browser.test.assertEq(
+ sentMessages[2],
+ rv.messages[0].headerMessageId,
+ "The headerMessageId in the copy of last message sent should be correct."
+ );
+
+ // Window should have closed after send.
+ await removedWindowPromise;
+
+ browser.test.notifyPass("finished");
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["compose", "compose.send"],
+ },
+ });
+
+ extension.onMessage("checkWindow", async expected => {
+ await checkComposeHeaders(expected);
+ extension.sendMessage();
+ });
+
+ extension.onMessage("getSentMessages", async () => {
+ extension.sendMessage(gSentMessages);
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("finished");
+ await extension.unload();
+});
+
+add_task(async function test_sendLater() {
+ let files = {
+ "background.js": async () => {
+ let details = {
+ to: ["sendLater@test.invalid"],
+ subject: "Test sendLater",
+ };
+
+ let createdWindowPromise = window.waitForEvent("windows.onCreated");
+ await browser.compose.beginNew(details);
+ let [createdWindow] = await createdWindowPromise;
+ browser.test.assertEq("messageCompose", createdWindow.type);
+
+ await window.sendMessage("checkWindow", details);
+
+ let [tab] = await browser.tabs.query({ windowId: createdWindow.id });
+
+ // Send Later.
+
+ let rv = await browser.compose.sendMessage(tab.id, { mode: "sendLater" });
+ let [outboxMessage] = await window.sendMessage(
+ "checkMessagesInOutbox",
+ details
+ );
+
+ browser.test.assertEq(
+ "sendLater",
+ rv.mode,
+ "The mode of the last message operation should be correct."
+ );
+ browser.test.assertEq(
+ outboxMessage,
+ rv.messages[0].headerMessageId,
+ "The headerMessageId in the copy of last message sent should be correct."
+ );
+
+ await window.sendMessage("clearMessagesInOutbox");
+ browser.test.notifyPass("finished");
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["compose", "compose.send", "messagesRead", "accountsRead"],
+ },
+ });
+
+ extension.onMessage("checkMessagesInOutbox", async expected => {
+ // Check if the sendLater request did put the message in the outbox.
+ let outboxMessages = [...gOutbox.messages];
+ Assert.ok(outboxMessages.length == 1);
+ let sentMessage = outboxMessages.shift();
+ Assert.equal(sentMessage.subject, expected.subject, "subject is correct");
+ Assert.equal(sentMessage.recipients, expected.to, "recipient is correct");
+ extension.sendMessage(sentMessage.messageId);
+ });
+
+ extension.onMessage("clearMessagesInOutbox", async () => {
+ let outboxMessages = [...gOutbox.messages];
+ await new Promise(resolve => {
+ gOutbox.deleteMessages(
+ outboxMessages,
+ null,
+ true,
+ false,
+ { OnStopCopy: resolve },
+ false
+ );
+ });
+
+ Assert.equal(0, [...gOutbox.messages].length, "outbox should be empty");
+ extension.sendMessage();
+ });
+
+ extension.onMessage("checkWindow", async expected => {
+ await checkComposeHeaders(expected);
+ extension.sendMessage();
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("finished");
+ await extension.unload();
+});
+
+add_task(async function test_onComposeStateChanged() {
+ let files = {
+ "background.js": async () => {
+ let numberOfEvents = 0;
+ browser.compose.onComposeStateChanged.addListener(async (tab, state) => {
+ numberOfEvents++;
+ browser.test.log(`State #${numberOfEvents}: ${JSON.stringify(state)}`);
+ switch (numberOfEvents) {
+ case 1:
+ // The fresh created composer has no recipient, send is disabled.
+ browser.test.assertEq(false, state.canSendNow);
+ browser.test.assertEq(false, state.canSendLater);
+ break;
+
+ case 2:
+ // The composer updated its initial details data, send is enabled.
+ browser.test.assertEq(true, state.canSendNow);
+ browser.test.assertEq(true, state.canSendLater);
+ break;
+
+ case 3:
+ // The recipient has been invalidated, send is disabled.
+ browser.test.assertEq(false, state.canSendNow);
+ browser.test.assertEq(false, state.canSendLater);
+ break;
+
+ case 4:
+ // The recipient has been reverted, send is enabled.
+ browser.test.assertEq(true, state.canSendNow);
+ browser.test.assertEq(true, state.canSendLater);
+
+ // Clean up.
+
+ let removedWindowPromise = window.waitForEvent("windows.onRemoved");
+ browser.windows.remove(createdWindow.id);
+ await removedWindowPromise;
+
+ browser.test.notifyPass("finished");
+ break;
+ }
+ });
+
+ // The call to beginNew should create two onComposeStateChanged events,
+ // one after the empty window has been created and one after the initial
+ // details have been set.
+ let createdWindowPromise = window.waitForEvent("windows.onCreated");
+ let createdTab = await browser.compose.beginNew({
+ to: ["test@test.invalid"],
+ subject: "Test part 1",
+ body: "Original body.",
+ });
+ let [createdWindow] = await createdWindowPromise;
+ browser.test.assertEq("messageCompose", createdWindow.type);
+
+ // Trigger an onComposeStateChanged event by invalidating the recipient.
+ await browser.compose.setComposeDetails(createdTab.id, {
+ to: ["test"],
+ subject: "Test part 2",
+ });
+
+ // Trigger an onComposeStateChanged event by reverting the recipient.
+ await browser.compose.setComposeDetails(createdTab.id, {
+ to: ["test@test.invalid"],
+ subject: "Test part 3",
+ });
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["compose"],
+ },
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("finished");
+ await extension.unload();
+});
+
+// Test onAfterSend for MV3
+add_task(async function test_onAfterSend_MV3_event_pages() {
+ let files = {
+ "background.js": async () => {
+ // Whenever the extension starts or wakes up, hasFired is set to false. In
+ // case of a wake-up, the first fired event is the one that woke up the background.
+ let hasFired = false;
+
+ browser.compose.onAfterSend.addListener(async (tab, sendInfo) => {
+ // Only send the first event after background wake-up, this should be
+ // the only one expected.
+ if (!hasFired) {
+ hasFired = true;
+ browser.test.sendMessage("onAfterSend received", sendInfo);
+ }
+ });
+
+ browser.test.sendMessage("background started");
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ manifest_version: 3,
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["compose"],
+ browser_specific_settings: {
+ gecko: { id: "compose.onAfterSend@xpcshell.test" },
+ },
+ },
+ });
+
+ function checkPersistentListeners({ primed }) {
+ // A persistent event is referenced by its moduleName as defined in
+ // ext-mails.json, not by its actual namespace.
+ const persistent_events = ["compose.onAfterSend"];
+
+ for (let event of persistent_events) {
+ let [moduleName, eventName] = event.split(".");
+ assertPersistentListeners(extension, moduleName, eventName, {
+ primed,
+ });
+ }
+ }
+
+ await extension.startup();
+ await extension.awaitMessage("background started");
+ // The listeners should be persistent, but not primed.
+ checkPersistentListeners({ primed: false });
+
+ // Trigger onAfterSend without terminating the background first.
+
+ let firstComposeWindow = await openComposeWindow(gPopAccount);
+ await focusWindow(firstComposeWindow);
+ firstComposeWindow.SetComposeDetails({ to: "first@invalid.net" });
+ firstComposeWindow.SetComposeDetails({ subject: "First message" });
+ firstComposeWindow.SendMessage();
+ let firstSaveInfo = await extension.awaitMessage("onAfterSend received");
+ Assert.equal(
+ "sendNow",
+ firstSaveInfo.mode,
+ "Returned SaveInfo should be correct"
+ );
+
+ // Terminate background and re-trigger onAfterSend.
+
+ await extension.terminateBackground({ disableResetIdleForTest: true });
+ // The listeners should be primed.
+ checkPersistentListeners({ primed: true });
+ let secondComposeWindow = await openComposeWindow(gPopAccount);
+ await focusWindow(secondComposeWindow);
+ secondComposeWindow.SetComposeDetails({ to: "second@invalid.net" });
+ secondComposeWindow.SetComposeDetails({ subject: "Second message" });
+ secondComposeWindow.SendMessage();
+ let secondSaveInfo = await extension.awaitMessage("onAfterSend received");
+ Assert.equal(
+ "sendNow",
+ secondSaveInfo.mode,
+ "Returned SaveInfo should be correct"
+ );
+
+ // The background should have been restarted.
+ await extension.awaitMessage("background started");
+ // The listener should no longer be primed.
+ checkPersistentListeners({ primed: false });
+
+ await extension.unload();
+});