Bug 1602384 - Make sure menu.onShown API event is still emitted after a destroyed extension context. r=robwu

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Luca Greco 2020-01-22 12:21:14 +00:00
Родитель e409c9441c
Коммит 324d405b13
3 изменённых файлов: 81 добавлений и 5 удалений

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

@ -41,8 +41,10 @@ var gRootItems = new Map();
// Menu IDs that were eligible for being shown in the current menu.
var gShownMenuItems = new DefaultMap(() => []);
// Set of extensions that are listening to onShown.
var gOnShownSubscribers = new Set();
// Map[Extension -> Set[Contexts]]
// A DefaultMap (keyed by extension) which keeps track of the
// contexts with a subscribed onShown event listener.
var gOnShownSubscribers = new DefaultMap(() => new Set());
// If id is not specified for an item we use an integer.
var gNextMenuItemID = 0;
@ -571,7 +573,9 @@ var gMenuBuilder = {
if (contextData.onBrowserAction || contextData.onPageAction) {
dispatchOnShownEvent(contextData.extension);
} else {
gOnShownSubscribers.forEach(dispatchOnShownEvent);
for (const extension of gOnShownSubscribers.keys()) {
dispatchOnShownEvent(extension);
}
}
this.contextData = contextData;
@ -1270,10 +1274,14 @@ this.menusInternal = class extends ExtensionAPI {
let tab = nativeTab && extension.tabManager.convert(nativeTab);
fire.sync(info, tab);
};
gOnShownSubscribers.add(extension);
gOnShownSubscribers.get(extension).add(context);
extension.on("webext-menu-shown", listener);
return () => {
gOnShownSubscribers.delete(extension);
const contexts = gOnShownSubscribers.get(extension);
contexts.delete(context);
if (contexts.size === 0) {
gOnShownSubscribers.delete(extension);
}
extension.off("webext-menu-shown", listener);
};
},

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

@ -141,6 +141,7 @@ skip-if = (verify && (os == 'linux' || os == 'mac'))
[browser_ext_menus_event_order.js]
[browser_ext_menus_events.js]
skip-if = os == 'linux' #Bug 1433892
[browser_ext_menus_events_after_context_destroy.js]
[browser_ext_menus_incognito.js]
[browser_ext_menus_refresh.js]
[browser_ext_menus_replace_menu.js]

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

@ -0,0 +1,67 @@
/* 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/. */
"use strict";
// This test does verify that the menus API events are still emitted when
// there are extension context alive with subscribed listeners
// (See Bug 1602384).
add_task(async function test_subscribed_events_fired_after_context_destroy() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["menus"],
},
files: {
"page.html": `<!DOCTYPE html>
<meta charset="uft-8"><script src="page.js"></script>
Extension Page
`,
"page.js": async function() {
browser.menus.onShown.addListener(() => {
browser.test.sendMessage("menu-onShown");
});
browser.menus.onHidden.addListener(() => {
browser.test.sendMessage("menu-onHidden");
});
// Call an API method implemented in the parent process
// to ensure the menu listeners are subscribed in the
// parent process.
await browser.runtime.getBrowserInfo();
browser.test.sendMessage("page-loaded");
},
},
});
await extension.startup();
const pageURL = `moz-extension://${extension.uuid}/page.html`;
info("Loading extension page in a tab");
const tab1 = BrowserTestUtils.addTab(gBrowser, pageURL);
await extension.awaitMessage("page-loaded");
info("Loading extension page in another tab");
const tab2 = BrowserTestUtils.addTab(gBrowser, pageURL);
await extension.awaitMessage("page-loaded");
info("Select the first tab");
gBrowser.selectedTab = tab1;
info("Remove the second tab");
BrowserTestUtils.removeTab(tab2);
info("Open a context menu and expect menu.onShown to be fired");
await window.promiseDocumentFlushed(() => {});
await openContextMenu("body");
await extension.awaitMessage("menu-onShown");
info("Close context menu and expect menu.onHidden to be fired");
await closeExtensionContextMenu();
await extension.awaitMessage("menu-onHidden");
ok(true, "The expected menu events have been fired");
BrowserTestUtils.removeTab(tab1);
await extension.unload();
});