Bug 1446956 - Grant access to the clicked tab in menus.onClicked
MozReview-Commit-ID: 3mVWOEcZFYn
--- a/browser/components/extensions/parent/ext-menus.js
+++ b/browser/components/extensions/parent/ext-menus.js
@@ -265,18 +265,18 @@ var gMenuBuilder = {
if (child.type == "radio" && child.groupName == item.groupName) {
child.checked = false;
}
}
// Select the clicked radio item.
item.checked = true;
}
- if (!contextData.onBookmark) {
- item.tabManager.addActiveTabPermission();
+ if (contextData.tab) {
+ item.tabManager.addActiveTabPermission(contextData.tab);
}
let info = item.getClickInfo(contextData, wasChecked);
const map = {shiftKey: "Shift", altKey: "Alt", metaKey: "Command", ctrlKey: "Ctrl"};
info.modifiers = Object.keys(map).filter(key => event[key]).map(key => map[key]);
if (event.ctrlKey && AppConstants.platform === "macosx") {
info.modifiers.push("MacCtrl");
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -98,16 +98,17 @@ support-files =
skip-if = (verify && (os == 'linux' || os == 'mac'))
[browser_ext_getViews.js]
[browser_ext_history_redirect.js]
[browser_ext_identity_indication.js]
[browser_ext_incognito_views.js]
[browser_ext_incognito_popup.js]
[browser_ext_lastError.js]
[browser_ext_menus.js]
+[browser_ext_menus_activeTab.js]
[browser_ext_menus_errors.js]
[browser_ext_menus_event_order.js]
[browser_ext_menus_events.js]
[browser_ext_menus_refresh.js]
[browser_ext_omnibox.js]
skip-if = (debug && (os == 'linux' || os == 'mac')) || (verify && (os == 'linux' || os == 'mac')) # Bug 1417052
[browser_ext_openPanel.js]
skip-if = (verify && !debug && (os == 'linux' || os == 'mac'))
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_menus_activeTab.js
@@ -0,0 +1,84 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+// Opens two tabs at the start of the tab strip and focuses the second tab.
+// Then an extension menu is registered for the "tab" context and a menu is
+// opened on the first tab and the extension menu item is clicked.
+// This triggers the onTabMenuClicked handler.
+async function openTwoTabsAndOpenTabMenu(onTabMenuClicked) {
+ const PAGE_URL = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html";
+ const OTHER_URL = "http://127.0.0.1:8888/browser/browser/components/extensions/test/browser/context.html";
+
+ let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE_URL);
+ let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, OTHER_URL);
+ // Move the first tab to the start so that it can be found by the .tabbrowser-tab selector below.
+ gBrowser.moveTabTo(tab1, 0);
+ gBrowser.moveTabTo(tab2, 1);
+
+ async function background(onTabMenuClicked) {
+ browser.menus.onClicked.addListener(async (info, tab) => {
+ await onTabMenuClicked(info, tab);
+ browser.test.sendMessage("onCommand_on_tab_click");
+ });
+
+ browser.menus.create({
+ title: "menu item on tab",
+ contexts: ["tab"],
+ }, () => {
+ browser.test.sendMessage("ready");
+ });
+ }
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ "permissions": ["menus", "activeTab"],
+ },
+ background: `(${background})(${onTabMenuClicked})`,
+ });
+
+ await extension.startup();
+ await extension.awaitMessage("ready");
+
+ // The .tabbrowser-tab selector matches the first tab (tab1).
+ let menu = await openChromeContextMenu("tabContextMenu", ".tabbrowser-tab", window);
+ let menuItem = menu.getElementsByAttribute("label", "menu item on tab")[0];
+ await closeTabContextMenu(menuItem);
+ await extension.awaitMessage("onCommand_on_tab_click");
+
+ await extension.unload();
+
+ BrowserTestUtils.removeTab(tab1);
+ BrowserTestUtils.removeTab(tab2);
+}
+
+add_task(async function activeTabForTabMenu() {
+ await openTwoTabsAndOpenTabMenu(async function onTabMenuClicked(info, tab) {
+ browser.test.assertEq(0, tab.index, "Expected a menu on the first tab.");
+
+ try {
+ let [actualUrl] = await browser.tabs.executeScript(tab.id, {code: "document.URL"});
+ browser.test.assertEq(tab.url, actualUrl, "Content script to execute in the first tab");
+ // (the activeTab permission should have been granted to the first tab.)
+ } catch (e) {
+ browser.test.fail(`Unexpected error in executeScript: ${e} :: ${e.stack}`);
+ }
+ });
+});
+
+add_task(async function noActiveTabForCurrentTab() {
+ await openTwoTabsAndOpenTabMenu(async function onTabMenuClicked(info, tab) {
+ const PAGE_URL = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html";
+ browser.test.assertEq(0, tab.index, "Expected a menu on the first tab.");
+ browser.test.assertEq(PAGE_URL, tab.url, "Expected tab.url to be available for the first tab");
+
+ let [tab2] = await browser.tabs.query({windowId: tab.windowId, index: 1});
+ browser.test.assertTrue(tab2.active, "The second tab should be focused.");
+ browser.test.assertEq(undefined, tab2.url, "Expected tab.url to be unavailable for the second tab.");
+
+ await browser.test.assertRejects(
+ browser.tabs.executeScript(tab2.id, {code: "document.URL"}),
+ /Missing host permission for the tab/,
+ "Content script should not run in the second tab");
+ // (The activeTab permission was granted to the first tab, not tab2.)
+ });
+});