Bug 1782203 - Unbreak existing context menu tests for Unified Extensions UI mode. r=willdurand,extension-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D161337
This commit is contained in:
Mike Conley 2022-11-15 15:02:09 +00:00
parent eee9638cbe
commit 2920088efe
5 changed files with 230 additions and 101 deletions

View File

@ -322,11 +322,16 @@ async function browseraction_contextmenu_manage_extension_helper(win) {
checkVisibility(toolbarCtxMenu, false);
toolbarCtxMenu.hidePopup();
info("Pin the browserAction and another button to the overflow menu");
CustomizableUI.addWidgetToArea(
nodeId,
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
);
// Pinning browser actions to the overflow panel isn't going to be possible
// after bug 1798896.
if (!win.gUnifiedExtensions.isEnabled) {
info("Pin a browserAction to the overflow menu");
CustomizableUI.addWidgetToArea(
nodeId,
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
);
}
CustomizableUI.addWidgetToArea(
otherButtonId,
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
@ -354,11 +359,13 @@ async function browseraction_contextmenu_manage_extension_helper(win) {
checkVisibility(overflowMenuCtxMenu, false);
overflowMenuCtxMenu.hidePopup();
info("Test overflow menu context menu in browserAction");
await testContextMenu(overflowMenuCtxMenu.id, customizing);
info("Restore initial state");
CustomizableUI.addWidgetToArea(nodeId, CustomizableUI.AREA_NAVBAR);
if (!win.gUnifiedExtensions.isEnabled) {
info("Test overflow menu context menu in browserAction");
await testContextMenu(overflowMenuCtxMenu.id, customizing);
info("Put browser action back in nav-bar");
CustomizableUI.addWidgetToArea(nodeId, CustomizableUI.AREA_NAVBAR);
}
info("Put other button action back in nav-bar");
CustomizableUI.addWidgetToArea(otherButtonId, CustomizableUI.AREA_NAVBAR);
if (customizing) {
@ -386,21 +393,37 @@ async function browseraction_contextmenu_manage_extension_helper(win) {
info("Run tests in normal mode");
await main(false);
await assertTelemetryMatches([
["action", "browserAction", null, { action: "manage", addonId: id }],
["view", "aboutAddons", "detail", { addonId: id, type }],
["action", "browserAction", null, { action: "manage", addonId: id }],
["view", "aboutAddons", "detail", { addonId: id, type }],
]);
if (win.gUnifiedExtensions.isEnabled) {
await assertTelemetryMatches([
["action", "browserAction", null, { action: "manage", addonId: id }],
["view", "aboutAddons", "detail", { addonId: id, type }],
]);
} else {
await assertTelemetryMatches([
["action", "browserAction", null, { action: "manage", addonId: id }],
["view", "aboutAddons", "detail", { addonId: id, type }],
["action", "browserAction", null, { action: "manage", addonId: id }],
["view", "aboutAddons", "detail", { addonId: id, type }],
]);
}
info("Run tests in customize mode");
await main(true);
await assertTelemetryMatches([
["action", "browserAction", null, { action: "manage", addonId: id }],
["view", "aboutAddons", "detail", { addonId: id, type }],
["action", "browserAction", null, { action: "manage", addonId: id }],
["view", "aboutAddons", "detail", { addonId: id, type }],
]);
if (win.gUnifiedExtensions.isEnabled) {
await assertTelemetryMatches([
["action", "browserAction", null, { action: "manage", addonId: id }],
["view", "aboutAddons", "detail", { addonId: id, type }],
]);
} else {
await assertTelemetryMatches([
["action", "browserAction", null, { action: "manage", addonId: id }],
["view", "aboutAddons", "detail", { addonId: id, type }],
["action", "browserAction", null, { action: "manage", addonId: id }],
["view", "aboutAddons", "detail", { addonId: id, type }],
]);
}
info("Close the dummy tab and finish");
win.gBrowser.removeTab(dummyTab);
@ -427,28 +450,49 @@ async function runTestContextMenu({ id, customizing, testContextMenu, win }) {
info("Test toolbar context menu in browserAction");
await testContextMenu("toolbar-context-menu", customizing);
info("Pin the browserAction and another button to the overflow menu");
CustomizableUI.addWidgetToArea(
nodeId,
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
);
if (win.gUnifiedExtensions.isEnabled) {
info("Pin the browserAction to the addons panel");
CustomizableUI.addWidgetToArea(nodeId, CustomizableUI.AREA_ADDONS);
info("Wait until the overflow menu is ready");
let overflowButton = win.document.getElementById("nav-bar-overflow-button");
let icon = overflowButton.icon;
await waitForElementShown(icon);
if (!customizing) {
info("Open addons panel");
win.gUnifiedExtensions.togglePanel();
await BrowserTestUtils.waitForEvent(
win.gUnifiedExtensions.panel,
"popupshown"
);
info("Test browserAction in addons panel");
await testContextMenu("unified-extensions-context-menu", customizing);
} else {
todo(
false,
"The browserAction cannot be accessed from customize " +
"mode when in the addons panel."
);
}
} else {
info("Pin the browserAction to the overflow panel");
CustomizableUI.addWidgetToArea(
nodeId,
CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
);
if (!customizing) {
info("Open overflow menu");
let menu = win.document.getElementById("widget-overflow");
let shown = BrowserTestUtils.waitForEvent(menu, "popupshown");
overflowButton.click();
await shown;
info("Wait until the overflow menu is ready");
let overflowButton = win.document.getElementById("nav-bar-overflow-button");
let icon = overflowButton.icon;
await waitForElementShown(icon);
if (!customizing) {
info("Open overflow menu");
let menu = win.document.getElementById("widget-overflow");
let shown = BrowserTestUtils.waitForEvent(menu, "popupshown");
overflowButton.click();
await shown;
}
info("Test overflow menu context menu in browserAction");
await testContextMenu("customizationPanelItemContextMenu", customizing);
}
info("Test overflow menu context menu in browserAction");
await testContextMenu("customizationPanelItemContextMenu", customizing);
info("Restore initial state");
CustomizableUI.addWidgetToArea(nodeId, CustomizableUI.AREA_NAVBAR);
@ -512,9 +556,11 @@ async function browseraction_contextmenu_remove_extension_helper(win) {
let menu = await openContextMenu(menuId, buttonId, win);
info(`Choosing 'Remove Extension' in ${menuId} should show confirm dialog`);
let removeExtension = menu.querySelector(
".customize-context-removeExtension"
);
let removeItemQuery =
menuId == "unified-extensions-context-menu"
? ".unified-extensions-context-menu-remove-extension"
: ".customize-context-removeExtension";
let removeExtension = menu.querySelector(removeItemQuery);
await closeChromeContextMenu(menuId, removeExtension, win);
let args = await confirmArgs;
is(args[1], `Remove ${name}?`);
@ -535,20 +581,39 @@ async function browseraction_contextmenu_remove_extension_helper(win) {
win,
});
await assertTelemetryMatches([
[
"action",
"browserAction",
"cancelled",
{ action: "uninstall", addonId: id },
],
[
"action",
"browserAction",
"cancelled",
{ action: "uninstall", addonId: id },
],
]);
if (win.gUnifiedExtensions.isEnabled) {
// The first uninstall event comes from the toolbar context menu, and the
// next via the unified extension context menu.
await assertTelemetryMatches([
[
"action",
"browserAction",
"cancelled",
{ action: "uninstall", addonId: id },
],
[
"action",
"unifiedExtensions",
"cancelled",
{ action: "uninstall", addonId: id },
],
]);
} else {
await assertTelemetryMatches([
[
"action",
"browserAction",
"cancelled",
{ action: "uninstall", addonId: id },
],
[
"action",
"browserAction",
"cancelled",
{ action: "uninstall", addonId: id },
],
]);
}
info("Run tests in customize mode");
await runTestContextMenu({
@ -558,20 +623,38 @@ async function browseraction_contextmenu_remove_extension_helper(win) {
win,
});
await assertTelemetryMatches([
[
"action",
"browserAction",
"cancelled",
{ action: "uninstall", addonId: id },
],
[
"action",
"browserAction",
"cancelled",
{ action: "uninstall", addonId: id },
],
]);
if (win.gUnifiedExtensions.isEnabled) {
// We'll only get one of these because in customize mode, the browserAction
// is not accessible when in the addons panel.
todo(
false,
"Should record a second removal event when browserAction " +
"becomes available in customize mode."
);
await assertTelemetryMatches([
[
"action",
"browserAction",
"cancelled",
{ action: "uninstall", addonId: id },
],
]);
} else {
await assertTelemetryMatches([
[
"action",
"browserAction",
"cancelled",
{ action: "uninstall", addonId: id },
],
[
"action",
"browserAction",
"cancelled",
{ action: "uninstall", addonId: id },
],
]);
}
let addon = await AddonManager.getAddonByID(id);
ok(addon, "Addon is still installed");
@ -643,7 +726,7 @@ async function browseraction_contextmenu_report_extension_helper(win) {
useAddonManager: "temporary",
});
async function testReportDialog() {
async function testReportDialog(viaUnifiedContextMenu) {
const reportDialogWindow = await BrowserTestUtils.waitForCondition(
() => AbuseReporter.getOpenDialog(),
"Wait for the abuse report dialog to have been opened"
@ -657,7 +740,7 @@ async function browseraction_contextmenu_report_extension_helper(win) {
);
is(
reportDialogParams.report.reportEntryPoint,
"toolbar_context_menu",
viaUnifiedContextMenu ? "unified_context_menu" : "toolbar_context_menu",
"Abuse report dialog has the expected reportEntryPoint"
);
@ -677,9 +760,13 @@ async function browseraction_contextmenu_report_extension_helper(win) {
let menu = await openContextMenu(menuId, buttonId, win);
info(`Choosing 'Report Extension' in ${menuId} should show confirm dialog`);
let reportExtension = menu.querySelector(
".customize-context-reportExtension"
);
let usingUnifiedContextMenu = menuId == "unified-extensions-context-menu";
let reportItemQuery = usingUnifiedContextMenu
? ".unified-extensions-context-menu-report-extension"
: ".customize-context-reportExtension";
let reportExtension = menu.querySelector(reportItemQuery);
ok(!reportExtension.hidden, "Report extension should be visibile");
// When running in customizing mode "about:addons" will load in a new tab,
@ -707,7 +794,7 @@ async function browseraction_contextmenu_report_extension_helper(win) {
if (browser.contentDocument?.readyState != "complete") {
await BrowserTestUtils.browserLoaded(browser);
}
await testReportDialog();
await testReportDialog(usingUnifiedContextMenu);
// Close the new about:addons tab when running in customize mode,
// or cancel the abuse report if the about:addons page has been

View File

@ -102,24 +102,31 @@ async function testOriginControls(
}
let doc = menu.ownerDocument;
let visibleItems = 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(menu.children[i]);
Assert.deepEqual(l10n, items[i], `Menu item ${i} has correct l10n attrs.`);
let l10n = doc.l10n.getAttributes(visibleItems[i]);
Assert.deepEqual(
l10n,
items[i],
`Visible menu item ${i} has correct l10n attrs.`
);
let checked = menu.children[i].getAttribute("checked") === "true";
let checked = visibleItems[i].getAttribute("checked") === "true";
is(i === selected, checked, `Expected checked value for item ${i}.`);
}
if (items.length) {
is(
menu.children[items.length].nodeName,
visibleItems[items.length].nodeName,
"menuseparator",
"Found separator."
);
is(
menu.children[items.length + 1].className,
visibleItems[items.length + 1].className,
manageExtensionClassName,
"All items accounted for."
);
@ -133,7 +140,7 @@ async function testOriginControls(
let itemToClick;
if (click) {
itemToClick = menu.children[click];
itemToClick = visibleItems[click];
}
await closeChromeContextMenu(contextMenuId, itemToClick, win);

View File

@ -57,6 +57,13 @@ function waitClosedWindow(win) {
});
}
function assertVisibleContextMenuItems(contextMenu, expected) {
let visibleItems = contextMenu.querySelectorAll(
":is(menuitem, menuseparator):not([hidden])"
);
is(visibleItems.length, expected, `expected ${expected} visible menu items`);
}
let win;
add_setup(async function() {
@ -570,7 +577,7 @@ add_task(async function test_context_menu_without_browserActionFor_global() {
// This promise rejects with an error if the implementation does not handle
// the case where `global.browserActionFor()` is undefined.
const contextMenu = await openUnifiedExtensionsContextMenu(win, extension.id);
is(contextMenu.childElementCount, 3, "expected 3 menu items");
assertVisibleContextMenuItems(contextMenu, 3);
await closeChromeContextMenu(contextMenu.id, null, win);
await closeExtensionsPanel(win);
@ -676,7 +683,8 @@ add_task(async function test_browser_action_context_menu() {
win,
extWithMenuBrowserAction.id
);
is(contextMenu.childElementCount, 5, "expected 5 menu items");
assertVisibleContextMenuItems(contextMenu, 5);
const [item, separator] = contextMenu.children;
is(
item.getAttribute("label"),
@ -697,21 +705,21 @@ add_task(async function test_browser_action_context_menu() {
win,
extWithMenuPageAction.id
);
is(contextMenu.childElementCount, 3, "expected 3 menu items");
assertVisibleContextMenuItems(contextMenu, 3);
await closeChromeContextMenu(contextMenu.id, null, win);
info("extension with no browser action and no menu");
// There is no context menu created by this extension, so there should only
// be 3 menu items corresponding to the default manage/remove/report items.
contextMenu = await openUnifiedExtensionsContextMenu(win, extWithoutMenu1.id);
is(contextMenu.childElementCount, 3, "expected 3 menu items");
assertVisibleContextMenuItems(contextMenu, 3);
await closeChromeContextMenu(contextMenu.id, null, win);
info("extension with browser action and no menu");
// There is no context menu created by this extension, so there should only
// be 3 menu items corresponding to the default manage/remove/report items.
contextMenu = await openUnifiedExtensionsContextMenu(win, extWithoutMenu2.id);
is(contextMenu.childElementCount, 3, "expected 3 menu items");
assertVisibleContextMenuItems(contextMenu, 3);
await closeChromeContextMenu(contextMenu.id, null, win);
info("extension with browser action and menu + sub-menu");
@ -721,7 +729,7 @@ add_task(async function test_browser_action_context_menu() {
win,
extWithSubMenuBrowserAction.id
);
is(contextMenu.childElementCount, 5, "expected 5 menu items");
assertVisibleContextMenuItems(contextMenu, 5);
const popup = await openSubmenu(contextMenu.children[0]);
is(popup.children.length, 1, "expected 1 submenu item");
is(
@ -730,7 +738,7 @@ add_task(async function test_browser_action_context_menu() {
"expected menu item"
);
// The number of items in the (main) context menu should remain the same.
is(contextMenu.childElementCount, 5, "expected 5 menu items");
assertVisibleContextMenuItems(contextMenu, 5);
await closeChromeContextMenu(contextMenu.id, null, win);
await closeExtensionsPanel(win);

View File

@ -51,6 +51,19 @@ function getChildrenIDs(parent) {
return Array.from(parent.children).map(child => child.id);
}
/**
* Returns a NodeList of all non-hidden menu, menuitem and menuseparators
* that are direct descendants of popup.
*
* @param {Element} popup
* @returns {NodeList} the visible items.
*/
function getVisibleMenuItems(popup) {
return popup.querySelectorAll(
":scope > :is(menu, menuitem, menuseparator):not([hidden])"
);
}
/**
* This helper function does most of the heavy lifting for these tests.
* It does the following in order:
@ -94,6 +107,11 @@ async function withWindowOverflowed(win, taskFn) {
const extWithMenuBrowserAction = ExtensionTestUtils.loadExtension({
manifest: {
browser_specific_settings: {
gecko: {
id: "overflowable-toolbar-addon-with-context-menu@mozilla.org",
},
},
name: "Extension #0",
browser_specific_settings: {
gecko: { id: "unified-extensions-overflowable-toolbar@ext-0" },
@ -620,15 +638,19 @@ add_task(async function test_context_menu() {
firstExtensionWidget.dataset.extensionid
);
Assert.ok(contextMenu, "expected a context menu");
let visibleItems = getVisibleMenuItems(contextMenu);
// The context menu for the extension that declares a browser action menu
// should have the menu item created by the extension, a menu separator
// and the 3 default menu items.
// should have the menu item created by the extension, a menu separator, the control
// for pinning the browser action to the toolbar, a menu separator and the 3 default menu items.
is(
contextMenu.childElementCount,
5,
"expected a custom context menu item and a menu separator in addition to the 3 default menu items"
visibleItems.length,
7,
"expected a custom context menu item, a menu separator, the pin to " +
"toolbar menu item, a menu separator, and the 3 default menu items"
);
const [item, separator] = contextMenu.children;
const [item, separator] = visibleItems;
is(
item.getAttribute("label"),
"Click me!",
@ -639,6 +661,7 @@ add_task(async function test_context_menu() {
"menuseparator",
"expected separator after last menu item created by the extension"
);
await closeChromeContextMenu(contextMenu.id, null, win);
info("extension with browser action and a menu with submenu");
@ -648,8 +671,9 @@ add_task(async function test_context_menu() {
win,
secondExtensionWidget.dataset.extensionid
);
is(contextMenu.childElementCount, 5, "expected 5 menu items");
const popup = await openSubmenu(contextMenu.children[0]);
visibleItems = getVisibleMenuItems(contextMenu);
is(visibleItems.length, 7, "expected 7 menu items");
const popup = await openSubmenu(visibleItems[0]);
is(popup.children.length, 1, "expected 1 submenu item");
is(
popup.children[0].getAttribute("label"),
@ -657,7 +681,8 @@ add_task(async function test_context_menu() {
"expected menu item"
);
// The number of items in the (main) context menu should remain the same.
is(contextMenu.childElementCount, 5, "expected 5 menu items");
visibleItems = getVisibleMenuItems(contextMenu);
is(visibleItems.length, 7, "expected 7 menu items");
await closeChromeContextMenu(contextMenu.id, null, win);
info("extension with no browser action and no menu");
@ -671,7 +696,9 @@ add_task(async function test_context_menu() {
thirdExtensionWidget.dataset.extensionid
);
Assert.ok(contextMenu, "expected a context menu");
is(contextMenu.childElementCount, 3, "expected 3 menu items");
visibleItems = getVisibleMenuItems(contextMenu);
is(visibleItems.length, 5, "expected 5 menu items");
await closeChromeContextMenu(contextMenu.id, null, win);
// We can close the unified extensions panel now.

View File

@ -66,7 +66,7 @@ const getUnifiedExtensionsItem = (win, extensionId) => {
// First try to find a CUI widget, otherwise a custom element when the
// extension does not have a browser action.
return (
view.querySelector(`[data-extensionid="${extensionId}"]`) ||
view.querySelector(`toolbaritem[data-extensionid="${extensionId}"]`) ||
view.querySelector(`unified-extensions-item[extension-id="${extensionId}"]`)
);
};