Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Errors

/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(async function unsupportedSchemes() {
const testcases = [
{
// Link to URL with query string parameters only.
testUrl: "magnet:?xt=urn:btih:somesha1hash&dn=displayname.txt",
matchingPatterns: [
"magnet:*",
"magnet:?xt=*",
"magnet:?xt=*txt",
"magnet:*?xt=*txt",
],
nonmatchingPatterns: [
// Although <all_urls> matches unsupported schemes in Chromium,
// we have specified that <all_urls> only matches all supported
// schemes. To match any scheme, an extension should not set the
// targetUrlPatterns field - this is checked below in subtest
// unsupportedSchemeWithoutTargetUrlPatterns.
"<all_urls>",
"agnet:*",
"magne:*",
],
},
{
// Link to bookmarklet.
testUrl: "javascript:-URL",
matchingPatterns: ["javascript:*", "javascript:*URL", "javascript:-URL"],
nonmatchingPatterns: [
"<all_urls>",
"javascript:javascript:-URL",
],
},
{
// Link to bookmarklet with comment.
testUrl: "javascript://-URL",
matchingPatterns: [
"javascript:*",
"javascript:*URL",
],
nonmatchingPatterns: ["<all_urls>", "javascript:-URL"],
},
{
// Link to data-URI.
testUrl: "data:application/foo,bar",
matchingPatterns: [
"<all_urls>",
"data:application/foo,bar",
"data:*,*",
"data:*",
],
nonmatchingPatterns: ["data:,bar", "data:application/foo,"],
},
{
// Extension page.
matchingPatterns: ["moz-extension://*/*"],
nonmatchingPatterns: [
"<all_urls>",
],
},
{
// While the scheme is supported, the URL is invalid.
testUrl: "http://",
matchingPatterns: [],
nonmatchingPatterns: ["http://*/*", "<all_urls>"],
},
];
async function testScript() {
let testcase;
browser.contextMenus.onShown.addListener(({ menuIds, linkUrl }) => {
browser.test.assertEq(testcase.testUrl, linkUrl, "Expected linkUrl");
for (let pattern of testcase.matchingPatterns) {
browser.test.assertTrue(
menuIds.includes(pattern),
`Menu item with targetUrlPattern="${pattern}" should be shown at ${testcase.testUrl}`
);
}
for (let pattern of testcase.nonmatchingPatterns) {
browser.test.assertFalse(
menuIds.includes(pattern),
`Menu item with targetUrlPattern="${pattern}" should not be shown at ${testcase.testUrl}`
);
}
testcase = null;
browser.test.sendMessage("onShown_checked");
});
browser.test.onMessage.addListener(async (msg, params) => {
browser.test.assertEq("setupTest", msg, "Expected message");
// Save test case in global variable for use in the onShown event.
testcase = params;
browser.test.log(`Running test for link with URL: ${testcase.testUrl}`);
document.getElementById("test_link_element").href = testcase.testUrl;
await browser.contextMenus.removeAll();
for (let targetUrlPattern of [
...testcase.matchingPatterns,
...testcase.nonmatchingPatterns,
]) {
await new Promise(resolve => {
browser.test.log(`Creating menu with "${targetUrlPattern}"`);
browser.contextMenus.create(
{
id: targetUrlPattern,
contexts: ["link"],
title: "Some menu item",
targetUrlPatterns: [targetUrlPattern],
},
resolve
);
});
}
browser.test.sendMessage("setupTest_ready");
});
browser.test.sendMessage("ready");
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["contextMenus"],
},
background() {
browser.tabs.create({ url: "testrunner.html" });
},
files: {
"testrunner.js": `(${testScript})()`,
"testrunner.html": `
<!DOCTYPE html><meta charset="utf-8">
<body>
<a id="test_link_element">Test link</a>
<script src="testrunner.js"></script>
</body>
`,
},
});
await extension.startup();
await extension.awaitMessage("ready");
for (let testcase of testcases) {
extension.sendMessage("setupTest", testcase);
await extension.awaitMessage("setupTest_ready");
await openExtensionContextMenu("#test_link_element");
await extension.awaitMessage("onShown_checked");
await closeContextMenu();
}
await extension.unload();
});
async function testLinkMenuWithoutTargetUrlPatterns(linkUrl) {
function background(expectedLinkUrl) {
let menuId;
browser.contextMenus.onShown.addListener(({ menuIds, linkUrl }) => {
browser.test.assertEq(1, menuIds.length, "Expected number of menus");
browser.test.assertEq(menuId, menuIds[0], "Expected menu ID");
browser.test.assertEq(expectedLinkUrl, linkUrl, "Expected linkUrl");
browser.test.sendMessage("done");
});
menuId = browser.contextMenus.create(
{
contexts: ["link"],
title: "Test menu item without targetUrlPattern",
},
() => {
browser.tabs.create({ url: "testpage.html" });
}
);
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["contextMenus"],
},
background: `(${background})("${linkUrl}")`,
files: {
"testpage.js": `browser.test.sendMessage("ready")`,
"testpage.html": `
<!DOCTYPE html><meta charset="utf-8">
<a id="test_link_element" href="${linkUrl}">Test link</a>
<script src="testpage.js"></script>
`,
},
});
await extension.startup();
await extension.awaitMessage("ready");
// Wait for the browser window chrome document to be flushed before
// trying to trigger the context menu in the newly created tab,
// to prevent intermittent failures (e.g. Bug 1775558).
await gBrowser.ownerGlobal.promiseDocumentFlushed(() => {});
await openExtensionContextMenu("#test_link_element");
await extension.awaitMessage("done");
await closeContextMenu();
await extension.unload();
}
// Tests that a menu item is shown on links with an unsupported scheme if
// targetUrlPatterns is not set.
add_task(async function unsupportedSchemeWithoutPattern() {
await testLinkMenuWithoutTargetUrlPatterns("unsupported-scheme:data");
});
// Tests that a menu item is shown on links with an invalid http:-URL if
// targetUrlPatterns is not set.
add_task(async function invalidHttpUrlWithoutPattern() {
await testLinkMenuWithoutTargetUrlPatterns("http://");
});
add_task(async function privileged_are_allowed_to_use_restrictedSchemes() {
let privilegedExtension = ExtensionTestUtils.loadExtension({
isPrivileged: true,
manifest: {
permissions: ["tabs", "contextMenus", "mozillaAddons"],
},
background() {
browser.contextMenus.create({
id: "privileged-extension",
title: "Privileged Extension",
contexts: ["page"],
documentUrlPatterns: ["about:reader*"],
});
let articleReady = Promise.withResolvers();
browser.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
if (
changeInfo.status === "complete" &&
tab.url.startsWith("about:reader")
) {
browser.test.sendMessage("readerModeEntered");
}
if (tab.isArticle && tab.url.includes("/readerModeArticle.html")) {
articleReady.resolve();
}
});
browser.test.onMessage.addListener(async msg => {
if (msg !== "enterReaderMode") {
browser.test.fail(`Received unexpected test message: ${msg}`);
return;
}
browser.test.log("Waiting for tab.isArticle to be true");
await articleReady.promise;
browser.test.log("Toggling reader mode");
browser.tabs.toggleReaderMode();
});
browser.tabs.query(
{ url: "*://example.com/*/readerModeArticle.html" },
tabs => {
if (tabs[0].isArticle) {
articleReady.resolve();
}
}
);
},
});
let nonPrivilegedExtension = ExtensionTestUtils.loadExtension({
isPrivileged: false,
manifest: {
permissions: ["contextMenus", "mozillaAddons"],
},
async background() {
browser.contextMenus.create({
id: "non-privileged-extension",
title: "Non Privileged Extension",
contexts: ["page"],
documentUrlPatterns: ["about:reader*"],
});
},
});
const baseUrl = getRootDirectory(gTestPath).replace(
);
const url = `${baseUrl}/readerModeArticle.html`;
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
url,
true,
true
);
await Promise.all([
privilegedExtension.startup(),
nonPrivilegedExtension.startup(),
]);
privilegedExtension.sendMessage("enterReaderMode");
await privilegedExtension.awaitMessage("readerModeEntered");
const contextMenu = await openContextMenu("body > h1");
let item = contextMenu.getElementsByAttribute(
"label",
"Privileged Extension"
);
is(
item.length,
1,
"Privileged extension's contextMenu item found as expected"
);
item = contextMenu.getElementsByAttribute(
"label",
"Non Privileged Extension"
);
is(
item.length,
0,
"Non privileged extension's contextMenu not found as expected"
);
await closeContextMenu();
BrowserTestUtils.removeTab(tab);
await Promise.all([
privilegedExtension.unload(),
nonPrivilegedExtension.unload(),
]);
});