Bug 1489430 - Add "Remove Extension" context menu item for pageAction. r=robwu,mstriemer,fluent-reviewers,Gijs

Differential Revision: https://phabricator.services.mozilla.com/D69831

--HG--
extra : moz-landing-system : lando
This commit is contained in:
William Durand 2020-04-08 14:18:53 +00:00
Родитель a91be586fd
Коммит b90b5b3778
10 изменённых файлов: 512 добавлений и 94 удалений

Просмотреть файл

@ -1006,3 +1006,86 @@ var gExtensionsNotifications = {
}
},
};
var BrowserAddonUI = {
promptRemoveExtension(addon) {
let { name } = addon;
let brand = document
.getElementById("bundle_brand")
.getString("brandShorterName");
let { getFormattedString, getString } = gNavigatorBundle;
let title = getFormattedString("webext.remove.confirmation.title", [name]);
let message = getFormattedString("webext.remove.confirmation.message", [
name,
brand,
]);
let btnTitle = getString("webext.remove.confirmation.button");
let {
BUTTON_TITLE_IS_STRING: titleString,
BUTTON_TITLE_CANCEL: titleCancel,
BUTTON_POS_0,
BUTTON_POS_1,
confirmEx,
} = Services.prompt;
let btnFlags = BUTTON_POS_0 * titleString + BUTTON_POS_1 * titleCancel;
let checkboxState = { value: false };
let checkboxMessage = null;
// Enable abuse report checkbox in the remove extension dialog,
// if enabled by the about:config prefs and the addon type
// is currently supported.
if (
gAddonAbuseReportEnabled &&
["extension", "theme"].includes(addon.type)
) {
checkboxMessage = getFormattedString(
"webext.remove.abuseReportCheckbox.message",
[document.getElementById("bundle_brand").getString("vendorShortName")]
);
}
const result = confirmEx(
null,
title,
message,
btnFlags,
btnTitle,
null,
null,
checkboxMessage,
checkboxState
);
return { remove: result === 0, report: checkboxState.value };
},
async reportAddon(addonId, reportEntryPoint) {
const win = await BrowserOpenAddonsMgr("addons://list/extension");
win.openAbuseReport({ addonId, reportEntryPoint });
},
async removeAddon(addonId, eventObject) {
let addon = addonId && (await AddonManager.getAddonByID(addonId));
if (!addon || !(addon.permissions & AddonManager.PERM_CAN_UNINSTALL)) {
return;
}
let { remove, report } = this.promptRemoveExtension(addon);
AMTelemetry.recordActionEvent({
object: eventObject,
action: "uninstall",
value: remove ? "accepted" : "cancelled",
extra: { addonId },
});
if (remove) {
// Leave the extension in pending uninstall if we are also reporting the
// add-on.
await addon.uninstall(report);
if (report) {
await this.reportAddon(addon.id, "uninstall");
}
}
},
};

Просмотреть файл

