summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/extensions/test/browser/browser_ext_windows_events.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/extensions/test/browser/browser_ext_windows_events.js')
-rw-r--r--comm/mail/components/extensions/test/browser/browser_ext_windows_events.js405
1 files changed, 405 insertions, 0 deletions
diff --git a/comm/mail/components/extensions/test/browser/browser_ext_windows_events.js b/comm/mail/components/extensions/test/browser/browser_ext_windows_events.js
new file mode 100644
index 0000000000..89cbd77e55
--- /dev/null
+++ b/comm/mail/components/extensions/test/browser/browser_ext_windows_events.js
@@ -0,0 +1,405 @@
+/* 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/. */
+
+add_task(async () => {
+ let account = createAccount();
+ addIdentity(account);
+ let rootFolder = account.incomingServer.rootFolder;
+ rootFolder.createSubfolder("windowsEvents", null);
+ let testFolder = rootFolder.findSubFolder("windowsEvents");
+ createMessages(testFolder, 5);
+
+ let extension = ExtensionTestUtils.loadExtension({
+ files: {
+ "background.js": async () => {
+ // Executes a command, but first loads a second extension with terminated
+ // background and waits for it to be restarted due to the executed command.
+ async function capturePrimedEvent(eventName, callback) {
+ let eventPageExtensionReadyPromise = window.waitForMessage();
+ browser.test.sendMessage("capturePrimedEvent", eventName);
+ await eventPageExtensionReadyPromise;
+ let eventPageExtensionFinishedPromise = window.waitForMessage();
+ callback();
+ return eventPageExtensionFinishedPromise;
+ }
+
+ let listener = {
+ tabEvents: [],
+ windowEvents: [],
+ currentPromise: null,
+
+ pushEvent(...args) {
+ browser.test.log(JSON.stringify(args));
+ let queue = args[0].startsWith("windows.")
+ ? this.windowEvents
+ : this.tabEvents;
+ queue.push(args);
+ if (queue.currentPromise) {
+ let p = queue.currentPromise;
+ queue.currentPromise = null;
+ p.resolve();
+ }
+ },
+ windowsOnCreated(...args) {
+ this.pushEvent("windows.onCreated", ...args);
+ },
+ windowsOnRemoved(...args) {
+ this.pushEvent("windows.onRemoved", ...args);
+ },
+ tabsOnCreated(...args) {
+ this.pushEvent("tabs.onCreated", ...args);
+ },
+ tabsOnRemoved(...args) {
+ this.pushEvent("tabs.onRemoved", ...args);
+ },
+ async checkEvent(expectedEvent, ...expectedArgs) {
+ let queue = expectedEvent.startsWith("windows.")
+ ? this.windowEvents
+ : this.tabEvents;
+ if (queue.length == 0) {
+ await new Promise(
+ resolve => (queue.currentPromise = { resolve })
+ );
+ }
+ let [actualEvent, ...actualArgs] = queue.shift();
+ browser.test.assertEq(expectedEvent, actualEvent);
+ browser.test.assertEq(expectedArgs.length, actualArgs.length);
+
+ for (let i = 0; i < expectedArgs.length; i++) {
+ browser.test.assertEq(
+ typeof expectedArgs[i],
+ typeof actualArgs[i]
+ );
+ if (typeof expectedArgs[i] == "object") {
+ for (let key of Object.keys(expectedArgs[i])) {
+ browser.test.assertEq(
+ expectedArgs[i][key],
+ actualArgs[i][key]
+ );
+ }
+ } else {
+ browser.test.assertEq(expectedArgs[i], actualArgs[i]);
+ }
+ }
+
+ return actualArgs;
+ },
+ };
+ browser.tabs.onCreated.addListener(
+ listener.tabsOnCreated.bind(listener)
+ );
+ browser.tabs.onRemoved.addListener(
+ listener.tabsOnRemoved.bind(listener)
+ );
+ browser.windows.onCreated.addListener(
+ listener.windowsOnCreated.bind(listener)
+ );
+ browser.windows.onRemoved.addListener(
+ listener.windowsOnRemoved.bind(listener)
+ );
+
+ browser.test.log(
+ "Collect the ID of the initial window (there must be only one) and tab."
+ );
+
+ let initialWindows = await browser.windows.getAll({ populate: true });
+ browser.test.assertEq(1, initialWindows.length);
+ let [{ id: initialWindow, tabs: initialTabs }] = initialWindows;
+ browser.test.assertEq(1, initialTabs.length);
+ browser.test.assertEq(0, initialTabs[0].index);
+ browser.test.assertTrue(initialTabs[0].mailTab);
+ let [{ id: initialTab }] = initialTabs;
+
+ browser.test.log("Open a new main window (messenger.xhtml).");
+
+ let primedMainWindowInfo = await window.sendMessage("openMainWindow");
+ let [{ id: mainWindow }] = await listener.checkEvent(
+ "windows.onCreated",
+ { type: "normal" }
+ );
+ let [{ id: mainTab }] = await listener.checkEvent("tabs.onCreated", {
+ index: 0,
+ windowId: mainWindow,
+ active: true,
+ mailTab: true,
+ });
+ window.assertDeepEqual(
+ [
+ {
+ id: mainWindow,
+ type: "normal",
+ },
+ ],
+ primedMainWindowInfo
+ );
+
+ browser.test.log("Open a compose window (messengercompose.xhtml).");
+
+ let primedComposeWindowInfo = await capturePrimedEvent(
+ "onCreated",
+ () => browser.compose.beginNew()
+ );
+ let [{ id: composeWindow }] = await listener.checkEvent(
+ "windows.onCreated",
+ {
+ type: "messageCompose",
+ }
+ );
+ let [{ id: composeTab }] = await listener.checkEvent("tabs.onCreated", {
+ index: 0,
+ windowId: composeWindow,
+ active: true,
+ mailTab: false,
+ });
+ window.assertDeepEqual(
+ [
+ {
+ id: composeWindow,
+ type: "messageCompose",
+ },
+ ],
+ primedComposeWindowInfo
+ );
+
+ browser.test.log("Open a message in a window (messageWindow.xhtml).");
+
+ let primedDisplayWindowInfo = await window.sendMessage(
+ "openDisplayWindow"
+ );
+ let [{ id: displayWindow }] = await listener.checkEvent(
+ "windows.onCreated",
+ {
+ type: "messageDisplay",
+ }
+ );
+ let [{ id: displayTab }] = await listener.checkEvent("tabs.onCreated", {
+ index: 0,
+ windowId: displayWindow,
+ active: true,
+ mailTab: false,
+ });
+ window.assertDeepEqual(
+ [
+ {
+ id: displayWindow,
+ type: "messageDisplay",
+ },
+ ],
+ primedDisplayWindowInfo
+ );
+
+ browser.test.log("Open a page in a popup window.");
+
+ let primedPopupWindowInfo = await capturePrimedEvent("onCreated", () =>
+ browser.windows.create({
+ url: "test.html",
+ type: "popup",
+ width: 800,
+ height: 500,
+ })
+ );
+ let [{ id: popupWindow }] = await listener.checkEvent(
+ "windows.onCreated",
+ {
+ type: "popup",
+ width: 800,
+ height: 500,
+ }
+ );
+ let [{ id: popupTab }] = await listener.checkEvent("tabs.onCreated", {
+ index: 0,
+ windowId: popupWindow,
+ active: true,
+ mailTab: false,
+ });
+ window.assertDeepEqual(
+ [
+ {
+ id: popupWindow,
+ type: "popup",
+ width: 800,
+ height: 500,
+ },
+ ],
+ primedPopupWindowInfo
+ );
+
+ browser.test.log("Pause to let windows load properly.");
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, 2500));
+
+ browser.test.log("Change focused window.");
+
+ let focusInfoPromise = new Promise(resolve => {
+ let listener = windowId => {
+ browser.windows.onFocusChanged.removeListener(listener);
+ resolve(windowId);
+ };
+ browser.windows.onFocusChanged.addListener(listener);
+ });
+ let [primedFocusInfo] = await capturePrimedEvent("onFocusChanged", () =>
+ browser.windows.update(composeWindow, { focused: true })
+ );
+ let focusInfo = await focusInfoPromise;
+ let platformInfo = await browser.runtime.getPlatformInfo();
+
+ let expectedWindow = ["mac", "win"].includes(platformInfo.os)
+ ? composeWindow
+ : browser.windows.WINDOW_ID_NONE;
+ window.assertDeepEqual(expectedWindow, primedFocusInfo);
+ window.assertDeepEqual(expectedWindow, focusInfo);
+
+ browser.test.log("Close the new main window.");
+
+ let primedMainWindowRemoveInfo = await capturePrimedEvent(
+ "onRemoved",
+ () => browser.windows.remove(mainWindow)
+ );
+ await listener.checkEvent("windows.onRemoved", mainWindow);
+ await listener.checkEvent("tabs.onRemoved", mainTab, {
+ windowId: mainWindow,
+ isWindowClosing: true,
+ });
+ window.assertDeepEqual([mainWindow], primedMainWindowRemoveInfo);
+
+ browser.test.log("Close the compose window.");
+
+ let primedComposWindowRemoveInfo = await capturePrimedEvent(
+ "onRemoved",
+ () => browser.windows.remove(composeWindow)
+ );
+ await listener.checkEvent("windows.onRemoved", composeWindow);
+ await listener.checkEvent("tabs.onRemoved", composeTab, {
+ windowId: composeWindow,
+ isWindowClosing: true,
+ });
+ window.assertDeepEqual([composeWindow], primedComposWindowRemoveInfo);
+
+ browser.test.log("Close the message window.");
+
+ let primedDisplayWindowRemoveInfo = await capturePrimedEvent(
+ "onRemoved",
+ () => browser.windows.remove(displayWindow)
+ );
+ await listener.checkEvent("windows.onRemoved", displayWindow);
+ await listener.checkEvent("tabs.onRemoved", displayTab, {
+ windowId: displayWindow,
+ isWindowClosing: true,
+ });
+ window.assertDeepEqual([displayWindow], primedDisplayWindowRemoveInfo);
+
+ browser.test.log("Close the popup window.");
+
+ let primedPopupWindowRemoveInfo = await capturePrimedEvent(
+ "onRemoved",
+ () => browser.windows.remove(popupWindow)
+ );
+ await listener.checkEvent("windows.onRemoved", popupWindow);
+ await listener.checkEvent("tabs.onRemoved", popupTab, {
+ windowId: popupWindow,
+ isWindowClosing: true,
+ });
+ window.assertDeepEqual([popupWindow], primedPopupWindowRemoveInfo);
+
+ let finalWindows = await browser.windows.getAll({ populate: true });
+ browser.test.assertEq(1, finalWindows.length);
+ browser.test.assertEq(initialWindow, finalWindows[0].id);
+ browser.test.assertEq(1, finalWindows[0].tabs.length);
+ browser.test.assertEq(initialTab, finalWindows[0].tabs[0].id);
+
+ browser.test.assertEq(0, listener.tabEvents.length);
+ browser.test.assertEq(0, listener.windowEvents.length);
+ browser.test.notifyPass("finished");
+ },
+ "utils.js": await getUtilsJS(),
+ },
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["addressBooks"],
+ },
+ });
+
+ // Function to start an event page extension (MV3), which can be called whenever
+ // the main test is about to trigger an event. The extension terminates its
+ // background and listens for that single event, verifying it is waking up correctly.
+ async function event_page_extension(eventName, actionCallback) {
+ let ext = ExtensionTestUtils.loadExtension({
+ 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;
+ let eventName = browser.runtime.getManifest().description;
+
+ if (
+ ["onCreated", "onFocusChanged", "onRemoved"].includes(eventName)
+ ) {
+ browser.windows[eventName].addListener(async (...args) => {
+ // Only send the first event after background wake-up, this should
+ // be the only one expected.
+ if (!hasFired) {
+ hasFired = true;
+ browser.test.sendMessage(`${eventName} received`, args);
+ }
+ });
+ }
+
+ browser.test.sendMessage("background started");
+ },
+ },
+ manifest: {
+ manifest_version: 3,
+ description: eventName,
+ background: { scripts: ["background.js"] },
+ browser_specific_settings: {
+ gecko: { id: `windows.eventpage.${eventName}@mochi.test` },
+ },
+ },
+ });
+ await ext.startup();
+ await ext.awaitMessage("background started");
+ // The listener should be persistent, but not primed.
+ assertPersistentListeners(ext, "windows", eventName, { primed: false });
+
+ await ext.terminateBackground({ disableResetIdleForTest: true });
+ // Verify the primed persistent listener.
+ assertPersistentListeners(ext, "windows", eventName, { primed: true });
+
+ await actionCallback();
+ let rv = await ext.awaitMessage(`${eventName} received`);
+ await ext.awaitMessage("background started");
+ // The listener should be persistent, but not primed.
+ assertPersistentListeners(ext, "windows", eventName, { primed: false });
+
+ await ext.unload();
+ return rv;
+ }
+
+ extension.onMessage("openMainWindow", async () => {
+ let primedEventData = await event_page_extension("onCreated", () => {
+ return window.MsgOpenNewWindowForFolder(testFolder.URI);
+ });
+ extension.sendMessage(...primedEventData);
+ });
+
+ extension.onMessage("openDisplayWindow", async () => {
+ let primedEventData = await event_page_extension("onCreated", () => {
+ return openMessageInWindow([...testFolder.messages][0]);
+ });
+ extension.sendMessage(...primedEventData);
+ });
+
+ extension.onMessage("capturePrimedEvent", async eventName => {
+ let primedEventData = await event_page_extension(eventName, () => {
+ // Resume execution of the main test, after the event page extension has
+ // primed its event listeners.
+ extension.sendMessage();
+ });
+ extension.sendMessage(...primedEventData);
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("finished");
+ await extension.unload();
+});