920 lines
25 KiB
JavaScript
920 lines
25 KiB
JavaScript
/* 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";
|
|
|
|
const { ExtensionPermissions } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/ExtensionPermissions.sys.mjs"
|
|
);
|
|
|
|
const PAGE =
|
|
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html";
|
|
const PAGE_BASE = PAGE.replace("context.html", "");
|
|
const PAGE_HOST_PATTERN = "http://mochi.test/*";
|
|
|
|
const EXPECT_TARGET_ELEMENT = 13337;
|
|
|
|
async function grantOptionalPermission(extension, permissions) {
|
|
let ext = WebExtensionPolicy.getByID(extension.id).extension;
|
|
return ExtensionPermissions.add(extension.id, permissions, ext);
|
|
}
|
|
|
|
var someOtherTab, testTab;
|
|
|
|
add_setup(async function () {
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [["extensions.manifestV3.enabled", true]],
|
|
});
|
|
|
|
// To help diagnose an intermittent later.
|
|
SimpleTest.requestCompleteLog();
|
|
|
|
// Setup the test tab now, rather than for each test
|
|
someOtherTab = gBrowser.selectedTab;
|
|
testTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
|
|
registerCleanupFunction(() => BrowserTestUtils.removeTab(testTab));
|
|
});
|
|
|
|
// Registers a context menu using menus.create(menuCreateParams) and checks
|
|
// whether the menus.onShown and menus.onHidden events are fired as expected.
|
|
// doOpenMenu must open the menu and its returned promise must resolve after the
|
|
// menu is shown. Similarly, doCloseMenu must hide the menu.
|
|
async function testShowHideEvent({
|
|
menuCreateParams,
|
|
id,
|
|
doOpenMenu,
|
|
doCloseMenu,
|
|
expectedShownEvent,
|
|
expectedShownEventWithPermissions = null,
|
|
forceTabToBackground = false,
|
|
manifest_version = 2,
|
|
}) {
|
|
async function background(menu_create_params) {
|
|
const [tab] = await browser.tabs.query({
|
|
active: true,
|
|
currentWindow: true,
|
|
});
|
|
if (browser.pageAction) {
|
|
await browser.pageAction.show(tab.id);
|
|
}
|
|
|
|
let shownEvents = [];
|
|
let hiddenEvents = [];
|
|
|
|
browser.menus.onShown.addListener((...args) => {
|
|
browser.test.log(`==> onShown args ${JSON.stringify(args)}`);
|
|
let [info, shownTab] = args;
|
|
if (info.targetElementId) {
|
|
// In this test, we aren't interested in the exact value,
|
|
// only in whether it is set or not.
|
|
info.targetElementId = 13337; // = EXPECT_TARGET_ELEMENT
|
|
}
|
|
shownEvents.push(info);
|
|
|
|
if (menu_create_params.title.includes("TEST_EXPECT_NO_TAB")) {
|
|
browser.test.assertEq(undefined, shownTab, "expect no tab");
|
|
} else {
|
|
browser.test.assertEq(tab.id, shownTab?.id, "expected tab");
|
|
}
|
|
browser.test.assertEq(2, args.length, "expected number of onShown args");
|
|
});
|
|
browser.menus.onHidden.addListener(event => hiddenEvents.push(event));
|
|
|
|
browser.test.onMessage.addListener(async msg => {
|
|
switch (msg) {
|
|
case "register-menu":
|
|
let menuId;
|
|
await new Promise(resolve => {
|
|
menuId = browser.menus.create(menu_create_params, resolve);
|
|
});
|
|
browser.test.assertEq(
|
|
0,
|
|
shownEvents.length,
|
|
"no onShown before menu"
|
|
);
|
|
browser.test.assertEq(
|
|
0,
|
|
hiddenEvents.length,
|
|
"no onHidden before menu"
|
|
);
|
|
browser.test.sendMessage("menu-registered", menuId);
|
|
break;
|
|
case "assert-menu-shown":
|
|
browser.test.assertEq(1, shownEvents.length, "expected onShown");
|
|
browser.test.assertEq(
|
|
0,
|
|
hiddenEvents.length,
|
|
"no onHidden before closing"
|
|
);
|
|
browser.test.sendMessage("onShown-event-data", shownEvents[0]);
|
|
break;
|
|
case "assert-menu-hidden":
|
|
browser.test.assertEq(
|
|
1,
|
|
shownEvents.length,
|
|
"expected no more onShown"
|
|
);
|
|
browser.test.assertEq(1, hiddenEvents.length, "expected onHidden");
|
|
browser.test.sendMessage("onHidden-event-data", hiddenEvents[0]);
|
|
break;
|
|
case "optional-menu-shown-with-permissions":
|
|
browser.test.assertEq(
|
|
2,
|
|
shownEvents.length,
|
|
"expected second onShown"
|
|
);
|
|
browser.test.sendMessage("onShown-event-data2", shownEvents[1]);
|
|
break;
|
|
}
|
|
});
|
|
|
|
browser.test.sendMessage("ready");
|
|
}
|
|
|
|
// Tab must initially open as a foreground tab, because the test extension
|
|
// looks for the active tab.
|
|
if (gBrowser.selectedTab != testTab) {
|
|
await BrowserTestUtils.switchTab(gBrowser, testTab);
|
|
}
|
|
|
|
let useAddonManager, browser_specific_settings;
|
|
const action = manifest_version < 3 ? "browser_action" : "action";
|
|
// hook up AOM so event pages in MV3 work.
|
|
if (manifest_version > 2) {
|
|
browser_specific_settings = { gecko: { id } };
|
|
useAddonManager = "temporary";
|
|
}
|
|
let extension = ExtensionTestUtils.loadExtension({
|
|
background: `(${background})(${JSON.stringify(menuCreateParams)})`,
|
|
useAddonManager,
|
|
manifest: {
|
|
manifest_version,
|
|
browser_specific_settings,
|
|
page_action: {},
|
|
[action]: {
|
|
default_popup: "popup.html",
|
|
default_area: "navbar",
|
|
},
|
|
permissions: ["menus"],
|
|
optional_permissions: [PAGE_HOST_PATTERN],
|
|
},
|
|
files: {
|
|
"popup.html": `<!DOCTYPE html><meta charset="utf-8">Popup body`,
|
|
},
|
|
});
|
|
await extension.startup();
|
|
await extension.awaitMessage("ready");
|
|
extension.sendMessage("register-menu");
|
|
let menuId = await extension.awaitMessage("menu-registered");
|
|
info(`menu registered ${menuId}`);
|
|
|
|
if (forceTabToBackground && gBrowser.selectedTab != someOtherTab) {
|
|
await BrowserTestUtils.switchTab(gBrowser, someOtherTab);
|
|
}
|
|
|
|
await doOpenMenu(extension, testTab);
|
|
extension.sendMessage("assert-menu-shown");
|
|
let shownEvent = await extension.awaitMessage("onShown-event-data");
|
|
|
|
// menuCreateParams.id is not set, therefore a numeric ID is generated.
|
|
expectedShownEvent.menuIds = [menuId];
|
|
Assert.deepEqual(shownEvent, expectedShownEvent, "expected onShown info");
|
|
|
|
await doCloseMenu(extension);
|
|
extension.sendMessage("assert-menu-hidden");
|
|
let hiddenEvent = await extension.awaitMessage("onHidden-event-data");
|
|
is(hiddenEvent, undefined, "expected no event data for onHidden event");
|
|
|
|
if (expectedShownEventWithPermissions) {
|
|
expectedShownEventWithPermissions.menuIds = [menuId];
|
|
await grantOptionalPermission(extension, {
|
|
permissions: [],
|
|
origins: [PAGE_HOST_PATTERN],
|
|
});
|
|
await doOpenMenu(extension, testTab);
|
|
extension.sendMessage("optional-menu-shown-with-permissions");
|
|
let shownEvent2 = await extension.awaitMessage("onShown-event-data2");
|
|
Assert.deepEqual(
|
|
shownEvent2,
|
|
expectedShownEventWithPermissions,
|
|
"expected onShown info when host permissions are enabled"
|
|
);
|
|
await doCloseMenu(extension);
|
|
}
|
|
|
|
await extension.unload();
|
|
}
|
|
|
|
// Make sure that we won't trigger onShown when extensions cannot add menus.
|
|
add_task(async function test_no_show_hide_for_unsupported_menu() {
|
|
let extension = ExtensionTestUtils.loadExtension({
|
|
background() {
|
|
let events = [];
|
|
browser.menus.onShown.addListener(data => events.push(data));
|
|
browser.menus.onHidden.addListener(() => events.push("onHidden"));
|
|
browser.test.onMessage.addListener(() => {
|
|
browser.test.assertEq(
|
|
"[]",
|
|
JSON.stringify(events),
|
|
"Should not have any events when the context is unsupported."
|
|
);
|
|
browser.test.notifyPass("done listening to menu events");
|
|
});
|
|
},
|
|
manifest: {
|
|
permissions: ["menus"],
|
|
},
|
|
});
|
|
|
|
await extension.startup();
|
|
// Open and close a menu for which the extension cannot add menu items.
|
|
await openChromeContextMenu("toolbar-context-menu", "#stop-reload-button");
|
|
await closeChromeContextMenu("toolbar-context-menu");
|
|
|
|
extension.sendMessage("check menu events");
|
|
await extension.awaitFinish("done listening to menu events");
|
|
|
|
await extension.unload();
|
|
});
|
|
|
|
add_task(async function test_show_hide_without_menu_item() {
|
|
let extension = ExtensionTestUtils.loadExtension({
|
|
background() {
|
|
let events = [];
|
|
browser.menus.onShown.addListener(data => events.push(data));
|
|
browser.menus.onHidden.addListener(() => events.push("onHidden"));
|
|
browser.test.onMessage.addListener(() => {
|
|
browser.test.sendMessage("events from menuless extension", events);
|
|
});
|
|
|
|
browser.menus.create({
|
|
title: "never shown",
|
|
documentUrlPatterns: ["*://url-pattern-that-never-matches/*"],
|
|
contexts: ["all"],
|
|
});
|
|
},
|
|
manifest: {
|
|
permissions: ["menus", PAGE_HOST_PATTERN],
|
|
},
|
|
});
|
|
|
|
await extension.startup();
|
|
|
|
// Run another context menu test where onShown/onHidden will fire.
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "any menu item",
|
|
contexts: ["all"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["page", "all"],
|
|
viewType: "tab",
|
|
editable: false,
|
|
frameId: 0,
|
|
},
|
|
async doOpenMenu() {
|
|
await openContextMenu("body");
|
|
},
|
|
async doCloseMenu() {
|
|
await closeExtensionContextMenu();
|
|
},
|
|
});
|
|
|
|
// Now the menu has been shown and hidden, and in another extension the
|
|
// onShown/onHidden events have been dispatched.
|
|
extension.sendMessage("check menu events");
|
|
let events = await extension.awaitMessage("events from menuless extension");
|
|
is(events.length, 2, "expect two events");
|
|
is(events[1], "onHidden", "last event should be onHidden");
|
|
ok(events[0].targetElementId, "info.targetElementId must be set in onShown");
|
|
delete events[0].targetElementId;
|
|
Assert.deepEqual(
|
|
events[0],
|
|
{
|
|
menuIds: [],
|
|
contexts: ["page", "all"],
|
|
viewType: "tab",
|
|
editable: false,
|
|
pageUrl: PAGE,
|
|
frameId: 0,
|
|
},
|
|
"expected onShown info from menuless extension"
|
|
);
|
|
await extension.unload();
|
|
});
|
|
|
|
add_task(async function test_show_hide_pageAction() {
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "pageAction item",
|
|
contexts: ["page_action"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["page_action", "all"],
|
|
viewType: undefined,
|
|
editable: false,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["page_action", "all"],
|
|
viewType: undefined,
|
|
editable: false,
|
|
pageUrl: PAGE,
|
|
},
|
|
async doOpenMenu(extension) {
|
|
await openActionContextMenu(extension, "page");
|
|
},
|
|
async doCloseMenu() {
|
|
await closeActionContextMenu(null, "page");
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_pageAction_v3() {
|
|
await testShowHideEvent({
|
|
manifest_version: 3,
|
|
id: "page-action@mochitest",
|
|
menuCreateParams: {
|
|
id: "page_action_item",
|
|
title: "pageAction item",
|
|
contexts: ["page_action"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["page_action", "all"],
|
|
viewType: undefined,
|
|
editable: false,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["page_action", "all"],
|
|
viewType: undefined,
|
|
editable: false,
|
|
pageUrl: PAGE,
|
|
},
|
|
async doOpenMenu(extension) {
|
|
await openActionContextMenu(extension, "page");
|
|
},
|
|
async doCloseMenu() {
|
|
await closeActionContextMenu(null, "page");
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_browserAction() {
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "browserAction item",
|
|
contexts: ["browser_action"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["browser_action", "all"],
|
|
viewType: undefined,
|
|
editable: false,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["browser_action", "all"],
|
|
viewType: undefined,
|
|
editable: false,
|
|
pageUrl: PAGE,
|
|
},
|
|
async doOpenMenu(extension) {
|
|
await openActionContextMenu(extension, "browser");
|
|
},
|
|
async doCloseMenu() {
|
|
await closeActionContextMenu();
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_browserAction_v3() {
|
|
await testShowHideEvent({
|
|
manifest_version: 3,
|
|
id: "browser-action@mochitest",
|
|
menuCreateParams: {
|
|
id: "action_item",
|
|
title: "Action item",
|
|
contexts: ["action"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["action", "all"],
|
|
viewType: undefined,
|
|
editable: false,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["action", "all"],
|
|
viewType: undefined,
|
|
editable: false,
|
|
pageUrl: PAGE,
|
|
},
|
|
async doOpenMenu(extension) {
|
|
await openActionContextMenu(extension, "browser");
|
|
},
|
|
async doCloseMenu() {
|
|
await closeActionContextMenu();
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_browserAction_popup() {
|
|
let popupUrl;
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "browserAction popup - TEST_EXPECT_NO_TAB",
|
|
contexts: ["all", "browser_action"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["page", "all"],
|
|
viewType: "popup",
|
|
frameId: 0,
|
|
editable: false,
|
|
get pageUrl() {
|
|
return popupUrl;
|
|
},
|
|
targetElementId: EXPECT_TARGET_ELEMENT,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["page", "all"],
|
|
viewType: "popup",
|
|
frameId: 0,
|
|
editable: false,
|
|
get pageUrl() {
|
|
return popupUrl;
|
|
},
|
|
targetElementId: EXPECT_TARGET_ELEMENT,
|
|
},
|
|
async doOpenMenu(extension) {
|
|
popupUrl = `moz-extension://${extension.uuid}/popup.html`;
|
|
await clickBrowserAction(extension);
|
|
await openContextMenuInPopup(extension);
|
|
},
|
|
async doCloseMenu(extension) {
|
|
await closeExtensionContextMenu();
|
|
await closeBrowserAction(extension);
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_browserAction_popup_v3() {
|
|
let popupUrl;
|
|
await testShowHideEvent({
|
|
manifest_version: 3,
|
|
id: "browser-action-popup@mochitest",
|
|
menuCreateParams: {
|
|
id: "action_popup",
|
|
title: "Action popup - TEST_EXPECT_NO_TAB",
|
|
contexts: ["all", "action"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["page", "all"],
|
|
viewType: "popup",
|
|
frameId: 0,
|
|
editable: false,
|
|
get pageUrl() {
|
|
return popupUrl;
|
|
},
|
|
targetElementId: EXPECT_TARGET_ELEMENT,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["page", "all"],
|
|
viewType: "popup",
|
|
frameId: 0,
|
|
editable: false,
|
|
get pageUrl() {
|
|
return popupUrl;
|
|
},
|
|
targetElementId: EXPECT_TARGET_ELEMENT,
|
|
},
|
|
async doOpenMenu(extension) {
|
|
popupUrl = `moz-extension://${extension.uuid}/popup.html`;
|
|
await clickBrowserAction(extension);
|
|
await openContextMenuInPopup(extension);
|
|
},
|
|
async doCloseMenu(extension) {
|
|
await closeExtensionContextMenu();
|
|
await closeBrowserAction(extension);
|
|
},
|
|
});
|
|
});
|
|
|
|
// Common code used by test_show_hide_tab and test_show_hide_tab_via_tab_panel.
|
|
async function testShowHideTabMenu({
|
|
doOpenTabContextMenu,
|
|
doCloseTabContextMenu,
|
|
}) {
|
|
await testShowHideEvent({
|
|
// To verify that the event matches the contextmenu target, switch to
|
|
// an unrelated tab before opening a contextmenu on the desired tab.
|
|
forceTabToBackground: true,
|
|
menuCreateParams: {
|
|
title: "tab menu item",
|
|
contexts: ["tab"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["tab"],
|
|
viewType: undefined,
|
|
editable: false,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["tab"],
|
|
viewType: undefined,
|
|
editable: false,
|
|
pageUrl: PAGE,
|
|
},
|
|
async doOpenMenu(extension, contextTab) {
|
|
await doOpenTabContextMenu(contextTab);
|
|
},
|
|
async doCloseMenu() {
|
|
await doCloseTabContextMenu();
|
|
},
|
|
});
|
|
}
|
|
|
|
add_task(async function test_show_hide_tab() {
|
|
await testShowHideTabMenu({
|
|
async doOpenTabContextMenu(contextTab) {
|
|
await openTabContextMenu(contextTab);
|
|
},
|
|
async doCloseTabContextMenu() {
|
|
await closeTabContextMenu();
|
|
},
|
|
});
|
|
});
|
|
|
|
// Checks that right-clicking on a tab in the all-tabs panel
|
|
// results in an event that is associated with the expected tab.
|
|
add_task(async function test_show_hide_tab_via_tab_panel() {
|
|
gTabsPanel.init();
|
|
const allTabsView = document.getElementById("allTabsMenu-allTabsView");
|
|
|
|
await testShowHideTabMenu({
|
|
async doOpenTabContextMenu(contextTab) {
|
|
// Show the tabs panel.
|
|
let allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(
|
|
allTabsView,
|
|
"ViewShown"
|
|
);
|
|
gTabsPanel.showAllTabsPanel();
|
|
await allTabsPopupShownPromise;
|
|
|
|
// Find the menu item that is associated with the given tab
|
|
let index = Array.prototype.findIndex.call(
|
|
gTabsPanel.allTabsViewTabs.children,
|
|
toolbaritem => toolbaritem.tab === contextTab
|
|
);
|
|
Assert.notStrictEqual(
|
|
index,
|
|
-1,
|
|
"sanity check: tabs panel has item for the tab"
|
|
);
|
|
|
|
// Finally, open the context menu on it.
|
|
await openChromeContextMenu(
|
|
"tabContextMenu",
|
|
`.all-tabs-item:nth-child(${index + 1})`
|
|
);
|
|
},
|
|
async doCloseTabContextMenu() {
|
|
await closeTabContextMenu();
|
|
let allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(
|
|
allTabsView.panelMultiView,
|
|
"PanelMultiViewHidden"
|
|
);
|
|
gTabsPanel.hideAllTabsPanel();
|
|
await allTabsPopupHiddenPromise;
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_tools_menu() {
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "menu item",
|
|
contexts: ["tools_menu"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["tools_menu"],
|
|
viewType: undefined,
|
|
editable: false,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["tools_menu"],
|
|
viewType: undefined,
|
|
editable: false,
|
|
pageUrl: PAGE,
|
|
},
|
|
async doOpenMenu() {
|
|
await openToolsMenu();
|
|
},
|
|
async doCloseMenu() {
|
|
await closeToolsMenu();
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_page() {
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "page menu item",
|
|
contexts: ["page"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["page", "all"],
|
|
viewType: "tab",
|
|
editable: false,
|
|
frameId: 0,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["page", "all"],
|
|
viewType: "tab",
|
|
editable: false,
|
|
pageUrl: PAGE,
|
|
frameId: 0,
|
|
targetElementId: EXPECT_TARGET_ELEMENT,
|
|
},
|
|
async doOpenMenu() {
|
|
await openContextMenu("body");
|
|
},
|
|
async doCloseMenu() {
|
|
await closeExtensionContextMenu();
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_frame() {
|
|
// frame info will be determined before opening the menu.
|
|
let frameId;
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "subframe menu item",
|
|
contexts: ["frame"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["frame", "all"],
|
|
viewType: "tab",
|
|
editable: false,
|
|
get frameId() {
|
|
return frameId;
|
|
},
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["frame", "all"],
|
|
viewType: "tab",
|
|
editable: false,
|
|
get frameId() {
|
|
return frameId;
|
|
},
|
|
pageUrl: PAGE,
|
|
frameUrl: PAGE_BASE + "context_frame.html",
|
|
targetElementId: EXPECT_TARGET_ELEMENT,
|
|
},
|
|
async doOpenMenu() {
|
|
frameId = await SpecialPowers.spawn(
|
|
gBrowser.selectedBrowser,
|
|
[],
|
|
function () {
|
|
const { WebNavigationFrames } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/WebNavigationFrames.sys.mjs"
|
|
);
|
|
|
|
let { contentWindow } = content.document.getElementById("frame");
|
|
return WebNavigationFrames.getFrameId(contentWindow);
|
|
}
|
|
);
|
|
await openContextMenuInFrame();
|
|
},
|
|
async doCloseMenu() {
|
|
await closeExtensionContextMenu();
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_password() {
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "password item",
|
|
contexts: ["password"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["editable", "password", "all"],
|
|
viewType: "tab",
|
|
editable: true,
|
|
frameId: 0,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["editable", "password", "all"],
|
|
viewType: "tab",
|
|
editable: true,
|
|
frameId: 0,
|
|
pageUrl: PAGE,
|
|
targetElementId: EXPECT_TARGET_ELEMENT,
|
|
},
|
|
async doOpenMenu() {
|
|
await openContextMenu("#password");
|
|
},
|
|
async doCloseMenu() {
|
|
await closeExtensionContextMenu();
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_link() {
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "link item",
|
|
contexts: ["link"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["link", "all"],
|
|
viewType: "tab",
|
|
editable: false,
|
|
frameId: 0,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["link", "all"],
|
|
viewType: "tab",
|
|
editable: false,
|
|
frameId: 0,
|
|
linkText: "Some link",
|
|
linkUrl: PAGE_BASE + "some-link",
|
|
pageUrl: PAGE,
|
|
targetElementId: EXPECT_TARGET_ELEMENT,
|
|
},
|
|
async doOpenMenu() {
|
|
await openContextMenu("#link1");
|
|
},
|
|
async doCloseMenu() {
|
|
await closeExtensionContextMenu();
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_image_link() {
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "image item",
|
|
contexts: ["image"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["image", "link", "all"],
|
|
viewType: "tab",
|
|
mediaType: "image",
|
|
editable: false,
|
|
frameId: 0,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["image", "link", "all"],
|
|
viewType: "tab",
|
|
mediaType: "image",
|
|
editable: false,
|
|
frameId: 0,
|
|
// Apparently, when a link has no content, its href is used as linkText.
|
|
linkText: PAGE_BASE + "image-around-some-link",
|
|
linkUrl: PAGE_BASE + "image-around-some-link",
|
|
srcUrl: PAGE_BASE + "ctxmenu-image.png",
|
|
pageUrl: PAGE,
|
|
targetElementId: EXPECT_TARGET_ELEMENT,
|
|
},
|
|
async doOpenMenu() {
|
|
await openContextMenu("#img-wrapped-in-link");
|
|
},
|
|
async doCloseMenu() {
|
|
await closeExtensionContextMenu();
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_editable_selection() {
|
|
let selectionText;
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "editable item",
|
|
contexts: ["editable"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["editable", "selection", "all"],
|
|
viewType: "tab",
|
|
editable: true,
|
|
frameId: 0,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["editable", "selection", "all"],
|
|
viewType: "tab",
|
|
editable: true,
|
|
frameId: 0,
|
|
pageUrl: PAGE,
|
|
get selectionText() {
|
|
return selectionText;
|
|
},
|
|
targetElementId: EXPECT_TARGET_ELEMENT,
|
|
},
|
|
async doOpenMenu() {
|
|
// Select lots of text in the test page before opening the menu.
|
|
selectionText = await SpecialPowers.spawn(
|
|
gBrowser.selectedBrowser,
|
|
[],
|
|
function () {
|
|
let node = content.document.getElementById("editabletext");
|
|
node.scrollIntoView();
|
|
node.select();
|
|
node.focus();
|
|
return node.value;
|
|
}
|
|
);
|
|
|
|
await openContextMenu("#editabletext");
|
|
},
|
|
async doCloseMenu() {
|
|
await closeExtensionContextMenu();
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_video() {
|
|
const VIDEO_URL = "data:video/webm,xxx";
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "video item",
|
|
contexts: ["video"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["video", "all"],
|
|
viewType: "tab",
|
|
mediaType: "video",
|
|
editable: false,
|
|
frameId: 0,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["video", "all"],
|
|
viewType: "tab",
|
|
mediaType: "video",
|
|
editable: false,
|
|
frameId: 0,
|
|
srcUrl: VIDEO_URL,
|
|
pageUrl: PAGE,
|
|
targetElementId: EXPECT_TARGET_ELEMENT,
|
|
},
|
|
async doOpenMenu() {
|
|
await SpecialPowers.spawn(
|
|
gBrowser.selectedBrowser,
|
|
[VIDEO_URL],
|
|
function (VIDEO_URL) {
|
|
let video = content.document.createElement("video");
|
|
video.controls = true;
|
|
video.src = VIDEO_URL;
|
|
content.document.body.appendChild(video);
|
|
video.scrollIntoView();
|
|
video.focus();
|
|
}
|
|
);
|
|
|
|
await openContextMenu("video");
|
|
},
|
|
async doCloseMenu() {
|
|
await closeExtensionContextMenu();
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_show_hide_audio() {
|
|
const AUDIO_URL = "data:audio/ogg,xxx";
|
|
await testShowHideEvent({
|
|
menuCreateParams: {
|
|
title: "audio item",
|
|
contexts: ["audio"],
|
|
},
|
|
expectedShownEvent: {
|
|
contexts: ["audio", "all"],
|
|
viewType: "tab",
|
|
mediaType: "audio",
|
|
editable: false,
|
|
frameId: 0,
|
|
},
|
|
expectedShownEventWithPermissions: {
|
|
contexts: ["audio", "all"],
|
|
viewType: "tab",
|
|
mediaType: "audio",
|
|
editable: false,
|
|
frameId: 0,
|
|
srcUrl: AUDIO_URL,
|
|
pageUrl: PAGE,
|
|
targetElementId: EXPECT_TARGET_ELEMENT,
|
|
},
|
|
async doOpenMenu() {
|
|
await SpecialPowers.spawn(
|
|
gBrowser.selectedBrowser,
|
|
[AUDIO_URL],
|
|
function (AUDIO_URL) {
|
|
let audio = content.document.createElement("audio");
|
|
audio.controls = true;
|
|
audio.src = AUDIO_URL;
|
|
content.document.body.appendChild(audio);
|
|
audio.scrollIntoView();
|
|
audio.focus();
|
|
}
|
|
);
|
|
|
|
await openContextMenu("audio");
|
|
},
|
|
async doCloseMenu() {
|
|
await closeExtensionContextMenu();
|
|
},
|
|
});
|
|
});
|