@ -911,7 +911,7 @@ var BrowserPageActions = {
* @param popup (DOM node, required)
* The context menu popup DOM node.
*/
onContextMenuShowing(event, popup) {
async onContextMenuShowing(event, popup) {
if (event.target != popup) {
return;
}
@ -933,6 +933,16 @@ var BrowserPageActions = {
: "extensionUnpinned";
}
popup.setAttribute("state", state);
let removeExtension = popup.querySelector(".removeExtensionItem");
let { extensionID } = this._contextAction;
let addon = extensionID && (await AddonManager.getAddonByID(extensionID));
removeExtension.hidden = !addon;
if (addon) {
removeExtension.disabled = !(
addon.permissions & AddonManager.PERM_CAN_UNINSTALL
);
}
},
/**
@ -968,6 +978,19 @@ var BrowserPageActions = {
window.BrowserOpenAddonsMgr(viewID);
},
/**
* Call this from the menu item in the context menu that removes an add-on.
*/
removeExtensionForContextAction() {
if (!this._contextAction) {
return;
}
let action = this._contextAction;
this._contextAction = null;
BrowserAddonUI.removeAddon(action.extensionID, "pageAction");
},
_contextAction: null,
/**

Просмотреть файл

@ -142,7 +142,7 @@ XPCOMUtils.defineLazyScriptGetter(
);
XPCOMUtils.defineLazyScriptGetter(
this,
["gExtensionsNotifications", "gXPInstallObserver"],
["BrowserAddonUI", "gExtensionsNotifications", "gXPInstallObserver"],
"chrome://browser/content/browser-addons.js"
);
XPCOMUtils.defineLazyScriptGetter(
@ -7106,52 +7106,6 @@ function UpdateCurrentCharset(target) {
}
}
function promptRemoveExtension(addon) {
let { name } = addon;
let brand = document
.getElementById("bundle_brand")
.getString("brandShorterName");
let { getFormattedString, getString } = gNavigatorBundle;
let title = getFormattedString("webext.remove.confirmation.title", [name]);
let message = getFormattedString("webext.remove.confirmation.message", [
name,
brand,
]);
let btnTitle = getString("webext.remove.confirmation.button");
let {
BUTTON_TITLE_IS_STRING: titleString,
BUTTON_TITLE_CANCEL: titleCancel,
BUTTON_POS_0,
BUTTON_POS_1,
confirmEx,
} = Services.prompt;
let btnFlags = BUTTON_POS_0 * titleString + BUTTON_POS_1 * titleCancel;
let checkboxState = { value: false };
let checkboxMessage = null;
// Enable abuse report checkbox in the remove extension dialog,
// if enabled by the about:config prefs and the addon type
// is currently supported.
if (gAddonAbuseReportEnabled && ["extension", "theme"].includes(addon.type)) {
checkboxMessage = getFormattedString(
"webext.remove.abuseReportCheckbox.message",
[document.getElementById("bundle_brand").getString("vendorShortName")]
);
}
const result = confirmEx(
null,
title,
message,
btnFlags,
btnTitle,
null,
null,
checkboxMessage,
checkboxState
);
return { remove: result === 0, report: checkboxState.value };
}
var ToolbarContextMenu = {
updateDownloadsAutoHide(popup) {
let checkbox = document.getElementById(
@ -7218,25 +7172,8 @@ var ToolbarContextMenu = {
async removeExtensionForContextAction(popup) {
let id = this._getExtensionId(popup);
let addon = id && (await AddonManager.getAddonByID(id));
if (!addon || !(addon.permissions & AddonManager.PERM_CAN_UNINSTALL)) {
return;
}
let { remove, report } = promptRemoveExtension(addon);
AMTelemetry.recordActionEvent({
object: "browserAction",
action: "uninstall",
value: remove ? "accepted" : "cancelled",
extra: { addonId: addon.id },
});
if (remove) {
// Leave the extension in pending uninstall if we are also
// reporting the add-on.
await addon.uninstall(report);
if (report) {
this.reportExtensionForContextAction(popup, "uninstall");
}
}
await BrowserAddonUI.removeAddon(id, "browserAction");
},
async reportExtensionForContextAction(popup, reportEntryPoint) {
@ -7245,11 +7182,8 @@ var ToolbarContextMenu = {
if (!addon) {
return;
}
const win = await BrowserOpenAddonsMgr("addons://list/extension");
win.openAbuseReport({
addonId: addon.id,
reportEntryPoint,
});
await BrowserAddonUI.reportAddon(addon.id, reportEntryPoint);
},
openAboutAddonsForContextAction(popup) {

Просмотреть файл

@ -591,6 +591,9 @@
<menuitem class="pageActionContextMenuItem extensionPinned extensionUnpinned"
oncommand="BrowserPageActions.openAboutAddonsForContextAction();"
data-l10n-id="page-action-manage-extension"/>
<menuitem class="pageActionContextMenuItem extensionPinned extensionUnpinned removeExtensionItem"
oncommand="BrowserPageActions.removeExtensionForContextAction();"
data-l10n-id="page-action-remove-extension"/>
</menupopup>
#include ../../components/places/content/bookmarksHistoryTooltip.inc.xhtml

Просмотреть файл

@ -2,6 +2,7 @@
support-files =
head.js
[browser_PageActions_removeExtension.js]
[browser_page_action_menu_add_search_engine.js]
support-files =
page_action_menu_add_search_engine_one.html

Просмотреть файл

@ -0,0 +1,322 @@
"use strict";
const { EnterprisePolicyTesting } = ChromeUtils.import(
"resource://testing-common/EnterprisePolicyTesting.jsm"
);
const { ExtensionCommon } = ChromeUtils.import(
"resource://gre/modules/ExtensionCommon.jsm"
);
const { TelemetryTestUtils } = ChromeUtils.import(
"resource://testing-common/TelemetryTestUtils.jsm"
);
const TELEMETRY_EVENTS_FILTERS = {
category: "addonsManager",
method: "action",
};
// Initialization. Must run first.
add_task(async function init() {
// The page action urlbar button, and therefore the panel, is only shown when
// the current tab is actionable -- i.e., a normal web page. about:blank is
// not, so open a new tab first thing, and close it when this test is done.
let tab = await BrowserTestUtils.openNewForegroundTab({
gBrowser,
url: "http://example.com/",
});
registerCleanupFunction(async () => {
BrowserTestUtils.removeTab(tab);
});
});
add_task(async function contextMenu_removeExtension_panel() {
Services.telemetry.clearEvents();
// We use an extension that shows a page action so that we can test the
// "remove extension" item in the context menu.
let extension = ExtensionTestUtils.loadExtension({
manifest: {
name: "Test contextMenu",
page_action: { show_matches: ["<all_urls>"] },
},
useAddonManager: "temporary",
});
await extension.startup();
let actionId = ExtensionCommon.makeWidgetId(extension.id);
// Open the panel and then open the context menu on the action's item.
await promisePageActionPanelOpen();
let panelButton = BrowserPageActions.panelButtonNodeForActionID(actionId);
let contextMenuPromise = promisePanelShown("pageActionContextMenu");
EventUtils.synthesizeMouseAtCenter(panelButton, {
type: "contextmenu",
button: 2,
});
await contextMenuPromise;
let removeExtensionItem = getRemoveExtensionItem();
Assert.ok(removeExtensionItem, "'Remove' item exists");
Assert.ok(!removeExtensionItem.hidden, "'Remove' item is visible");
Assert.ok(!removeExtensionItem.disabled, "'Remove' item is not disabled");
// Click the "remove extension" item, a prompt should be displayed and then
// the add-on should be uninstalled. We mock the prompt service to confirm
// the removal of the add-on.
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
let addonUninstalledPromise = promiseAddonUninstalled(extension.id);
mockPromptService();
EventUtils.synthesizeMouseAtCenter(removeExtensionItem, {});
await Promise.all([contextMenuPromise, addonUninstalledPromise]);
// Done, clean up.
await extension.unload();
TelemetryTestUtils.assertEvents(
[
{
object: "pageAction",
value: "accepted",
extra: { addonId: extension.id, action: "uninstall" },
},
],
TELEMETRY_EVENTS_FILTERS
);
// urlbar tests that run after this one can break if the mouse is left over
// the area where the urlbar popup appears, which seems to happen due to the
// above synthesized mouse events. Move it over the urlbar.
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, { type: "mousemove" });
gURLBar.focus();
});
add_task(async function contextMenu_removeExtension_urlbar() {
Services.telemetry.clearEvents();
// We use an extension that shows a page action so that we can test the
// "remove extension" item in the context menu.
let extension = ExtensionTestUtils.loadExtension({
manifest: {
name: "Test contextMenu",
page_action: { show_matches: ["<all_urls>"] },
},
useAddonManager: "temporary",
});
await extension.startup();
// The pageAction implementation enables the button at the next animation
// frame, so before we look for the button we should wait one animation frame
// as well.
await promiseAnimationFrame();
let actionId = ExtensionCommon.makeWidgetId(extension.id);
// Open the context menu on the action's urlbar button.
let urlbarButton = BrowserPageActions.urlbarButtonNodeForActionID(actionId);
let contextMenuPromise = promisePanelShown("pageActionContextMenu");
EventUtils.synthesizeMouseAtCenter(urlbarButton, {
type: "contextmenu",
button: 2,
});
await contextMenuPromise;
let removeExtensionItem = getRemoveExtensionItem();
Assert.ok(removeExtensionItem, "'Remove' item exists");
Assert.ok(!removeExtensionItem.hidden, "'Remove' item is visible");
Assert.ok(!removeExtensionItem.disabled, "'Remove' item is not disabled");
// Click the "remove extension" item, a prompt should be displayed and then
// the add-on should be uninstalled. We mock the prompt service to cancel the
// removal of the add-on.
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
let promptService = mockPromptService();
let promptCancelledPromise = new Promise(resolve => {
promptService.confirmEx = () => resolve();
});
EventUtils.synthesizeMouseAtCenter(removeExtensionItem, {});
await Promise.all([contextMenuPromise, promptCancelledPromise]);
// Done, clean up.
await extension.unload();
TelemetryTestUtils.assertEvents(
[
{
object: "pageAction",
value: "cancelled",
extra: { addonId: extension.id, action: "uninstall" },
},
],
TELEMETRY_EVENTS_FILTERS
);
// urlbar tests that run after this one can break if the mouse is left over
// the area where the urlbar popup appears, which seems to happen due to the
// above synthesized mouse events. Move it over the urlbar.
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, { type: "mousemove" });
gURLBar.focus();
});
add_task(async function contextMenu_removeExtension_disabled_in_panel() {
// We use an extension that shows a page action so that we can test the
// "remove extension" item in the context menu.
let extension = ExtensionTestUtils.loadExtension({
manifest: {
name: "Test contextMenu",
page_action: { show_matches: ["<all_urls>"] },
},
useAddonManager: "temporary",
});
await extension.startup();
// Add a policy to prevent the add-on from being uninstalled.
await EnterprisePolicyTesting.setupPolicyEngineWithJson({
policies: {
Extensions: {
Locked: [extension.id],
},
},
});
let actionId = ExtensionCommon.makeWidgetId(extension.id);
// Open the panel and then open the context menu on the action's item.
await promisePageActionPanelOpen();
let panelButton = BrowserPageActions.panelButtonNodeForActionID(actionId);
let contextMenuPromise = promisePanelShown("pageActionContextMenu");
EventUtils.synthesizeMouseAtCenter(panelButton, {
type: "contextmenu",
button: 2,
});
await contextMenuPromise;
let removeExtensionItem = getRemoveExtensionItem();
Assert.ok(removeExtensionItem, "'Remove' item exists");
Assert.ok(!removeExtensionItem.hidden, "'Remove' item is visible");
Assert.ok(removeExtensionItem.disabled, "'Remove' item is disabled");
// Press escape to hide the context menu.
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
EventUtils.synthesizeKey("KEY_Escape");
await contextMenuPromise;
// Done, clean up.
await extension.unload();
await EnterprisePolicyTesting.setupPolicyEngineWithJson("");
// urlbar tests that run after this one can break if the mouse is left over
// the area where the urlbar popup appears, which seems to happen due to the
// above synthesized mouse events. Move it over the urlbar.
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, { type: "mousemove" });
gURLBar.focus();
});
add_task(async function contextMenu_removeExtension_disabled_in_urlbar() {
// We use an extension that shows a page action so that we can test the
// "remove extension" item in the context menu.
let extension = ExtensionTestUtils.loadExtension({
manifest: {
name: "Test contextMenu",
page_action: { show_matches: ["<all_urls>"] },
},
useAddonManager: "temporary",
});
await extension.startup();
// The pageAction implementation enables the button at the next animation
// frame, so before we look for the button we should wait one animation frame
// as well.
await promiseAnimationFrame();
// Add a policy to prevent the add-on from being uninstalled.
await EnterprisePolicyTesting.setupPolicyEngineWithJson({
policies: {
Extensions: {
Locked: [extension.id],
},
},
});
let actionId = ExtensionCommon.makeWidgetId(extension.id);
// Open the context menu on the action's urlbar button.
let urlbarButton = BrowserPageActions.urlbarButtonNodeForActionID(actionId);
let contextMenuPromise = promisePanelShown("pageActionContextMenu");
EventUtils.synthesizeMouseAtCenter(urlbarButton, {
type: "contextmenu",
button: 2,
});
await contextMenuPromise;
let removeExtensionItem = getRemoveExtensionItem();
Assert.ok(removeExtensionItem, "'Remove' item exists");
Assert.ok(!removeExtensionItem.hidden, "'Remove' item is visible");
Assert.ok(removeExtensionItem.disabled, "'Remove' item is disabled");
// Press escape to hide the context menu.
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
EventUtils.synthesizeKey("KEY_Escape");
await contextMenuPromise;
// Done, clean up.
await extension.unload();
await EnterprisePolicyTesting.setupPolicyEngineWithJson("");
// urlbar tests that run after this one can break if the mouse is left over
// the area where the urlbar popup appears, which seems to happen due to the
// above synthesized mouse events. Move it over the urlbar.
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, { type: "mousemove" });
gURLBar.focus();
});
function promiseAddonUninstalled(addonId) {
return new Promise(resolve => {
let listener = {};
listener.onUninstalled = addon => {
if (addon.id == addonId) {
AddonManager.removeAddonListener(listener);
resolve();
}
};
AddonManager.addAddonListener(listener);
});
}
function mockPromptService() {
let { prompt } = Services;
let promptService = {
// The prompt returns 1 for cancelled and 0 for accepted.
_response: 0,
QueryInterface: ChromeUtils.generateQI([Ci.nsIPromptService]),
confirmEx: () => promptService._response,
};
Services.prompt = promptService;
registerCleanupFunction(() => {
Services.prompt = prompt;
});
return promptService;
}
function getRemoveExtensionItem() {
return document.querySelector(
"#pageActionContextMenu > menuitem[label='Remove Extension']"
);
}
async function promiseAnimationFrame(win = window) {
await new Promise(resolve => win.requestAnimationFrame(resolve));
let { tm } = Services;
return new Promise(resolve => tm.dispatchToMainThread(resolve));
}

Просмотреть файл

@ -208,12 +208,13 @@ add_task(async function test_hiddenPageActionContextMenu() {
return window.getComputedStyle(node).visibility == "visible";
});
is(menuItems.length, 3, "Correct number of children");
const [dontShowItem, separator, manageItem] = menuItems;
is(menuItems.length, 4, "Correct number of children");
const [dontShowItem, separator, manageItem, removeItem] = menuItems;
is(dontShowItem.label, "Remove from Address Bar", "Correct first child");
is(separator.tagName, "menuseparator", "Correct second child");
is(manageItem.label, "Manage Extension\u2026", "Correct third child");
is(removeItem.label, "Remove Extension", "Correct fourth child");
await closeChromeContextMenu(menu.id);
await closeChromeContextMenu(BrowserPageActions.panelNode.id);

Просмотреть файл

@ -111,6 +111,8 @@ page-action-manage-extension =
.label = Manage Extension…
page-action-remove-from-urlbar =
.label = Remove from Address Bar
page-action-remove-extension =
.label = Remove Extension
## Auto-hide Context Menu

Просмотреть файл

@ -1533,10 +1533,11 @@ add_task(async function contextMenu() {
});
await contextMenuPromise;
// The context menu should show the "remove" item and the "manage" item.
// Click the "remove" item.
// The context menu should show the "remove" item and the "manage" item. The
// 4th item is "remove extension" but it is hidden in this test case because
// the page action isn't bound to an addon. Click the "remove" item.
let menuItems = collectContextMenuItems();
Assert.equal(menuItems.length, 3, "Context menu has 3 children");
Assert.equal(menuItems.length, 4, "Context menu has 4 children");
Assert.equal(
menuItems[0].label,
"Remove from Address Bar",
@ -1552,6 +1553,13 @@ add_task(async function contextMenu() {
"Manage Extension\u2026",
"'Manage' item is present"
);
Assert.equal(
menuItems[3].label,
"Remove Extension",
"'Remove' item is present"
);
Assert.ok(menuItems[3].hidden, "'Remove' item is hidden");
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
EventUtils.synthesizeMouseAtCenter(menuItems[0], {});
await contextMenuPromise;
@ -1570,10 +1578,10 @@ add_task(async function contextMenu() {
});
await contextMenuPromise;
// The context menu should show the "add" item and the "manage" item. Click
// the "add" item.
// The context menu should show the "add" item and the "manage" item. The 4th
// item is "remove extension" but it is hidden. Click the "add" item.
menuItems = collectContextMenuItems();
Assert.equal(menuItems.length, 3, "Context menu has 3 children");
Assert.equal(menuItems.length, 4, "Context menu has 4 children");
Assert.equal(
menuItems[0].label,
"Add to Address Bar",
@ -1589,6 +1597,13 @@ add_task(async function contextMenu() {
"Manage Extension\u2026",
"'Manage' item is present"
);
Assert.equal(
menuItems[3].label,
"Remove Extension",
"'Remove' item is present"
);
Assert.ok(menuItems[3].hidden, "'Remove' item is hidden");
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
EventUtils.synthesizeMouseAtCenter(menuItems[0], {});
await contextMenuPromise;
@ -1598,7 +1613,7 @@ add_task(async function contextMenu() {
return BrowserPageActions.urlbarButtonNodeForActionID(action.id);
}, "Waiting for urlbar button to be added back");
// Open the context menu again on the action's button in the panel. (The
// Open the context menu again on the action's button in the panel. (The
// panel should still be open.)
contextMenuPromise = promisePanelShown("pageActionContextMenu");
EventUtils.synthesizeMouseAtCenter(panelButton, {
@ -1607,10 +1622,11 @@ add_task(async function contextMenu() {
});
await contextMenuPromise;
// The context menu should show the "remove" item and the "manage" item.
// Click the "manage" item. about:addons should open.
// The context menu should show the "remove" item and the "manage" item. The
// 4th item is "remove extension" but it is hidden. Click the "manage" item.
// about:addons should open.
menuItems = collectContextMenuItems();
Assert.equal(menuItems.length, 3, "Context menu has 3 children");
Assert.equal(menuItems.length, 4, "Context menu has 4 children");
Assert.equal(
menuItems[0].label,
"Remove from Address Bar",
@ -1626,6 +1642,14 @@ add_task(async function contextMenu() {
"Manage Extension\u2026",
"'Manage' item is present"
);
Assert.equal(
menuItems[3].label,
"Remove Extension",
"'Remove' item is present"
);
Assert.ok(menuItems[3].hidden, "'Remove' item is hidden");
// Click the "manage" item, about:addons should open.
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
let aboutAddonsPromise = BrowserTestUtils.waitForNewTab(
gBrowser,
@ -1645,10 +1669,11 @@ add_task(async function contextMenu() {
});
await contextMenuPromise;
// The context menu should show the "remove" item and the "manage" item.
// Click the "remove" item.
// The context menu should show the "remove" item and the "manage" item. The
// 4th item is "remove extension" but it is hidden. Click the "manage" item.
// about:addons should open.
menuItems = collectContextMenuItems();
Assert.equal(menuItems.length, 3, "Context menu has 3 children");
Assert.equal(menuItems.length, 4, "Context menu has 4 children");
Assert.equal(
menuItems[0].label,
"Remove from Address Bar",
@ -1664,6 +1689,13 @@ add_task(async function contextMenu() {
"Manage Extension\u2026",
"'Manage' item is present"
);
Assert.equal(
menuItems[3].label,
"Remove Extension",
"'Remove' item is present"
);
Assert.ok(menuItems[3].hidden, "'Remove' item is hidden");
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
EventUtils.synthesizeMouseAtCenter(menuItems[0], {});
await contextMenuPromise;
@ -1682,10 +1714,10 @@ add_task(async function contextMenu() {
});
await contextMenuPromise;
// The context menu should show the "add" item and the "manage" item. Click
// the "add" item.
// The context menu should show the "remove" item and the "manage" item. The
// 4th item is "remove extension" but it is hidden. Click the "remove" item.
menuItems = collectContextMenuItems();
Assert.equal(menuItems.length, 3, "Context menu has 3 children");
Assert.equal(menuItems.length, 4, "Context menu has 4 children");
Assert.equal(
menuItems[0].label,
"Add to Address Bar",
@ -1701,6 +1733,13 @@ add_task(async function contextMenu() {
"Manage Extension\u2026",
"'Manage' item is present"
);
Assert.equal(
menuItems[3].label,
"Remove Extension",
"'Remove' item is present"
);
Assert.ok(menuItems[3].hidden, "'Remove' item is hidden");
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
EventUtils.synthesizeMouseAtCenter(menuItems[0], {});
await contextMenuPromise;
@ -1719,10 +1758,10 @@ add_task(async function contextMenu() {
});
await contextMenuPromise;
// The context menu should show the "remove" item and the "manage" item.
// Click the "manage" item. about:addons should open.
// The context menu should show the "add" item and the "manage" item. The 4th
// item is "remove extension" but it is hidden. Click the "add" item.
menuItems = collectContextMenuItems();
Assert.equal(menuItems.length, 3, "Context menu has 3 children");
Assert.equal(menuItems.length, 4, "Context menu has 4 children");
Assert.equal(
menuItems[0].label,
"Remove from Address Bar",
@ -1738,6 +1777,14 @@ add_task(async function contextMenu() {
"Manage Extension\u2026",
"'Manage' item is present"
);
Assert.equal(
menuItems[3].label,
"Remove Extension",
"'Remove' item is present"
);
Assert.ok(menuItems[3].hidden, "'Remove' item is hidden");
// Click the "manage" item, about:addons should open.
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
aboutAddonsPromise = BrowserTestUtils.waitForNewTab(gBrowser, "about:addons");
EventUtils.synthesizeMouseAtCenter(menuItems[2], {});

Просмотреть файл

@ -2886,7 +2886,9 @@ class AddonCard extends HTMLElement {
let {
remove,
report,
} = windowRoot.ownerGlobal.promptRemoveExtension(addon);
} = windowRoot.ownerGlobal.BrowserAddonUI.promptRemoveExtension(
addon
);
let value = remove ? "accepted" : "cancelled";
this.recordActionEvent("uninstall", value);
if (remove) {