Bug 1469705: allow menus.refresh() without an onShown listener r=mixedpuppy

MozReview-Commit-ID: 3GbQEoSFTW8

--HG--
extra : rebase_source : cfb50b104e14c1e38b319c207164c96c3fa0f55e
This commit is contained in:
Peter Simonyi 2018-07-05 22:06:23 -04:00
Родитель 315e5ddcc0
Коммит c3ec2fa929
2 изменённых файлов: 113 добавлений и 49 удалений

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

@ -353,14 +353,13 @@ var gMenuBuilder = {
return;
}
if (!gShownMenuItems.has(extension)) {
// The onShown event was not fired for the extension, so the extension
// does not know that a menu is being shown, and therefore they should
// not care whether the extension menu is updated.
return;
}
if (contextData.onBrowserAction || contextData.onPageAction) {
if (contextData.extension.id !== extension.id) {
// The extension that just called refresh() is not the owner of the
// action whose context menu is showing, so it can't have any items in
// the menu anyway and nothing will change.
return;
}
// The action menu can only have items from one extension, so remove all
// items (including the separator) and rebuild the action menu (if any).
for (let item of this.itemsToCleanUp) {

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

@ -13,12 +13,17 @@ const PAGE = "http://mochi.test:8888/browser/browser/components/extensions/test/
// to the menu item ID from the browser.menus API (if existent, null otherwise).
function loadExtensionWithMenusApi() {
async function background() {
browser.menus.onShown.addListener(() => {
function shownHandler() {
browser.test.sendMessage("onShown fired");
});
}
browser.menus.onShown.addListener(shownHandler);
browser.test.onMessage.addListener((method, ...params) => {
let result;
if (method === "create") {
if (method === "* remove onShown listener") {
browser.menus.onShown.removeListener(shownHandler);
result = Promise.resolve();
} else if (method === "create") {
result = new Promise(resolve => {
browser.menus.create(params[0], resolve);
});
@ -45,6 +50,10 @@ function loadExtensionWithMenusApi() {
return extension.awaitMessage(`${method}-result`);
};
extension.removeOnShownListener = async function() {
extension.callMenuApi("* remove onShown listener");
};
extension.getXULElementByMenuId = id => {
// Same implementation as elementId getter in ext-menus.js
if (typeof id != "number") {
@ -157,8 +166,66 @@ async function testRefreshMenusWhileVisible({contexts, doOpenMenu, doCloseMenu,
await extension.unload();
}
// Check that one extension calling refresh() doesn't interfere with others.
// When expectOtherItems == false, the other extension's menu items should not
// show at all (e.g. for browserAction).
async function testRefreshOther({contexts, doOpenMenu, doCloseMenu,
expectOtherItems}) {
let extension = loadExtensionWithMenusApi();
let other_extension = loadExtensionWithMenusApi();
await extension.startup();
await other_extension.startup();
await extension.callMenuApi("create", {
id: "action_item",
title: "visible menu item",
contexts: contexts,
});
await other_extension.callMenuApi("create", {
id: "action_item",
title: "other menu item",
contexts: contexts,
});
await doOpenMenu(extension);
await extension.awaitMessage("onShown fired");
if (expectOtherItems) {
await other_extension.awaitMessage("onShown fired");
}
let elem = extension.getXULElementByMenuId("action_item");
is(elem.getAttribute("label"), "visible menu item", "extension menu shown");
elem = other_extension.getXULElementByMenuId("action_item");
if (expectOtherItems) {
is(elem.getAttribute("label"), "other menu item",
"other extension's menu is also shown");
} else {
is(elem, null, "other extension's menu should be hidden");
}
await extension.callMenuApi("update", "action_item", {title: "changed"});
await other_extension.callMenuApi("update", "action_item", {title: "foo"});
await other_extension.callMenuApi("refresh");
// refreshing the menu of an unrelated extension should not affect the menu
// of another extension.
elem = extension.getXULElementByMenuId("action_item");
is(elem.getAttribute("label"), "visible menu item", "extension menu shown");
elem = other_extension.getXULElementByMenuId("action_item");
if (expectOtherItems) {
is(elem.getAttribute("label"), "foo", "other extension's item is updated");
} else {
is(elem, null, "other extension's menu should still be hidden");
}
await doCloseMenu();
await extension.unload();
await other_extension.unload();
}
add_task(async function refresh_menus_with_browser_action() {
await testRefreshMenusWhileVisible({
const args = {
contexts: ["browser_action"],
async doOpenMenu(extension) {
await openActionContextMenu(extension, "browser");
@ -166,12 +233,15 @@ add_task(async function refresh_menus_with_browser_action() {
async doCloseMenu() {
await closeActionContextMenu();
},
});
};
await testRefreshMenusWhileVisible(args);
args.expectOtherItems = false;
await testRefreshOther(args);
});
add_task(async function refresh_menus_with_tab() {
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
await testRefreshMenusWhileVisible({
const args = {
contexts: ["tab"],
async doOpenMenu() {
await openTabContextMenu();
@ -179,12 +249,15 @@ add_task(async function refresh_menus_with_tab() {
async doCloseMenu() {
await closeTabContextMenu();
},
});
};
await testRefreshMenusWhileVisible(args);
args.expectOtherItems = true;
await testRefreshOther(args);
BrowserTestUtils.removeTab(tab);
});
add_task(async function refresh_menus_with_tools_menu() {
await testRefreshMenusWhileVisible({
const args = {
contexts: ["tools_menu"],
async doOpenMenu() {
await openToolsMenu();
@ -192,12 +265,15 @@ add_task(async function refresh_menus_with_tools_menu() {
async doCloseMenu() {
await closeToolsMenu();
},
});
};
await testRefreshMenusWhileVisible(args);
args.expectOtherItems = true;
await testRefreshOther(args);
});
add_task(async function refresh_menus_with_page() {
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
await testRefreshMenusWhileVisible({
const args = {
contexts: ["page"],
async doOpenMenu() {
await openContextMenu("body");
@ -205,7 +281,10 @@ add_task(async function refresh_menus_with_page() {
async doCloseMenu() {
await closeExtensionContextMenu();
},
});
};
await testRefreshMenusWhileVisible(args);
args.expectOtherItems = true;
await testRefreshOther(args);
BrowserTestUtils.removeTab(tab);
});
@ -246,46 +325,32 @@ add_task(async function refresh_without_menus_at_onShown() {
BrowserTestUtils.removeTab(tab);
});
add_task(async function refresh_menus_with_browser_action() {
add_task(async function refresh_without_onShown() {
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
let extension = loadExtensionWithMenusApi();
let other_extension = loadExtensionWithMenusApi();
await extension.startup();
await other_extension.startup();
await extension.removeOnShownListener();
const doOpenMenu = () => openContextMenu("body");
const doCloseMenu = () => closeExtensionContextMenu();
await doOpenMenu();
await extension.callMenuApi("create", {
id: "action_item",
title: "visible menu item",
contexts: ["browser_action"],
id: "too late",
title: "created after shown",
});
await other_extension.callMenuApi("create", {
id: "action_item",
title: "other menu item",
contexts: ["browser_action"],
});
is(extension.getXULElementByMenuId("too late"), null,
"item created after shown is not visible before refresh");
await openActionContextMenu(extension, "browser");
await extension.awaitMessage("onShown fired");
await extension.callMenuApi("refresh");
let elem = extension.getXULElementByMenuId("too late");
is(elem.getAttribute("label"), "created after shown",
"refresh updates the menu even without onShown");
let elem = extension.getXULElementByMenuId("action_item");
is(elem.getAttribute("label"), "visible menu item", "extension menu shown");
elem = other_extension.getXULElementByMenuId("action_item");
is(elem, null, "other extension's menu should be hidden");
await extension.callMenuApi("update", "action_item", {title: "changed"});
await other_extension.callMenuApi("update", "action_item", {title: "foo"});
await other_extension.callMenuApi("refresh");
// refreshing the menu of an unrelated extension should not affect the menu
// of another extension.
elem = extension.getXULElementByMenuId("action_item");
is(elem.getAttribute("label"), "visible menu item", "extension menu shown");
elem = other_extension.getXULElementByMenuId("action_item");
is(elem, null, "other extension's menu should be hidden");
await closeActionContextMenu();
await doCloseMenu();
await extension.unload();
await other_extension.unload();
BrowserTestUtils.removeTab(tab);
});
add_task(async function refresh_menus_during_navigation() {