Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Errors

"use strict";
const { AddonTestUtils } = ChromeUtils.importESModule(
);
const { ExtensionPermissions, QuarantinedDomains } = ChromeUtils.importESModule(
);
AddonTestUtils.initMochitest(this);
loadTestSubscript("head_unified_extensions.js");
const RED =
"iVBORw0KGgoAAAANSUhEUgAAANwAAADcCAYAAAAbWs+BAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gIUARQAHY8+4wAAApBJREFUeNrt3cFqAjEUhlEjvv8rXzciiiBGk/He5JxdN2U649dY+KmnEwAAAAAv2uMXEeGOwERntwAEB4IDBAeCAwQHggPBAYIDwQGCA8GB4ADBgeAAwYHgAMGB4EBwgOCgpkuKq2it/r8Li2hbvGKqP6s/PycnHHv9YvSWEgQHCA4EBwgOBAeCAwQHggMEByXM+QRUE6D3suwuPafDn5MTDg50KXnVPSdxa54y/oYDwQGCA8EBggPBAYIDwYHggBE+X5rY3Y3Tey97Nn2eU+rnlGfaZa6Ft5SA4EBwgOBAcCA4QHAgOEBwIDjgZu60y1xrDPtIJxwgOBAcIDgQHAgOEBwIDhAcCA4EBwgOBAcIDgQHCA4EB4IDBAeCAwQHggPBAYIDwQGCA8GB4ADBgeAAwYHgAMGB4GADcz9y2McIgxMOBAeCAwQHggMEB4IDwQGCA8EBggPBATdP6+KIGPRdW7i1LCFi6ALfCQfeUoLgAMGB4ADBgeBAcIDgQHCA4CCdOVvK7quwveQgg7eRTjjwlhIQHAgOBAcIDgQHCA4EB4IDBAfl5dhSdl+17SX3F22rdLlOOBAcCA4QHAgOEBwIDgQHCA4EBwgO0qm5pez6Ce0uSym2jXTCgeAAwYHgQHCA4EBwgOBAcCA4QHBQ3vpbyu47Yns51OLbSCccCA4QHAgOBAcIDgQHCA4EB4ID5jDt+vkObjgFM9dywoHgAMGB4EBwgOBAcIDgQHAgOEBwsA5bysPveMLtpW2kEw4EBwgOBAcIDgQHggMEB4IDBAeCg33ZUqZ/Ql9sL20jnXCA4EBwIDhAcCA4QHAgOBAcIDgQHNOZai3DlhKccCA4QHAgOEBwIDgQHCA4AAAAAGA1VyxaWIohrgXFAAAAAElFTkSuQmCC";
const l10n = new Localization(
["branding/brand.ftl", "browser/extensionsUI.ftl"],
true
);
async function makeExtension({
useAddonManager = "temporary",
manifest_version = 3,
id,
permissions,
host_permissions,
content_scripts,
granted,
default_area,
}) {
info(
`Loading extension ` +
JSON.stringify({ id, permissions, host_permissions, granted })
);
let manifest = {
manifest_version,
browser_specific_settings: { gecko: { id } },
permissions,
host_permissions,
content_scripts,
action: {
default_popup: "popup.html",
default_area: default_area || "navbar",
},
icons: {
16: "red.png",
},
};
if (manifest_version < 3) {
manifest.browser_action = manifest.action;
delete manifest.action;
}
let ext = ExtensionTestUtils.loadExtension({
manifest,
useAddonManager,
async background() {
browser.permissions.onAdded.addListener(({ origins }) => {
browser.test.sendMessage("granted", origins.join());
});
browser.permissions.onRemoved.addListener(({ origins }) => {
browser.test.sendMessage("revoked", origins.join());
});
browser.runtime.onInstalled.addListener(async () => {
if (browser.menus) {
let submenu = browser.menus.create({
id: "parent",
title: "submenu",
contexts: ["action"],
});
browser.menus.create({
id: "child1",
title: "child1",
parentId: submenu,
});
await new Promise(resolve => {
browser.menus.create(
{
id: "child2",
title: "child2",
parentId: submenu,
},
resolve
);
});
}
browser.test.sendMessage("ready");
});
},
files: {
"red.png": imageBufferFromDataURI(RED),
"popup.html": `<!DOCTYPE html><meta charset=utf-8>Test Popup`,
},
});
if (granted) {
info("Granting initial permissions.");
await ExtensionPermissions.add(id, { permissions: [], origins: granted });
}
await ext.startup();
await ext.awaitMessage("ready");
return ext;
}
async function testQuarantinePopup(popup) {
let [title, line1, line2] = await l10n.formatMessages([
{
id: "webext-quarantine-confirmation-title",
args: { addonName: "Generated extension" },
},
"webext-quarantine-confirmation-line-1",
"webext-quarantine-confirmation-line-2",
]);
let [titleEl, , helpEl] = popup.querySelectorAll("description");
ok(popup.getAttribute("icon").endsWith("/red.png"), "Correct icon.");
is(title.value, titleEl.textContent, "Correct title.");
is(line1.value + "\n\n" + line2.value, helpEl.textContent, "Correct lines.");
}
async function testOriginControls(
extension,
{ contextMenuId },
{
items,
selected,
click,
granted,
revoked,
attention,
quarantined,
allowQuarantine,
}
) {
info(
`Testing ${extension.id} on ${gBrowser.currentURI.spec} with contextMenuId=${contextMenuId}.`
);
let buttonOrWidget;
let menu;
let nextMenuItemClassName;
switch (contextMenuId) {
case "toolbar-context-menu":
let target = `#${CSS.escape(makeWidgetId(extension.id))}-BAP`;
buttonOrWidget = document.querySelector(target).parentElement;
menu = await openChromeContextMenu(contextMenuId, target);
nextMenuItemClassName = "customize-context-manageExtension";
break;
case "unified-extensions-context-menu":
await openExtensionsPanel();
buttonOrWidget = getUnifiedExtensionsItem(extension.id);
menu = await openUnifiedExtensionsContextMenu(extension.id);
nextMenuItemClassName = "unified-extensions-context-menu-pin-to-toolbar";
break;
default:
throw new Error(`unexpected context menu "${contextMenuId}"`);
}
let doc = menu.ownerDocument;
let visibleOriginItems = menu.querySelectorAll(
":is(menuitem, menuseparator):not([hidden])"
);
info("Check expected menu items.");
for (let i = 0; i < items.length; i++) {
let l10n = doc.l10n.getAttributes(visibleOriginItems[i]);
Assert.deepEqual(
l10n,
items[i],
`Visible menu item ${i} has correct l10n attrs.`
);
let checked = visibleOriginItems[i].getAttribute("checked") === "true";
is(i === selected, checked, `Expected checked value for item ${i}.`);
}
if (items.length) {
is(
visibleOriginItems[items.length].nodeName,
"menuseparator",
"Found separator."
);
is(
visibleOriginItems[items.length + 1].className,
nextMenuItemClassName,
"All items accounted for."
);
}
is(
buttonOrWidget.hasAttribute("attention"),
!!attention,
"Expected attention badge before clicking."
);
Assert.deepEqual(
document.l10n.getAttributes(
buttonOrWidget.querySelector(".unified-extensions-item-action-button")
),
{
// eslint-disable-next-line no-nested-ternary
id: attention
? quarantined
? "origin-controls-toolbar-button-quarantined"
: "origin-controls-toolbar-button-permission-needed"
: "origin-controls-toolbar-button",
args: {
extensionTitle: "Generated extension",
},
},
"Correct l10n message."
);
let itemToClick;
if (click) {
itemToClick = visibleOriginItems[click];
}
let quarantinePopup;
if (itemToClick && quarantined) {
quarantinePopup = promisePopupNotificationShown("addon-webext-permissions");
}
// Clicking a menu item of the unified extensions context menu should close
// the unified extensions panel automatically.
let panelHidden =
itemToClick && contextMenuId === "unified-extensions-context-menu"
? BrowserTestUtils.waitForEvent(document, "popuphidden", true)
: Promise.resolve();
await closeChromeContextMenu(contextMenuId, itemToClick);
await panelHidden;
// When there is no menu item to close, we should manually close the unified
// extensions panel because simply closing the context menu will not close
// it.
if (!itemToClick && contextMenuId === "unified-extensions-context-menu") {
await closeExtensionsPanel();
}
if (granted) {
info("Waiting for the permissions.onAdded event.");
let host = await extension.awaitMessage("granted");
is(host, granted.join(), "Expected host permission granted.");
}
if (revoked) {
info("Waiting for the permissions.onRemoved event.");
let host = await extension.awaitMessage("revoked");
is(host, revoked.join(), "Expected host permission revoked.");
}
if (quarantinePopup) {
let popup = await quarantinePopup;
await testQuarantinePopup(popup);
if (allowQuarantine) {
popup.button.click();
} else {
popup.secondaryButton.click();
}
}
}
// Move the widget to the toolbar or the addons panel (if Unified Extensions
// is enabled) or the overflow panel otherwise.
function moveWidget(ext, pinToToolbar = false) {
let area = pinToToolbar
? CustomizableUI.AREA_NAVBAR
: CustomizableUI.AREA_ADDONS;
let widgetId = `${makeWidgetId(ext.id)}-browser-action`;
CustomizableUI.addWidgetToArea(widgetId, area);
}
const originControlsInContextMenu = async options => {
// Has no permissions.
let ext1 = await makeExtension({ id: "ext1@test" });
// Has activeTab and (ungranted) example.com permissions.
let ext2 = await makeExtension({
id: "ext2@test",
permissions: ["activeTab"],
host_permissions: ["*://example.com/*"],
useAddonManager: "permanent",
});
// Has ungranted <all_urls>, and granted example.com.
let ext3 = await makeExtension({
id: "ext3@test",
host_permissions: ["<all_urls>"],
granted: ["*://example.com/*"],
useAddonManager: "permanent",
});
// Has granted <all_urls>.
let ext4 = await makeExtension({
id: "ext4@test",
host_permissions: ["<all_urls>"],
granted: ["<all_urls>"],
useAddonManager: "permanent",
});
// MV2 extension with an <all_urls> content script and activeTab.
let ext5 = await makeExtension({
manifest_version: 2,
id: "ext5@test",
permissions: ["activeTab"],
content_scripts: [
{
matches: ["<all_urls>"],
css: [],
},
],
useAddonManager: "permanent",
});
// Add an extension always visible in the extensions panel.
let ext6 = await makeExtension({
id: "ext6@test",
default_area: "menupanel",
});
let extensions = [ext1, ext2, ext3, ext4, ext5, ext6];
let unifiedButton;
if (options.contextMenuId === "unified-extensions-context-menu") {
moveWidget(ext1, false);
moveWidget(ext2, false);
moveWidget(ext3, false);
moveWidget(ext4, false);
moveWidget(ext5, false);
unifiedButton = document.querySelector("#unified-extensions-button");
} else {
// TestVerify runs this again in the same Firefox instance, so move the
// widgets back to the toolbar for testing outside the unified extensions
// panel.
moveWidget(ext1, true);
moveWidget(ext2, true);
moveWidget(ext3, true);
moveWidget(ext4, true);
moveWidget(ext5, true);
}
const NO_ACCESS = { id: "origin-controls-no-access", args: null };
const QUARANTINED = {
id: "origin-controls-quarantined-status",
args: null,
};
const ALLOW_QUARANTINED = {
id: "origin-controls-quarantined-allow",
args: null,
};
const ACCESS_OPTIONS = { id: "origin-controls-options", args: null };
const ALL_SITES = { id: "origin-controls-option-all-domains", args: null };
const WHEN_CLICKED = {
id: "origin-controls-option-when-clicked",
args: null,
};
const UNIFIED_NO_ATTENTION = { id: "unified-extensions-button", args: null };
const UNIFIED_ATTENTION = {
id: "unified-extensions-button-permissions-needed",
args: null,
};
const UNIFIED_QUARANTINED = {
id: "unified-extensions-button-quarantined",
args: null,
};
await BrowserTestUtils.withNewTab("about:blank", async () => {
await testOriginControls(ext1, options, { items: [NO_ACCESS] });
await testOriginControls(ext2, options, { items: [NO_ACCESS] });
await testOriginControls(ext3, options, { items: [NO_ACCESS] });
await testOriginControls(ext4, options, { items: [NO_ACCESS] });
await testOriginControls(ext5, options, { items: [] });
if (unifiedButton) {
ok(
!unifiedButton.hasAttribute("attention"),
"No extension will have attention indicator on about:blank."
);
Assert.deepEqual(
document.l10n.getAttributes(unifiedButton),
UNIFIED_NO_ATTENTION,
"Unified button has no permissions needed tooltip."
);
}
});
await BrowserTestUtils.withNewTab("http://mochi.test:8888/", async () => {
const ALWAYS_ON = {
id: "origin-controls-option-always-on",
args: { domain: "mochi.test" },
};
await testOriginControls(ext1, options, { items: [NO_ACCESS] });
// Has activeTab.
await testOriginControls(ext2, options, {
items: [ACCESS_OPTIONS, WHEN_CLICKED],
selected: 1,
attention: true,
});
// Could access mochi.test when clicked.
await testOriginControls(ext3, options, {
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
selected: 1,
attention: true,
});
// Has <all_urls> granted.
await testOriginControls(ext4, options, {
items: [ACCESS_OPTIONS, ALL_SITES],
selected: 1,
attention: false,
});
// MV2 extension, has no origin controls, and never flags for attention.
await testOriginControls(ext5, options, { items: [], attention: false });
if (unifiedButton) {
ok(
unifiedButton.hasAttribute("attention"),
"Both ext2 and ext3 are WHEN_CLICKED for example.com, so show attention indicator."
);
Assert.deepEqual(
document.l10n.getAttributes(unifiedButton),
UNIFIED_ATTENTION,
"UEB has permissions needed tooltip."
);
}
});
info("Testing again with mochi.test now quarantined.");
await SpecialPowers.pushPrefEnv({
set: [
["extensions.quarantinedDomains.enabled", true],
["extensions.quarantinedDomains.list", "mochi.test"],
],
});
// Reset quarantined state between test runs.
QuarantinedDomains.setUserAllowedAddonIdPref(ext2.id, false);
QuarantinedDomains.setUserAllowedAddonIdPref(ext4.id, false);
QuarantinedDomains.setUserAllowedAddonIdPref(ext5.id, false);
await BrowserTestUtils.withNewTab("http://mochi.test:8888/", async () => {
await testOriginControls(ext1, options, {
items: [NO_ACCESS],
attention: false,
});
await testOriginControls(ext2, options, {
items: [QUARANTINED, ALLOW_QUARANTINED],
attention: true,
quarantined: true,
click: 1,
allowQuarantine: false,
});
// Still quarantined.
await testOriginControls(ext2, options, {
items: [QUARANTINED, ALLOW_QUARANTINED],
attention: true,
quarantined: true,
click: 1,
allowQuarantine: true,
});
// Not quarantined anymore.
await testOriginControls(ext2, options, {
items: [ACCESS_OPTIONS, WHEN_CLICKED],
selected: 1,
attention: true,
quarantined: false,
});
await testOriginControls(ext3, options, {
items: [QUARANTINED, ALLOW_QUARANTINED],
attention: true,
quarantined: true,
});
await testOriginControls(ext4, options, {
items: [QUARANTINED, ALLOW_QUARANTINED],
attention: true,
quarantined: true,
click: 1,
allowQuarantine: true,
});
await testOriginControls(ext4, options, {
items: [ACCESS_OPTIONS, ALL_SITES],
selected: 1,
attention: false,
quarantined: false,
});
// MV2 normally don't have controls, but we always show for quarantined.
await testOriginControls(ext5, options, {
items: [QUARANTINED, ALLOW_QUARANTINED],
attention: true,
quarantined: true,
click: 1,
allowQuarantine: true,
});
await testOriginControls(ext5, options, {
items: [],
attention: false,
quarantined: false,
});
if (unifiedButton) {
ok(unifiedButton.hasAttribute("attention"), "Expected attention UI");
Assert.deepEqual(
document.l10n.getAttributes(unifiedButton),
UNIFIED_QUARANTINED,
"Expected attention tooltip text for quarantined domains"
);
}
});
if (unifiedButton) {
extensions.forEach(extension =>
moveWidget(extension, /* pinToToolbar */ true)
);
await BrowserTestUtils.withNewTab("http://mochi.test:8888/", async () => {
ok(unifiedButton.hasAttribute("attention"), "Expected attention UI");
Assert.deepEqual(
document.l10n.getAttributes(unifiedButton),
UNIFIED_QUARANTINED,
"Expected attention tooltip text for quarantined domains"
);
await openExtensionsPanel();
const messages = getMessageBars();
Assert.equal(messages.length, 1, "expected a message");
const supportLink = messages[0].querySelector("a");
Assert.equal(
supportLink.getAttribute("support-page"),
"quarantined-domains",
"Expected the correct support page ID"
);
await closeExtensionsPanel();
});
extensions.forEach(extension =>
moveWidget(extension, /* pinToToolbar */ false)
);
}
await SpecialPowers.popPrefEnv();
await BrowserTestUtils.withNewTab("http://example.com/", async () => {
const ALWAYS_ON = {
id: "origin-controls-option-always-on",
args: { domain: "example.com" },
};
await testOriginControls(ext1, options, { items: [NO_ACCESS] });
// Click alraedy selected options, expect no permission changes.
await testOriginControls(ext2, options, {
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
selected: 1,
click: 1,
attention: true,
});
await testOriginControls(ext3, options, {
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
selected: 2,
click: 2,
attention: false,
});
await testOriginControls(ext4, options, {
items: [ACCESS_OPTIONS, ALL_SITES],
selected: 1,
click: 1,
attention: false,
});
await testOriginControls(ext5, options, { items: [], attention: false });
if (unifiedButton) {
ok(
unifiedButton.hasAttribute("attention"),
"ext2 is WHEN_CLICKED for example.com, show attention indicator."
);
Assert.deepEqual(
document.l10n.getAttributes(unifiedButton),
UNIFIED_ATTENTION,
"UEB attention for only one extension."
);
}
// Click the other option, expect example.com permission granted/revoked.
await testOriginControls(ext2, options, {
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
selected: 1,
click: 2,
granted: ["*://example.com/*"],
attention: true,
});
if (unifiedButton) {
ok(
!unifiedButton.hasAttribute("attention"),
"Bot ext2 and ext3 are ALWAYS_ON for example.com, so no attention indicator."
);
Assert.deepEqual(
document.l10n.getAttributes(unifiedButton),
UNIFIED_NO_ATTENTION,
"Unified button has no permissions needed tooltip."
);
}
await testOriginControls(ext3, options, {
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
selected: 2,
click: 1,
revoked: ["*://example.com/*"],
attention: false,
});
if (unifiedButton) {
ok(
unifiedButton.hasAttribute("attention"),
"ext3 is now WHEN_CLICKED for example.com, show attention indicator."
);
Assert.deepEqual(
document.l10n.getAttributes(unifiedButton),
UNIFIED_ATTENTION,
"UEB attention for only one extension."
);
}
// Other option is now selected.
await testOriginControls(ext2, options, {
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
selected: 2,
attention: false,
});
await testOriginControls(ext3, options, {
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
selected: 1,
attention: true,
});
if (unifiedButton) {
ok(
unifiedButton.hasAttribute("attention"),
"Still showing the attention indicator."
);
Assert.deepEqual(
document.l10n.getAttributes(unifiedButton),
UNIFIED_ATTENTION,
"UEB attention for only one extension."
);
}
});
// Regression test for Bug 1861002.
const addonListener = {
registered: false,
onPropertyChanged(addon, changedProps) {
ok(
addon,
`onPropertyChanged should not be called without an AddonWrapper for changed properties: ${changedProps}`
);
},
};
AddonManager.addAddonListener(addonListener);
addonListener.registered = true;
const unregisterAddonListener = () => {
if (!addonListener.registered) {
return;
}
AddonManager.removeAddonListener(addonListener);
addonListener.registered = false;
};
registerCleanupFunction(unregisterAddonListener);
let { messages } = await AddonTestUtils.promiseConsoleOutput(async () => {
await Promise.all(extensions.map(e => e.unload()));
});
unregisterAddonListener();
AddonTestUtils.checkMessages(
messages,
{
forbidden: [
{
message:
/AddonListener threw exception when calling onPropertyChanged/,
},
],
},
"Expect no exception raised from AddonListener onPropertyChanged callbacks"
);
};
add_task(async function originControls_in_browserAction_contextMenu() {
await originControlsInContextMenu({ contextMenuId: "toolbar-context-menu" });
});
add_task(async function originControls_in_unifiedExtensions_contextMenu() {
await originControlsInContextMenu({
contextMenuId: "unified-extensions-context-menu",
});
});
add_task(async function test_attention_dot_when_pinning_extension() {
const extension = await makeExtension({ permissions: ["activeTab"] });
await extension.startup();
const unifiedButton = document.querySelector("#unified-extensions-button");
const extensionWidgetID = AppUiTestInternals.getBrowserActionWidgetId(
extension.id
);
const extensionWidget =
CustomizableUI.getWidget(extensionWidgetID).forWindow(window).node;
await BrowserTestUtils.withNewTab("http://mochi.test:8888/", async () => {
// The extensions should be placed in the navbar by default so we do not
// expect an attention dot on the Unifed Extensions Button (UEB), only on
// the extension (widget) itself.
ok(
!unifiedButton.hasAttribute("attention"),
"expected no attention attribute on the UEB"
);
ok(
extensionWidget.hasAttribute("attention"),
"expected attention attribute on the extension widget"
);
// Open the context menu of the extension and unpin the extension.
let contextMenu = await openChromeContextMenu(
"toolbar-context-menu",
`#${CSS.escape(extensionWidgetID)}`
);
let pinToToolbar = contextMenu.querySelector(
".customize-context-pinToToolbar"
);
ok(pinToToolbar, "expected a 'Pin to Toolbar' menu item");
// Passing the `pinToToolbar` item to `closeChromeContextMenu()` will
// activate it before closing the context menu.
await closeChromeContextMenu(contextMenu.id, pinToToolbar);
ok(
unifiedButton.hasAttribute("attention"),
"expected attention attribute on the UEB"
);
// We still expect the attention dot on the extension.
ok(
extensionWidget.hasAttribute("attention"),
"expected attention attribute on the extension widget"
);
// Now let's open the unified extensions panel, and pin the same extension
// to the toolbar, which should hide the attention dot on the UEB again.
await openExtensionsPanel();
contextMenu = await openUnifiedExtensionsContextMenu(extension.id);
pinToToolbar = contextMenu.querySelector(
".unified-extensions-context-menu-pin-to-toolbar"
);
ok(pinToToolbar, "expected a 'Pin to Toolbar' menu item");
const hidden = BrowserTestUtils.waitForEvent(
gUnifiedExtensions.panel,
"popuphidden",
true
);
contextMenu.activateItem(pinToToolbar);
await hidden;
ok(
!unifiedButton.hasAttribute("attention"),
"expected no attention attribute on the UEB"
);
// We still expect the attention dot on the extension.
ok(
extensionWidget.hasAttribute("attention"),
"expected attention attribute on the extension widget"
);
});
await extension.unload();
});
async function testWithSubmenu(menu, nextItemClassName) {
function expectMenuItems() {
info("Checking expected menu items.");
let [submenu, sep1, ocMessage, sep2, next] = menu.children;
is(submenu.tagName, "menu", "First item is a submenu.");
is(submenu.label, "submenu", "Submenu has the expected label.");
is(sep1.tagName, "menuseparator", "Second item is a separator.");
let l10n = menu.ownerDocument.l10n.getAttributes(ocMessage);
is(ocMessage.tagName, "menuitem", "Third is origin controls message.");
is(l10n.id, "origin-controls-no-access", "Expected l10n id.");
is(sep2.tagName, "menuseparator", "Fourth item is a separator.");
is(next.className, nextItemClassName, "All items accounted for.");
}
const [submenu] = menu.children;
const popup = submenu.querySelector("menupopup");
// Open and close the submenu repeatedly a few times.
for (let i = 0; i < 3; i++) {
expectMenuItems();
const popupShown = BrowserTestUtils.waitForEvent(popup, "popupshown");
submenu.openMenu(true);
await popupShown;
expectMenuItems();
const popupHidden = BrowserTestUtils.waitForEvent(popup, "popuphidden");
submenu.openMenu(false);
await popupHidden;
}
menu.hidePopup();
}
add_task(async function test_originControls_with_submenus() {
let extension = await makeExtension({
id: "submenus@test",
permissions: ["menus"],
});
await BrowserTestUtils.withNewTab("about:blank", async () => {
info(`Testing with submenus.`);
moveWidget(extension, true);
let target = `#${CSS.escape(makeWidgetId(extension.id))}-BAP`;
await testWithSubmenu(
await openChromeContextMenu("toolbar-context-menu", target),
"customize-context-manageExtension"
);
info(`Testing with submenus inside extensions panel.`);
moveWidget(extension, false);
await openExtensionsPanel();
await testWithSubmenu(
await openUnifiedExtensionsContextMenu(extension.id),
"unified-extensions-context-menu-pin-to-toolbar"
);
await closeExtensionsPanel();
});
await extension.unload();
});