865 lines
25 KiB
JavaScript
865 lines
25 KiB
JavaScript
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* vim: set sts=2 sw=2 et tw=80: */
|
|
"use strict";
|
|
|
|
Services.scriptloader.loadSubScript(
|
|
"chrome://mochitests/content/browser/browser/components/places/tests/browser/head.js",
|
|
this
|
|
);
|
|
/* globals withSidebarTree, synthesizeClickOnSelectedTreeCell, promiseLibrary, promiseLibraryClosed
|
|
*/
|
|
|
|
const PAGE =
|
|
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html";
|
|
|
|
add_task(async function () {
|
|
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
|
|
|
|
gBrowser.selectedTab = tab1;
|
|
|
|
let extension = ExtensionTestUtils.loadExtension({
|
|
manifest: {
|
|
permissions: ["contextMenus"],
|
|
},
|
|
|
|
background: function () {
|
|
browser.test.assertEq(
|
|
browser.contextMenus.ContextType.TAB,
|
|
"tab",
|
|
"ContextType is available"
|
|
);
|
|
browser.contextMenus.create({
|
|
id: "clickme-image",
|
|
title: "Click me!",
|
|
contexts: ["image"],
|
|
});
|
|
browser.contextMenus.create(
|
|
{
|
|
id: "clickme-page",
|
|
title: "Click me!",
|
|
contexts: ["page"],
|
|
},
|
|
() => {
|
|
browser.test.sendMessage("ready");
|
|
}
|
|
);
|
|
},
|
|
});
|
|
|
|
await extension.startup();
|
|
await extension.awaitMessage("ready");
|
|
|
|
let contentAreaContextMenu = await openContextMenu("#img1");
|
|
let item = contentAreaContextMenu.getElementsByAttribute(
|
|
"label",
|
|
"Click me!"
|
|
);
|
|
is(item.length, 1, "contextMenu item for image was found");
|
|
await closeContextMenu();
|
|
|
|
contentAreaContextMenu = await openContextMenu("body");
|
|
item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!");
|
|
is(item.length, 1, "contextMenu item for page was found");
|
|
await closeContextMenu();
|
|
|
|
await extension.unload();
|
|
|
|
BrowserTestUtils.removeTab(tab1);
|
|
});
|
|
|
|
add_task(async function () {
|
|
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
|
|
|
|
gBrowser.selectedTab = tab1;
|
|
|
|
let extension = ExtensionTestUtils.loadExtension({
|
|
manifest: {
|
|
permissions: ["contextMenus"],
|
|
},
|
|
|
|
background: async function () {
|
|
browser.test.onMessage.addListener(msg => {
|
|
if (msg == "removeall") {
|
|
browser.contextMenus.removeAll();
|
|
browser.test.sendMessage("removed");
|
|
}
|
|
});
|
|
|
|
// A generic onclick callback function.
|
|
function genericOnClick(info, tab) {
|
|
browser.test.sendMessage("onclick", { info, tab });
|
|
}
|
|
|
|
browser.contextMenus.onClicked.addListener((info, tab) => {
|
|
browser.test.sendMessage("browser.contextMenus.onClicked", {
|
|
info,
|
|
tab,
|
|
});
|
|
});
|
|
|
|
browser.contextMenus.create({
|
|
contexts: ["all"],
|
|
type: "separator",
|
|
});
|
|
|
|
let contexts = [
|
|
"page",
|
|
"link",
|
|
"selection",
|
|
"image",
|
|
"editable",
|
|
"password",
|
|
];
|
|
for (let i = 0; i < contexts.length; i++) {
|
|
let context = contexts[i];
|
|
let title = context;
|
|
browser.contextMenus.create({
|
|
title: title,
|
|
contexts: [context],
|
|
id: "ext-" + context,
|
|
onclick: genericOnClick,
|
|
});
|
|
if (context == "selection") {
|
|
browser.contextMenus.update("ext-selection", {
|
|
title: "selection is: '%s'",
|
|
onclick: genericOnClick,
|
|
});
|
|
}
|
|
}
|
|
|
|
let parent = browser.contextMenus.create({
|
|
title: "parent",
|
|
});
|
|
browser.contextMenus.create({
|
|
title: "child1",
|
|
parentId: parent,
|
|
onclick: genericOnClick,
|
|
});
|
|
let child2 = browser.contextMenus.create({
|
|
title: "child2",
|
|
parentId: parent,
|
|
onclick: genericOnClick,
|
|
});
|
|
|
|
let parentToDel = browser.contextMenus.create({
|
|
title: "parentToDel",
|
|
});
|
|
browser.contextMenus.create({
|
|
title: "child1",
|
|
parentId: parentToDel,
|
|
onclick: genericOnClick,
|
|
});
|
|
browser.contextMenus.create({
|
|
title: "child2",
|
|
parentId: parentToDel,
|
|
onclick: genericOnClick,
|
|
});
|
|
browser.contextMenus.remove(parentToDel);
|
|
|
|
browser.contextMenus.create({
|
|
title: "Without onclick property",
|
|
id: "ext-without-onclick",
|
|
});
|
|
|
|
await browser.test.assertRejects(
|
|
browser.contextMenus.update(parent, { parentId: child2 }),
|
|
/cannot be an ancestor/,
|
|
"Should not be able to reparent an item as descendent of itself"
|
|
);
|
|
|
|
browser.test.sendMessage("contextmenus");
|
|
},
|
|
});
|
|
|
|
await extension.startup();
|
|
await extension.awaitMessage("contextmenus");
|
|
|
|
let expectedClickInfo = {
|
|
menuItemId: "ext-image",
|
|
mediaType: "image",
|
|
srcUrl:
|
|
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/ctxmenu-image.png",
|
|
pageUrl: PAGE,
|
|
editable: false,
|
|
};
|
|
|
|
function checkClickInfo(result) {
|
|
for (let i of Object.keys(expectedClickInfo)) {
|
|
is(
|
|
result.info[i],
|
|
expectedClickInfo[i],
|
|
"click info " +
|
|
i +
|
|
" expected to be: " +
|
|
expectedClickInfo[i] +
|
|
" but was: " +
|
|
result.info[i]
|
|
);
|
|
}
|
|
is(
|
|
expectedClickInfo.pageSrc,
|
|
result.tab.url,
|
|
"click info page source is the right tab"
|
|
);
|
|
}
|
|
|
|
let extensionMenuRoot = await openExtensionContextMenu();
|
|
|
|
// Check some menu items
|
|
let items = extensionMenuRoot.getElementsByAttribute("label", "image");
|
|
is(items.length, 1, "contextMenu item for image was found (context=image)");
|
|
let image = items[0];
|
|
|
|
items = extensionMenuRoot.getElementsByAttribute("label", "selection-edited");
|
|
is(
|
|
items.length,
|
|
0,
|
|
"contextMenu item for selection was not found (context=image)"
|
|
);
|
|
|
|
items = extensionMenuRoot.getElementsByAttribute("label", "parentToDel");
|
|
is(
|
|
items.length,
|
|
0,
|
|
"contextMenu item for removed parent was not found (context=image)"
|
|
);
|
|
|
|
items = extensionMenuRoot.getElementsByAttribute("label", "parent");
|
|
is(items.length, 1, "contextMenu item for parent was found (context=image)");
|
|
|
|
is(
|
|
items[0].menupopup.children.length,
|
|
2,
|
|
"child items for parent were found (context=image)"
|
|
);
|
|
|
|
// Click on ext-image item and check the click results
|
|
await closeExtensionContextMenu(image);
|
|
|
|
let result = await extension.awaitMessage("onclick");
|
|
checkClickInfo(result);
|
|
result = await extension.awaitMessage("browser.contextMenus.onClicked");
|
|
checkClickInfo(result);
|
|
|
|
// Test "link" context and OnClick data property.
|
|
extensionMenuRoot = await openExtensionContextMenu("[href=some-link]");
|
|
|
|
// Click on ext-link and check the click results
|
|
items = extensionMenuRoot.getElementsByAttribute("label", "link");
|
|
is(items.length, 1, "contextMenu item for parent was found (context=link)");
|
|
let link = items[0];
|
|
|
|
expectedClickInfo = {
|
|
menuItemId: "ext-link",
|
|
linkUrl:
|
|
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/some-link",
|
|
linkText: "Some link",
|
|
pageUrl: PAGE,
|
|
editable: false,
|
|
};
|
|
|
|
await closeExtensionContextMenu(link);
|
|
|
|
result = await extension.awaitMessage("onclick");
|
|
checkClickInfo(result);
|
|
result = await extension.awaitMessage("browser.contextMenus.onClicked");
|
|
checkClickInfo(result);
|
|
|
|
// Test "editable" context and OnClick data property.
|
|
extensionMenuRoot = await openExtensionContextMenu("#edit-me");
|
|
|
|
// Check some menu items.
|
|
items = extensionMenuRoot.getElementsByAttribute("label", "editable");
|
|
is(
|
|
items.length,
|
|
1,
|
|
"contextMenu item for text input element was found (context=editable)"
|
|
);
|
|
let editable = items[0];
|
|
|
|
// Click on ext-editable item and check the click results.
|
|
await closeExtensionContextMenu(editable);
|
|
|
|
expectedClickInfo = {
|
|
menuItemId: "ext-editable",
|
|
pageUrl: PAGE,
|
|
editable: true,
|
|
};
|
|
|
|
result = await extension.awaitMessage("onclick");
|
|
checkClickInfo(result);
|
|
result = await extension.awaitMessage("browser.contextMenus.onClicked");
|
|
checkClickInfo(result);
|
|
|
|
extensionMenuRoot = await openExtensionContextMenu("#readonly-text");
|
|
|
|
// Check some menu items.
|
|
items = extensionMenuRoot.getElementsByAttribute("label", "editable");
|
|
is(
|
|
items.length,
|
|
0,
|
|
"contextMenu item for text input element was not found (context=editable fails for readonly items)"
|
|
);
|
|
|
|
// Hide the popup "manually" because there's nothing to click.
|
|
await closeContextMenu();
|
|
|
|
// Test "editable" context on type=tel and type=number items, and OnClick data property.
|
|
extensionMenuRoot = await openExtensionContextMenu("#call-me-maybe");
|
|
|
|
// Check some menu items.
|
|
items = extensionMenuRoot.getElementsByAttribute("label", "editable");
|
|
is(
|
|
items.length,
|
|
1,
|
|
"contextMenu item for text input element was found (context=editable)"
|
|
);
|
|
editable = items[0];
|
|
|
|
// Click on ext-editable item and check the click results.
|
|
await closeExtensionContextMenu(editable);
|
|
|
|
expectedClickInfo = {
|
|
menuItemId: "ext-editable",
|
|
pageUrl: PAGE,
|
|
editable: true,
|
|
};
|
|
|
|
result = await extension.awaitMessage("onclick");
|
|
checkClickInfo(result);
|
|
result = await extension.awaitMessage("browser.contextMenus.onClicked");
|
|
checkClickInfo(result);
|
|
|
|
extensionMenuRoot = await openExtensionContextMenu("#number-input");
|
|
|
|
// Check some menu items.
|
|
items = extensionMenuRoot.getElementsByAttribute("label", "editable");
|
|
is(
|
|
items.length,
|
|
1,
|
|
"contextMenu item for text input element was found (context=editable)"
|
|
);
|
|
editable = items[0];
|
|
|
|
// Click on ext-editable item and check the click results.
|
|
await closeExtensionContextMenu(editable);
|
|
|
|
expectedClickInfo = {
|
|
menuItemId: "ext-editable",
|
|
pageUrl: PAGE,
|
|
editable: true,
|
|
};
|
|
|
|
result = await extension.awaitMessage("onclick");
|
|
checkClickInfo(result);
|
|
result = await extension.awaitMessage("browser.contextMenus.onClicked");
|
|
checkClickInfo(result);
|
|
|
|
extensionMenuRoot = await openExtensionContextMenu("#password");
|
|
items = extensionMenuRoot.getElementsByAttribute("label", "password");
|
|
is(
|
|
items.length,
|
|
1,
|
|
"contextMenu item for password input element was found (context=password)"
|
|
);
|
|
let password = items[0];
|
|
await closeExtensionContextMenu(password);
|
|
expectedClickInfo = {
|
|
menuItemId: "ext-password",
|
|
pageUrl: PAGE,
|
|
editable: true,
|
|
};
|
|
|
|
result = await extension.awaitMessage("onclick");
|
|
checkClickInfo(result);
|
|
result = await extension.awaitMessage("browser.contextMenus.onClicked");
|
|
checkClickInfo(result);
|
|
|
|
extensionMenuRoot = await openExtensionContextMenu("#noneditablepassword");
|
|
items = extensionMenuRoot.getElementsByAttribute("label", "password");
|
|
is(
|
|
items.length,
|
|
1,
|
|
"contextMenu item for password input element was found (context=password)"
|
|
);
|
|
password = items[0];
|
|
await closeExtensionContextMenu(password);
|
|
expectedClickInfo.editable = false;
|
|
result = await extension.awaitMessage("onclick");
|
|
checkClickInfo(result);
|
|
result = await extension.awaitMessage("browser.contextMenus.onClicked");
|
|
checkClickInfo(result);
|
|
|
|
// Select some text
|
|
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {
|
|
let doc = content.document;
|
|
let range = doc.createRange();
|
|
let selection = content.getSelection();
|
|
selection.removeAllRanges();
|
|
let textNode = doc.getElementById("img1").previousSibling;
|
|
range.setStart(textNode, 0);
|
|
range.setEnd(textNode, 100);
|
|
selection.addRange(range);
|
|
});
|
|
|
|
// Bring up context menu again
|
|
extensionMenuRoot = await openExtensionContextMenu();
|
|
|
|
// Check some menu items
|
|
items = extensionMenuRoot.getElementsByAttribute(
|
|
"label",
|
|
"Without onclick property"
|
|
);
|
|
is(items.length, 1, "contextMenu item was found (context=page)");
|
|
|
|
await closeExtensionContextMenu(items[0]);
|
|
|
|
expectedClickInfo = {
|
|
menuItemId: "ext-without-onclick",
|
|
pageUrl: PAGE,
|
|
};
|
|
|
|
result = await extension.awaitMessage("browser.contextMenus.onClicked");
|
|
checkClickInfo(result);
|
|
|
|
// Bring up context menu again
|
|
extensionMenuRoot = await openExtensionContextMenu();
|
|
|
|
// Check some menu items
|
|
items = extensionMenuRoot.getElementsByAttribute(
|
|
"label",
|
|
"selection is: 'just some text 12345678901234567890123456789012\u2026'"
|
|
);
|
|
is(
|
|
items.length,
|
|
1,
|
|
"contextMenu item for selection was found (context=selection)"
|
|
);
|
|
let selectionItem = items[0];
|
|
|
|
items = extensionMenuRoot.getElementsByAttribute("label", "selection");
|
|
is(
|
|
items.length,
|
|
0,
|
|
"contextMenu item label update worked (context=selection)"
|
|
);
|
|
|
|
await closeExtensionContextMenu(selectionItem);
|
|
|
|
expectedClickInfo = {
|
|
menuItemId: "ext-selection",
|
|
pageUrl: PAGE,
|
|
selectionText:
|
|
" just some text 1234567890123456789012345678901234567890123456789012345678901234567890123456789012",
|
|
};
|
|
|
|
result = await extension.awaitMessage("onclick");
|
|
checkClickInfo(result);
|
|
result = await extension.awaitMessage("browser.contextMenus.onClicked");
|
|
checkClickInfo(result);
|
|
|
|
// Select a lot of text
|
|
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
|
|
let doc = content.document;
|
|
let range = doc.createRange();
|
|
let selection = content.getSelection();
|
|
selection.removeAllRanges();
|
|
let textNode = doc.getElementById("longtext").firstChild;
|
|
range.setStart(textNode, 0);
|
|
range.setEnd(textNode, textNode.length);
|
|
selection.addRange(range);
|
|
});
|
|
|
|
// Bring up context menu again
|
|
extensionMenuRoot = await openExtensionContextMenu("#longtext");
|
|
|
|
// Check some menu items
|
|
items = extensionMenuRoot.getElementsByAttribute(
|
|
"label",
|
|
"selection is: 'Sed ut perspiciatis unde omnis iste natus error\u2026'"
|
|
);
|
|
is(
|
|
items.length,
|
|
1,
|
|
`contextMenu item for longtext selection was found (context=selection)`
|
|
);
|
|
await closeExtensionContextMenu(items[0]);
|
|
|
|
expectedClickInfo = {
|
|
menuItemId: "ext-selection",
|
|
pageUrl: PAGE,
|
|
};
|
|
|
|
result = await extension.awaitMessage("onclick");
|
|
checkClickInfo(result);
|
|
result = await extension.awaitMessage("browser.contextMenus.onClicked");
|
|
checkClickInfo(result);
|
|
ok(
|
|
result.info.selectionText.endsWith("quo voluptas nulla pariatur?"),
|
|
"long text selection worked"
|
|
);
|
|
|
|
// Select a lot of text, excercise the editable element code path in
|
|
// the Browser:GetSelection handler.
|
|
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
|
|
let doc = content.document;
|
|
let node = doc.getElementById("editabletext");
|
|
// content.js handleContentContextMenu fails intermittently without focus.
|
|
node.focus();
|
|
node.selectionStart = 0;
|
|
node.selectionEnd = 844;
|
|
});
|
|
|
|
// Bring up context menu again
|
|
extensionMenuRoot = await openExtensionContextMenu("#editabletext");
|
|
|
|
// Check some menu items
|
|
items = extensionMenuRoot.getElementsByAttribute("label", "editable");
|
|
is(
|
|
items.length,
|
|
1,
|
|
"contextMenu item for text input element was found (context=editable)"
|
|
);
|
|
await closeExtensionContextMenu(items[0]);
|
|
|
|
expectedClickInfo = {
|
|
menuItemId: "ext-editable",
|
|
editable: true,
|
|
pageUrl: PAGE,
|
|
};
|
|
|
|
result = await extension.awaitMessage("onclick");
|
|
checkClickInfo(result);
|
|
result = await extension.awaitMessage("browser.contextMenus.onClicked");
|
|
checkClickInfo(result);
|
|
ok(
|
|
result.info.selectionText.endsWith(
|
|
"perferendis doloribus asperiores repellat."
|
|
),
|
|
"long text selection worked"
|
|
);
|
|
|
|
extension.sendMessage("removeall");
|
|
await extension.awaitMessage("removed");
|
|
|
|
let contentAreaContextMenu = await openContextMenu("#img1");
|
|
items = contentAreaContextMenu.getElementsByAttribute(
|
|
"ext-type",
|
|
"top-level-menu"
|
|
);
|
|
is(items.length, 0, "top level item was not found (after removeAll()");
|
|
await closeContextMenu();
|
|
|
|
await extension.unload();
|
|
BrowserTestUtils.removeTab(tab1);
|
|
});
|
|
|
|
add_task(async function testRemoveAllWithTwoExtensions() {
|
|
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
|
|
const manifest = { permissions: ["contextMenus"] };
|
|
|
|
const first = ExtensionTestUtils.loadExtension({
|
|
manifest,
|
|
background() {
|
|
browser.contextMenus.create({ title: "alpha", contexts: ["all"] });
|
|
|
|
browser.contextMenus.onClicked.addListener(() => {
|
|
browser.contextMenus.removeAll();
|
|
});
|
|
browser.test.onMessage.addListener(msg => {
|
|
if (msg == "ping") {
|
|
browser.test.sendMessage("pong-alpha");
|
|
return;
|
|
}
|
|
browser.contextMenus.create({ title: "gamma", contexts: ["all"] });
|
|
});
|
|
},
|
|
});
|
|
|
|
const second = ExtensionTestUtils.loadExtension({
|
|
manifest,
|
|
background() {
|
|
browser.contextMenus.create({ title: "beta", contexts: ["all"] });
|
|
|
|
browser.contextMenus.onClicked.addListener(() => {
|
|
browser.contextMenus.removeAll();
|
|
});
|
|
|
|
browser.test.onMessage.addListener(() => {
|
|
browser.test.sendMessage("pong-beta");
|
|
});
|
|
},
|
|
});
|
|
|
|
await first.startup();
|
|
await second.startup();
|
|
|
|
async function confirmMenuItems(...items) {
|
|
// Round-trip to extension to make sure that the context menu state has been
|
|
// updated by the async contextMenus.create / contextMenus.removeAll calls.
|
|
first.sendMessage("ping");
|
|
second.sendMessage("ping");
|
|
await first.awaitMessage("pong-alpha");
|
|
await second.awaitMessage("pong-beta");
|
|
|
|
const menu = await openContextMenu();
|
|
for (const id of ["alpha", "beta", "gamma"]) {
|
|
const expected = items.includes(id);
|
|
const found = menu.getElementsByAttribute("label", id);
|
|
is(
|
|
!!found.length,
|
|
expected,
|
|
`menu item ${id} ${expected ? "" : "not "}found`
|
|
);
|
|
}
|
|
// Return the first menu item, we need to click it.
|
|
return menu.getElementsByAttribute("label", items[0])[0];
|
|
}
|
|
|
|
// Confirm alpha, beta exist; click alpha to remove it.
|
|
const alpha = await confirmMenuItems("alpha", "beta");
|
|
await closeExtensionContextMenu(alpha);
|
|
|
|
// Confirm only beta exists.
|
|
await confirmMenuItems("beta");
|
|
await closeContextMenu();
|
|
|
|
// Create gamma, confirm, click.
|
|
first.sendMessage("create");
|
|
const beta = await confirmMenuItems("beta", "gamma");
|
|
await closeExtensionContextMenu(beta);
|
|
|
|
// Confirm only gamma is left.
|
|
await confirmMenuItems("gamma");
|
|
await closeContextMenu();
|
|
|
|
await first.unload();
|
|
await second.unload();
|
|
BrowserTestUtils.removeTab(tab);
|
|
});
|
|
|
|
function bookmarkContextMenuExtension() {
|
|
return ExtensionTestUtils.loadExtension({
|
|
manifest: {
|
|
permissions: ["contextMenus", "bookmarks", "activeTab"],
|
|
},
|
|
async background() {
|
|
const url = "https://example.com/";
|
|
const title = "Example";
|
|
let newBookmark = await browser.bookmarks.create({
|
|
url,
|
|
title,
|
|
parentId: "toolbar_____",
|
|
});
|
|
browser.contextMenus.onClicked.addListener(async (info, tab) => {
|
|
browser.test.assertEq(
|
|
undefined,
|
|
tab,
|
|
"click event in bookmarks menu is not associated with any tab"
|
|
);
|
|
browser.test.assertEq(
|
|
newBookmark.id,
|
|
info.bookmarkId,
|
|
"Bookmark ID matches"
|
|
);
|
|
|
|
await browser.test.assertRejects(
|
|
browser.tabs.executeScript({ code: "'some code';" }),
|
|
/Missing host permission for the tab/,
|
|
"Content script should not run, activeTab should not be granted to bookmark menu events"
|
|
);
|
|
|
|
let [bookmark] = await browser.bookmarks.get(info.bookmarkId);
|
|
browser.test.assertEq(title, bookmark.title, "Bookmark title matches");
|
|
browser.test.assertEq(url, bookmark.url, "Bookmark url matches");
|
|
browser.test.assertFalse(
|
|
info.hasOwnProperty("pageUrl"),
|
|
"Context menu does not expose pageUrl"
|
|
);
|
|
await browser.bookmarks.remove(info.bookmarkId);
|
|
browser.test.sendMessage("test-finish");
|
|
});
|
|
browser.contextMenus.create(
|
|
{
|
|
title: "Get bookmark",
|
|
contexts: ["bookmark"],
|
|
},
|
|
() => {
|
|
browser.test.sendMessage("bookmark-created", newBookmark.id);
|
|
}
|
|
);
|
|
},
|
|
});
|
|
}
|
|
|
|
add_task(async function test_bookmark_contextmenu() {
|
|
info("Adding a bookmark to the bookmarks toolbar.");
|
|
let addedBookmark = await PlacesUtils.bookmarks.insert({
|
|
parentGuid: PlacesUtils.bookmarks.toolbarGuid,
|
|
title: "Test",
|
|
url: "https://example.com",
|
|
});
|
|
|
|
registerCleanupFunction(async () => {
|
|
await PlacesUtils.bookmarks.remove(addedBookmark);
|
|
});
|
|
|
|
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
|
|
|
|
await toggleBookmarksToolbar(true);
|
|
|
|
const extension = bookmarkContextMenuExtension();
|
|
|
|
await extension.startup();
|
|
await extension.awaitMessage("bookmark-created");
|
|
let menu = await openChromeContextMenu(
|
|
"placesContext",
|
|
"#PersonalToolbar .bookmark-item:last-child"
|
|
);
|
|
|
|
let menuItem = menu.getElementsByAttribute("label", "Get bookmark")[0];
|
|
closeChromeContextMenu("placesContext", menuItem);
|
|
|
|
await extension.awaitMessage("test-finish");
|
|
await extension.unload();
|
|
await toggleBookmarksToolbar(false);
|
|
|
|
BrowserTestUtils.removeTab(tab);
|
|
});
|
|
|
|
add_task(async function test_bookmark_sidebar_contextmenu() {
|
|
await withSidebarTree("bookmarks", async tree => {
|
|
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
|
|
|
|
let extension = bookmarkContextMenuExtension();
|
|
await extension.startup();
|
|
let bookmarkGuid = await extension.awaitMessage("bookmark-created");
|
|
|
|
let sidebar = window.SidebarController.browser;
|
|
let menu = sidebar.contentDocument.getElementById("placesContext");
|
|
tree.selectItems([bookmarkGuid]);
|
|
let shown = BrowserTestUtils.waitForEvent(menu, "popupshown");
|
|
synthesizeClickOnSelectedTreeCell(tree, { type: "contextmenu" });
|
|
await shown;
|
|
|
|
let menuItem = menu.getElementsByAttribute("label", "Get bookmark")[0];
|
|
closeChromeContextMenu("placesContext", menuItem, sidebar.contentWindow);
|
|
await extension.awaitMessage("test-finish");
|
|
await extension.unload();
|
|
|
|
BrowserTestUtils.removeTab(tab);
|
|
});
|
|
});
|
|
|
|
function bookmarkFolderContextMenuExtension() {
|
|
return ExtensionTestUtils.loadExtension({
|
|
manifest: {
|
|
permissions: ["contextMenus", "bookmarks"],
|
|
},
|
|
async background() {
|
|
const title = "Example";
|
|
let newBookmark = await browser.bookmarks.create({
|
|
title,
|
|
parentId: "toolbar_____",
|
|
});
|
|
await new Promise(resolve =>
|
|
browser.contextMenus.create(
|
|
{
|
|
title: "Get bookmark",
|
|
contexts: ["bookmark"],
|
|
},
|
|
resolve
|
|
)
|
|
);
|
|
browser.contextMenus.onClicked.addListener(async info => {
|
|
browser.test.assertEq(
|
|
newBookmark.id,
|
|
info.bookmarkId,
|
|
"Bookmark ID matches"
|
|
);
|
|
|
|
let [bookmark] = await browser.bookmarks.get(info.bookmarkId);
|
|
browser.test.assertEq(title, bookmark.title, "Bookmark title matches");
|
|
browser.test.assertFalse(
|
|
info.hasOwnProperty("pageUrl"),
|
|
"Context menu does not expose pageUrl"
|
|
);
|
|
await browser.bookmarks.remove(info.bookmarkId);
|
|
browser.test.sendMessage("test-finish");
|
|
});
|
|
browser.test.sendMessage("bookmark-created", newBookmark.id);
|
|
},
|
|
});
|
|
}
|
|
|
|
add_task(async function test_organizer_contextmenu() {
|
|
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
|
|
let library = await promiseLibrary("BookmarksToolbar");
|
|
|
|
let menu = library.document.getElementById("placesContext");
|
|
let mainTree = library.document.getElementById("placeContent");
|
|
let leftTree = library.document.getElementById("placesList");
|
|
|
|
let tests = [
|
|
[mainTree, bookmarkContextMenuExtension],
|
|
[mainTree, bookmarkFolderContextMenuExtension],
|
|
[leftTree, bookmarkFolderContextMenuExtension],
|
|
];
|
|
|
|
for (let [tree, makeExtension] of tests) {
|
|
let extension = makeExtension();
|
|
await extension.startup();
|
|
let bookmarkGuid = await extension.awaitMessage("bookmark-created");
|
|
|
|
tree.selectItems([bookmarkGuid]);
|
|
let shown = BrowserTestUtils.waitForEvent(menu, "popupshown");
|
|
synthesizeClickOnSelectedTreeCell(tree, { type: "contextmenu" });
|
|
await shown;
|
|
|
|
let menuItem = menu.getElementsByAttribute("label", "Get bookmark")[0];
|
|
closeChromeContextMenu("placesContext", menuItem, library);
|
|
await extension.awaitMessage("test-finish");
|
|
await extension.unload();
|
|
}
|
|
|
|
await promiseLibraryClosed(library);
|
|
BrowserTestUtils.removeTab(tab);
|
|
});
|
|
|
|
add_task(async function test_bookmark_context_requires_permission() {
|
|
await toggleBookmarksToolbar(true);
|
|
|
|
const extension = ExtensionTestUtils.loadExtension({
|
|
manifest: {
|
|
permissions: ["contextMenus"],
|
|
},
|
|
background() {
|
|
browser.contextMenus.create(
|
|
{
|
|
title: "Get bookmark",
|
|
contexts: ["bookmark"],
|
|
},
|
|
() => {
|
|
browser.test.sendMessage("bookmark-created");
|
|
}
|
|
);
|
|
},
|
|
});
|
|
await extension.startup();
|
|
await extension.awaitMessage("bookmark-created");
|
|
let menu = await openChromeContextMenu(
|
|
"placesContext",
|
|
"#PersonalToolbar .bookmark-item:last-child"
|
|
);
|
|
|
|
Assert.equal(
|
|
menu.getElementsByAttribute("label", "Get bookmark").length,
|
|
0,
|
|
"bookmark context menu not created with `bookmarks` permission."
|
|
);
|
|
|
|
closeChromeContextMenu("placesContext");
|
|
|
|
await extension.unload();
|
|
await toggleBookmarksToolbar(false);
|
|
});
|