summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/extensions/test/browser/head_menus.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/extensions/test/browser/head_menus.js')
-rw-r--r--comm/mail/components/extensions/test/browser/head_menus.js733
1 files changed, 733 insertions, 0 deletions
diff --git a/comm/mail/components/extensions/test/browser/head_menus.js b/comm/mail/components/extensions/test/browser/head_menus.js
new file mode 100644
index 0000000000..346c4ca044
--- /dev/null
+++ b/comm/mail/components/extensions/test/browser/head_menus.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/. */
+
+/* globals synthesizeMouseAtCenterAndRetry, awaitBrowserLoaded */
+
+"use strict";
+
+const { ExtensionPermissions } = ChromeUtils.importESModule(
+ "resource://gre/modules/ExtensionPermissions.sys.mjs"
+);
+
+const { mailTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/MailTestUtils.jsm"
+);
+
+const treeClick = mailTestUtils.treeClick.bind(null, EventUtils, window);
+
+var URL_BASE =
+ "http://mochi.test:8888/browser/comm/mail/components/extensions/test/browser/data";
+
+/**
+ * Left-click on something and wait for the context menu to appear.
+ * For elements in the parent process only.
+ *
+ * @param {Element} menu - The <menu> that should appear.
+ * @param {Element} element - The element to be clicked on.
+ * @returns {Promise} A promise that resolves when the menu appears.
+ */
+function leftClick(menu, element) {
+ let shownPromise = BrowserTestUtils.waitForEvent(menu, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(element, {}, element.ownerGlobal);
+ return shownPromise;
+}
+/**
+ * Right-click on something and wait for the context menu to appear.
+ * For elements in the parent process only.
+ *
+ * @param {Element} menu - The <menu> that should appear.
+ * @param {Element} element - The element to be clicked on.
+ * @returns {Promise} A promise that resolves when the menu appears.
+ */
+function rightClick(menu, element) {
+ let shownPromise = BrowserTestUtils.waitForEvent(menu, "popupshown");
+ EventUtils.synthesizeMouseAtCenter(
+ element,
+ { type: "contextmenu" },
+ element.ownerGlobal
+ );
+ return shownPromise;
+}
+
+/**
+ * Right-click on something in a content document and wait for the context
+ * menu to appear.
+ *
+ * @param {Element} menu - The <menu> that should appear.
+ * @param {string} selector - CSS selector of the element to be clicked on.
+ * @param {Element} browser - <browser> containing the element.
+ * @returns {Promise} A promise that resolves when the menu appears.
+ */
+async function rightClickOnContent(menu, selector, browser) {
+ let shownPromise = BrowserTestUtils.waitForEvent(menu, "popupshown");
+ await synthesizeMouseAtCenterAndRetry(
+ selector,
+ { type: "contextmenu" },
+ browser
+ );
+ return shownPromise;
+}
+
+/**
+ * Check the parameters of a browser.onShown event was fired.
+ *
+ * @see mail/components/extensions/schemas/menus.json
+ *
+ * @param extension
+ * @param {object} expectedInfo
+ * @param {Array?} expectedInfo.menuIds
+ * @param {Array?} expectedInfo.contexts
+ * @param {Array?} expectedInfo.attachments
+ * @param {object?} expectedInfo.displayedFolder
+ * @param {object?} expectedInfo.selectedFolder
+ * @param {Array?} expectedInfo.selectedMessages
+ * @param {RegExp?} expectedInfo.pageUrl
+ * @param {string?} expectedInfo.selectionText
+ * @param {object} expectedTab
+ * @param {boolean} expectedTab.active
+ * @param {integer} expectedTab.index
+ * @param {boolean} expectedTab.mailTab
+ */
+async function checkShownEvent(extension, expectedInfo, expectedTab) {
+ let [info, tab] = await extension.awaitMessage("onShown");
+ Assert.deepEqual(info.menuIds, expectedInfo.menuIds);
+ Assert.deepEqual(info.contexts, expectedInfo.contexts);
+
+ Assert.equal(
+ !!info.attachments,
+ !!expectedInfo.attachments,
+ "attachments in info"
+ );
+ if (expectedInfo.attachments) {
+ Assert.equal(info.attachments.length, expectedInfo.attachments.length);
+ for (let i = 0; i < expectedInfo.attachments.length; i++) {
+ Assert.equal(info.attachments[i].name, expectedInfo.attachments[i].name);
+ Assert.equal(info.attachments[i].size, expectedInfo.attachments[i].size);
+ }
+ }
+
+ for (let infoKey of ["displayedFolder", "selectedFolder"]) {
+ Assert.equal(
+ !!info[infoKey],
+ !!expectedInfo[infoKey],
+ `${infoKey} in info`
+ );
+ if (expectedInfo[infoKey]) {
+ Assert.equal(info[infoKey].accountId, expectedInfo[infoKey].accountId);
+ Assert.equal(info[infoKey].path, expectedInfo[infoKey].path);
+ Assert.ok(Array.isArray(info[infoKey].subFolders));
+ }
+ }
+
+ Assert.equal(
+ !!info.selectedMessages,
+ !!expectedInfo.selectedMessages,
+ "selectedMessages in info"
+ );
+ if (expectedInfo.selectedMessages) {
+ Assert.equal(info.selectedMessages.id, null);
+ Assert.equal(
+ info.selectedMessages.messages.length,
+ expectedInfo.selectedMessages.messages.length
+ );
+ for (let i = 0; i < expectedInfo.selectedMessages.messages.length; i++) {
+ Assert.equal(
+ info.selectedMessages.messages[i].subject,
+ expectedInfo.selectedMessages.messages[i].subject
+ );
+ }
+ }
+
+ Assert.equal(!!info.pageUrl, !!expectedInfo.pageUrl, "pageUrl in info");
+ if (expectedInfo.pageUrl) {
+ if (typeof expectedInfo.pageUrl == "string") {
+ Assert.equal(info.pageUrl, expectedInfo.pageUrl);
+ } else {
+ Assert.ok(info.pageUrl.match(expectedInfo.pageUrl));
+ }
+ }
+
+ Assert.equal(
+ !!info.selectionText,
+ !!expectedInfo.selectionText,
+ "selectionText in info"
+ );
+ if (expectedInfo.selectionText) {
+ Assert.equal(info.selectionText, expectedInfo.selectionText);
+ }
+
+ Assert.equal(tab.active, expectedTab.active, "tab is active");
+ Assert.equal(tab.index, expectedTab.index, "tab index");
+ Assert.equal(tab.mailTab, expectedTab.mailTab, "tab is mailTab");
+}
+
+/**
+ * Check the parameters of a browser.onClicked event was fired.
+ *
+ * @see mail/components/extensions/schemas/menus.json
+ *
+ * @param extension
+ * @param {object} expectedInfo
+ * @param {string?} expectedInfo.selectionText
+ * @param {string?} expectedInfo.linkText
+ * @param {RegExp?} expectedInfo.pageUrl
+ * @param {RegExp?} expectedInfo.linkUrl
+ * @param {RegExp?} expectedInfo.srcUrl
+ * @param {object} expectedTab
+ * @param {boolean} expectedTab.active
+ * @param {integer} expectedTab.index
+ * @param {boolean} expectedTab.mailTab
+ */
+async function checkClickedEvent(extension, expectedInfo, expectedTab) {
+ let [info, tab] = await extension.awaitMessage("onClicked");
+
+ Assert.equal(info.selectionText, expectedInfo.selectionText, "selectionText");
+ Assert.equal(info.linkText, expectedInfo.linkText, "linkText");
+ if (expectedInfo.menuItemId) {
+ Assert.equal(info.menuItemId, expectedInfo.menuItemId, "menuItemId");
+ }
+
+ for (let infoKey of ["pageUrl", "linkUrl", "srcUrl"]) {
+ Assert.equal(
+ !!info[infoKey],
+ !!expectedInfo[infoKey],
+ `${infoKey} in info`
+ );
+ if (expectedInfo[infoKey]) {
+ if (typeof expectedInfo[infoKey] == "string") {
+ Assert.equal(info[infoKey], expectedInfo[infoKey]);
+ } else {
+ Assert.ok(info[infoKey].match(expectedInfo[infoKey]));
+ }
+ }
+ }
+
+ Assert.equal(tab.active, expectedTab.active, "tab is active");
+ Assert.equal(tab.index, expectedTab.index, "tab index");
+ Assert.equal(tab.mailTab, expectedTab.mailTab, "tab is mailTab");
+}
+
+async function getMenuExtension(manifest) {
+ let details = {
+ files: {
+ "background.js": async () => {
+ let contexts = [
+ "audio",
+ "compose_action",
+ "compose_action_menu",
+ "message_display_action",
+ "message_display_action_menu",
+ "editable",
+ "frame",
+ "image",
+ "link",
+ "page",
+ "password",
+ "selection",
+ "tab",
+ "video",
+ "message_list",
+ "folder_pane",
+ "compose_attachments",
+ "compose_body",
+ "tools_menu",
+ ];
+ if (browser.runtime.getManifest().manifest_version > 2) {
+ contexts.push("action", "action_menu");
+ } else {
+ contexts.push("browser_action", "browser_action_menu");
+ }
+
+ for (let context of contexts) {
+ browser.menus.create({
+ id: context,
+ title: context,
+ contexts: [context],
+ });
+ }
+
+ browser.menus.onShown.addListener((...args) => {
+ browser.test.sendMessage("onShown", args);
+ });
+
+ browser.menus.onClicked.addListener((...args) => {
+ browser.test.sendMessage("onClicked", args);
+ });
+ browser.test.sendMessage("menus-created");
+ },
+ },
+ manifest: {
+ browser_specific_settings: {
+ gecko: {
+ id: "menus@mochi.test",
+ },
+ },
+ background: { scripts: ["background.js"] },
+ ...manifest,
+ },
+ useAddonManager: "temporary",
+ };
+
+ if (!details.manifest.permissions) {
+ details.manifest.permissions = [];
+ }
+ details.manifest.permissions.push("menus");
+ console.log(JSON.stringify(details, 2));
+ let extension = ExtensionTestUtils.loadExtension(details);
+ if (details.manifest.host_permissions) {
+ // MV3 has to manually grant the requested permission.
+ await ExtensionPermissions.add("menus@mochi.test", {
+ permissions: [],
+ origins: details.manifest.host_permissions,
+ });
+ }
+ return extension;
+}
+
+async function subtest_content(
+ extension,
+ extensionHasPermission,
+ browser,
+ pageUrl,
+ tab
+) {
+ await awaitBrowserLoaded(browser, url => url != "about:blank");
+
+ let menuId = browser.getAttribute("context");
+ let ownerDocument;
+ if (browser.ownerGlobal.parent.location.href == "about:3pane") {
+ ownerDocument = browser.ownerGlobal.parent.document;
+ } else if (menuId == "browserContext") {
+ ownerDocument = browser.ownerGlobal.top.document;
+ } else {
+ ownerDocument = browser.ownerDocument;
+ }
+ let menu = ownerDocument.getElementById(menuId);
+
+ await synthesizeMouseAtCenterAndRetry("body", {}, browser);
+
+ info("Test a part of the page with no content.");
+
+ await rightClickOnContent(menu, "body", browser);
+ Assert.ok(menu.querySelector("#menus_mochi_test-menuitem-_page"));
+ let hiddenPromise = BrowserTestUtils.waitForEvent(menu, "popuphidden");
+ menu.hidePopup();
+ await hiddenPromise;
+ // Sometimes, the popup will open then instantly disappear. It seems to
+ // still be hiding after the previous appearance. If we wait a little bit,
+ // this doesn't happen.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, 250));
+
+ await checkShownEvent(
+ extension,
+ {
+ menuIds: ["page"],
+ contexts: ["page", "all"],
+ pageUrl: extensionHasPermission ? pageUrl : undefined,
+ },
+ tab
+ );
+
+ info("Test selection.");
+
+ await SpecialPowers.spawn(browser, [], () => {
+ let text = content.document.querySelector("p");
+ content.getSelection().selectAllChildren(text);
+ });
+ await rightClickOnContent(menu, "p", browser);
+ Assert.ok(menu.querySelector("#menus_mochi_test-menuitem-_selection"));
+ await checkShownEvent(
+ extension,
+ {
+ pageUrl: extensionHasPermission ? pageUrl : undefined,
+ selectionText: extensionHasPermission ? "This is text." : undefined,
+ menuIds: ["selection"],
+ contexts: ["selection", "all"],
+ },
+ tab
+ );
+
+ hiddenPromise = BrowserTestUtils.waitForEvent(menu, "popuphidden");
+ let clickedPromise = checkClickedEvent(
+ extension,
+ {
+ pageUrl,
+ selectionText: "This is text.",
+ },
+ tab
+ );
+ menu.activateItem(
+ menu.querySelector("#menus_mochi_test-menuitem-_selection")
+ );
+ await clickedPromise;
+ await hiddenPromise;
+
+ // Sometimes, the popup will open then instantly disappear. It seems to
+ // still be hiding after the previous appearance. If we wait a little bit,
+ // this doesn't happen.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, 250));
+
+ await synthesizeMouseAtCenterAndRetry("body", {}, browser); // Select nothing.
+
+ info("Test link.");
+
+ await rightClickOnContent(menu, "a", browser);
+ Assert.ok(menu.querySelector("#menus_mochi_test-menuitem-_link"));
+ await checkShownEvent(
+ extension,
+ {
+ pageUrl: extensionHasPermission ? pageUrl : undefined,
+ menuIds: ["link"],
+ contexts: ["link", "all"],
+ },
+ tab
+ );
+
+ hiddenPromise = BrowserTestUtils.waitForEvent(menu, "popuphidden");
+ clickedPromise = checkClickedEvent(
+ extension,
+ {
+ pageUrl,
+ linkUrl: "http://mochi.test:8888/",
+ linkText: "This is a link with text.",
+ },
+ tab
+ );
+ menu.activateItem(menu.querySelector("#menus_mochi_test-menuitem-_link"));
+ await clickedPromise;
+ await hiddenPromise;
+ // Sometimes, the popup will open then instantly disappear. It seems to
+ // still be hiding after the previous appearance. If we wait a little bit,
+ // this doesn't happen.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, 250));
+
+ info("Test image.");
+
+ await rightClickOnContent(menu, "img", browser);
+ Assert.ok(menu.querySelector("#menus_mochi_test-menuitem-_image"));
+ await checkShownEvent(
+ extension,
+ {
+ pageUrl: extensionHasPermission ? pageUrl : undefined,
+ menuIds: ["image"],
+ contexts: ["image", "all"],
+ },
+ tab
+ );
+
+ hiddenPromise = BrowserTestUtils.waitForEvent(menu, "popuphidden");
+ clickedPromise = checkClickedEvent(
+ extension,
+ {
+ pageUrl,
+ srcUrl: `${URL_BASE}/tb-logo.png`,
+ },
+ tab
+ );
+ menu.activateItem(menu.querySelector("#menus_mochi_test-menuitem-_image"));
+ await clickedPromise;
+ await hiddenPromise;
+ // Sometimes, the popup will open then instantly disappear. It seems to
+ // still be hiding after the previous appearance. If we wait a little bit,
+ // this doesn't happen.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, 250));
+}
+
+async function openExtensionSubMenu(menu) {
+ // The extension submenu ends with a number, which increases over time, but it
+ // does not have a underscore.
+ let submenu;
+ for (let item of menu.querySelectorAll("[id^=menus_mochi_test-menuitem-]")) {
+ if (!item.id.includes("-_")) {
+ submenu = item;
+ break;
+ }
+ }
+ Assert.ok(submenu, `Found submenu: ${submenu.id}`);
+
+ // Open submenu.
+ let submenuPromise = BrowserTestUtils.waitForEvent(menu, "popupshown");
+ submenu.openMenu(true);
+ await submenuPromise;
+
+ return submenu;
+}
+
+async function subtest_compose_body(
+ extension,
+ extensionHasPermission,
+ browser,
+ pageUrl,
+ tab
+) {
+ await awaitBrowserLoaded(browser, url => url != "about:blank");
+
+ let ownerDocument = browser.ownerDocument;
+ let menu = ownerDocument.getElementById(browser.getAttribute("context"));
+
+ await synthesizeMouseAtCenterAndRetry("body", {}, browser);
+
+ info("Test a part of the page with no content.");
+ {
+ await rightClickOnContent(menu, "body", browser);
+ Assert.ok(menu.querySelector(`#menus_mochi_test-menuitem-_compose_body`));
+ Assert.ok(menu.querySelector(`#menus_mochi_test-menuitem-_editable`));
+ let hiddenPromise = BrowserTestUtils.waitForEvent(menu, "popuphidden");
+ menu.hidePopup();
+ await hiddenPromise;
+ // Sometimes, the popup will open then instantly disappear. It seems to
+ // still be hiding after the previous appearance. If we wait a little bit,
+ // this doesn't happen.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, 250));
+
+ await checkShownEvent(
+ extension,
+ {
+ menuIds: ["editable", "compose_body"],
+ contexts: ["editable", "compose_body", "all"],
+ pageUrl: extensionHasPermission ? pageUrl : undefined,
+ },
+ tab
+ );
+ }
+
+ info("Test selection.");
+ {
+ await SpecialPowers.spawn(browser, [], () => {
+ let text = content.document.querySelector("p");
+ content.getSelection().selectAllChildren(text);
+ });
+
+ await rightClickOnContent(menu, "p", browser);
+ let submenu = await openExtensionSubMenu(menu);
+
+ await checkShownEvent(
+ extension,
+ {
+ pageUrl: extensionHasPermission ? pageUrl : undefined,
+ selectionText: extensionHasPermission ? "This is text." : undefined,
+ menuIds: ["editable", "selection", "compose_body"],
+ contexts: ["editable", "selection", "compose_body", "all"],
+ },
+ tab
+ );
+ Assert.ok(submenu.querySelector("#menus_mochi_test-menuitem-_selection"));
+ Assert.ok(
+ submenu.querySelector("#menus_mochi_test-menuitem-_compose_body")
+ );
+ Assert.ok(submenu.querySelector("#menus_mochi_test-menuitem-_editable"));
+
+ let hiddenPromise = BrowserTestUtils.waitForEvent(submenu, "popuphidden");
+ let clickedPromise = checkClickedEvent(
+ extension,
+ {
+ pageUrl,
+ selectionText: "This is text.",
+ },
+ tab
+ );
+ menu.activateItem(
+ submenu.querySelector("#menus_mochi_test-menuitem-_selection")
+ );
+ await clickedPromise;
+ await hiddenPromise;
+
+ // Sometimes, the popup will open then instantly disappear. It seems to
+ // still be hiding after the previous appearance. If we wait a little bit,
+ // this doesn't happen.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, 250));
+ await synthesizeMouseAtCenterAndRetry("body", {}, browser); // Select nothing.
+ }
+
+ info("Test link.");
+ {
+ await rightClickOnContent(menu, "a", browser);
+ let submenu = await openExtensionSubMenu(menu);
+
+ await checkShownEvent(
+ extension,
+ {
+ pageUrl: extensionHasPermission ? pageUrl : undefined,
+ menuIds: ["editable", "link", "compose_body"],
+ contexts: ["editable", "link", "compose_body", "all"],
+ },
+ tab
+ );
+ Assert.ok(submenu.querySelector("#menus_mochi_test-menuitem-_link"));
+ Assert.ok(submenu.querySelector("#menus_mochi_test-menuitem-_editable"));
+ Assert.ok(
+ submenu.querySelector("#menus_mochi_test-menuitem-_compose_body")
+ );
+
+ let hiddenPromise = BrowserTestUtils.waitForEvent(submenu, "popuphidden");
+ let clickedPromise = checkClickedEvent(
+ extension,
+ {
+ pageUrl,
+ linkUrl: "http://mochi.test:8888/",
+ linkText: "This is a link with text.",
+ },
+ tab
+ );
+ menu.activateItem(
+ submenu.querySelector("#menus_mochi_test-menuitem-_link")
+ );
+ await clickedPromise;
+ await hiddenPromise;
+
+ // Sometimes, the popup will open then instantly disappear. It seems to
+ // still be hiding after the previous appearance. If we wait a little bit,
+ // this doesn't happen.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, 250));
+ await synthesizeMouseAtCenterAndRetry("body", {}, browser); // Select nothing.
+ }
+
+ info("Test image.");
+ {
+ await rightClickOnContent(menu, "img", browser);
+ let submenu = await openExtensionSubMenu(menu);
+
+ await checkShownEvent(
+ extension,
+ {
+ pageUrl: extensionHasPermission ? pageUrl : undefined,
+ menuIds: ["editable", "image", "compose_body"],
+ contexts: ["editable", "image", "compose_body", "all"],
+ },
+ tab
+ );
+ Assert.ok(submenu.querySelector("#menus_mochi_test-menuitem-_image"));
+ Assert.ok(submenu.querySelector("#menus_mochi_test-menuitem-_editable"));
+ Assert.ok(
+ submenu.querySelector("#menus_mochi_test-menuitem-_compose_body")
+ );
+
+ let hiddenPromise = BrowserTestUtils.waitForEvent(menu, "popuphidden");
+ let clickedPromise = checkClickedEvent(
+ extension,
+ {
+ pageUrl,
+ srcUrl: `${URL_BASE}/tb-logo.png`,
+ },
+ tab
+ );
+ menu.activateItem(
+ submenu.querySelector("#menus_mochi_test-menuitem-_image")
+ );
+ await clickedPromise;
+ await hiddenPromise;
+
+ // Sometimes, the popup will open then instantly disappear. It seems to
+ // still be hiding after the previous appearance. If we wait a little bit,
+ // this doesn't happen.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, 250));
+ await synthesizeMouseAtCenterAndRetry("body", {}, browser); // Select nothing.
+ }
+}
+
+// Test UI elements which have been made accessible for the menus API.
+// Assumed to be run after subtest_content, so we know everything has finished
+// loading.
+async function subtest_element(
+ extension,
+ extensionHasPermission,
+ element,
+ pageUrl,
+ tab
+) {
+ for (let selectedTest of [false, true]) {
+ element.focus();
+ if (selectedTest) {
+ element.value = "This is selected text.";
+ element.select();
+ } else {
+ element.value = "";
+ }
+
+ let event = await rightClick(element.ownerGlobal, element);
+ let menu = event.target;
+ let trigger = menu.triggerNode;
+ let menuitem = menu.querySelector("#menus_mochi_test-menuitem-_editable");
+ Assert.equal(
+ element.id,
+ trigger.id,
+ "Contextmenu of correct element has been triggered."
+ );
+ Assert.equal(
+ menuitem.id,
+ "menus_mochi_test-menuitem-_editable",
+ "Contextmenu includes menu."
+ );
+
+ await checkShownEvent(
+ extension,
+ {
+ menuIds: selectedTest ? ["editable", "selection"] : ["editable"],
+ contexts: selectedTest
+ ? ["editable", "selection", "all"]
+ : ["editable", "all"],
+ pageUrl: extensionHasPermission ? pageUrl : undefined,
+ selectionText:
+ extensionHasPermission && selectedTest
+ ? "This is selected text."
+ : undefined,
+ },
+ tab
+ );
+
+ // With text being selected, there will be two "context" entries in an
+ // extension submenu. Open the submenu.
+ let submenu = null;
+ if (selectedTest) {
+ for (let foundMenu of menu.querySelectorAll(
+ "[id^='menus_mochi_test-menuitem-']"
+ )) {
+ if (!foundMenu.id.startsWith("menus_mochi_test-menuitem-_")) {
+ submenu = foundMenu;
+ }
+ }
+ Assert.ok(submenu, "Submenu found.");
+ let submenuPromise = BrowserTestUtils.waitForEvent(
+ element.ownerGlobal,
+ "popupshown"
+ );
+ submenu.openMenu(true);
+ await submenuPromise;
+ }
+
+ let hiddenPromise = BrowserTestUtils.waitForEvent(
+ element.ownerGlobal,
+ "popuphidden"
+ );
+ let clickedPromise = checkClickedEvent(
+ extension,
+ {
+ pageUrl,
+ selectionText: selectedTest ? "This is selected text." : undefined,
+ },
+ tab
+ );
+ if (submenu) {
+ submenu.menupopup.activateItem(menuitem);
+ } else {
+ menu.activateItem(menuitem);
+ }
+ await clickedPromise;
+ await hiddenPromise;
+
+ // Sometimes, the popup will open then instantly disappear. It seems to
+ // still be hiding after the previous appearance. If we wait a little bit,
+ // this doesn't happen.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, 250));
+ }
+}