647 lines
20 KiB
HTML
647 lines
20 KiB
HTML
<!DOCTYPE HTML>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>Test for protocol handlers</title>
|
||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||
<script src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||
<script type="text/javascript" src="head.js"></script>
|
||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||
</head>
|
||
<body>
|
||
|
||
<script type="text/javascript">
|
||
"use strict";
|
||
|
||
/* eslint-disable mozilla/balanced-listeners */
|
||
|
||
function protocolChromeScript() {
|
||
const PROTOCOL_HANDLER_OPEN_PERM_KEY = "open-protocol-handler";
|
||
const PERMISSION_KEY_DELIMITER = "^";
|
||
|
||
/* eslint-env mozilla/chrome-script */
|
||
addMessageListener("setup", ({ protocol, principalOrigins }) => {
|
||
let data = {};
|
||
const protoSvc = Cc[
|
||
"@mozilla.org/uriloader/external-protocol-service;1"
|
||
].getService(Ci.nsIExternalProtocolService);
|
||
let protoInfo = protoSvc.getProtocolHandlerInfo(protocol);
|
||
data.preferredAction = protoInfo.preferredAction == protoInfo.useHelperApp;
|
||
|
||
let handlers = protoInfo.possibleApplicationHandlers;
|
||
data.handlers = handlers.length;
|
||
|
||
let handler = handlers.queryElementAt(0, Ci.nsIHandlerApp);
|
||
data.isWebHandler = handler instanceof Ci.nsIWebHandlerApp;
|
||
data.uriTemplate = handler.uriTemplate;
|
||
|
||
// ext+ protocols should be set as default when there is only one
|
||
data.preferredApplicationHandler =
|
||
protoInfo.preferredApplicationHandler == handler;
|
||
data.alwaysAskBeforeHandling = protoInfo.alwaysAskBeforeHandling;
|
||
const handlerSvc = Cc[
|
||
"@mozilla.org/uriloader/handler-service;1"
|
||
].getService(Ci.nsIHandlerService);
|
||
handlerSvc.store(protoInfo);
|
||
|
||
for (let origin of principalOrigins) {
|
||
let principal = Services.scriptSecurityManager.createContentPrincipal(
|
||
Services.io.newURI(origin),
|
||
{}
|
||
);
|
||
let pbPrincipal = Services.scriptSecurityManager.createContentPrincipal(
|
||
Services.io.newURI(origin),
|
||
{
|
||
privateBrowsingId: 1,
|
||
}
|
||
);
|
||
let permKey =
|
||
PROTOCOL_HANDLER_OPEN_PERM_KEY + PERMISSION_KEY_DELIMITER + protocol;
|
||
Services.perms.addFromPrincipal(
|
||
principal,
|
||
permKey,
|
||
Services.perms.ALLOW_ACTION,
|
||
Services.perms.EXPIRE_NEVER
|
||
);
|
||
Services.perms.addFromPrincipal(
|
||
pbPrincipal,
|
||
permKey,
|
||
Services.perms.ALLOW_ACTION,
|
||
Services.perms.EXPIRE_NEVER
|
||
);
|
||
}
|
||
|
||
sendAsyncMessage("handlerData", data);
|
||
});
|
||
addMessageListener("setPreferredAction", data => {
|
||
let { protocol, template } = data;
|
||
const protoSvc = Cc[
|
||
"@mozilla.org/uriloader/external-protocol-service;1"
|
||
].getService(Ci.nsIExternalProtocolService);
|
||
let protoInfo = protoSvc.getProtocolHandlerInfo(protocol);
|
||
|
||
for (let handler of protoInfo.possibleApplicationHandlers.enumerate()) {
|
||
if (handler.uriTemplate.startsWith(template)) {
|
||
protoInfo.preferredApplicationHandler = handler;
|
||
protoInfo.preferredAction = protoInfo.useHelperApp;
|
||
protoInfo.alwaysAskBeforeHandling = false;
|
||
}
|
||
}
|
||
const handlerSvc = Cc[
|
||
"@mozilla.org/uriloader/handler-service;1"
|
||
].getService(Ci.nsIHandlerService);
|
||
handlerSvc.store(protoInfo);
|
||
sendAsyncMessage("set");
|
||
});
|
||
}
|
||
|
||
add_task(async function test_protocolHandler() {
|
||
let extensionData = {
|
||
manifest: {
|
||
protocol_handlers: [
|
||
{
|
||
protocol: "ext+foo",
|
||
name: "a foo protocol handler",
|
||
uriTemplate: "foo.html?val=%s",
|
||
},
|
||
],
|
||
},
|
||
|
||
background() {
|
||
browser.test.onMessage.addListener(async (msg, arg) => {
|
||
if (msg == "open") {
|
||
let tab = await browser.tabs.create({ url: arg });
|
||
browser.test.sendMessage("opened", tab.id);
|
||
} else if (msg == "close") {
|
||
await browser.tabs.remove(arg);
|
||
browser.test.sendMessage("closed");
|
||
}
|
||
});
|
||
browser.test.sendMessage("test-url", browser.runtime.getURL("foo.html"));
|
||
},
|
||
|
||
files: {
|
||
"foo.js": function() {
|
||
browser.test.sendMessage("test-query", location.search);
|
||
browser.tabs.getCurrent().then(tab => browser.test.sendMessage("test-tab", tab.id));
|
||
},
|
||
"foo.html": `<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<script src="foo.js"><\/script>
|
||
</head>
|
||
</html>`,
|
||
},
|
||
};
|
||
|
||
let pb_extension = ExtensionTestUtils.loadExtension({
|
||
background() {
|
||
browser.test.onMessage.addListener(async (msg, arg) => {
|
||
if (msg == "open") {
|
||
let win = await browser.windows.create({ url: arg, incognito: true });
|
||
browser.test.sendMessage("opened", {
|
||
windowId: win.id,
|
||
tabId: win.tabs[0].id,
|
||
});
|
||
} else if (msg == "nav") {
|
||
await browser.tabs.update(arg.tabId, { url: arg.url });
|
||
browser.test.sendMessage("navigated");
|
||
} else if (msg == "close") {
|
||
await browser.windows.remove(arg);
|
||
browser.test.sendMessage("closed");
|
||
}
|
||
});
|
||
},
|
||
incognitoOverride: "spanning",
|
||
});
|
||
await pb_extension.startup();
|
||
|
||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||
await extension.startup();
|
||
let handlerUrl = await extension.awaitMessage("test-url");
|
||
|
||
// Ensure that the protocol handler is configured, and set it as default to
|
||
// bypass the dialog.
|
||
let chromeScript = SpecialPowers.loadChromeScript(protocolChromeScript);
|
||
|
||
let msg = chromeScript.promiseOneMessage("handlerData");
|
||
chromeScript.sendAsyncMessage("setup", {
|
||
protocol: "ext+foo",
|
||
principalOrigins: [
|
||
`moz-extension://${extension.uuid}/`,
|
||
`moz-extension://${pb_extension.uuid}/`,
|
||
],
|
||
});
|
||
let data = await msg;
|
||
ok(
|
||
data.preferredAction,
|
||
"using a helper application is the preferred action"
|
||
);
|
||
ok(data.preferredApplicationHandler, "handler was set as default handler");
|
||
is(data.handlers, 1, "one handler is set");
|
||
ok(!data.alwaysAskBeforeHandling, "will not show dialog");
|
||
ok(data.isWebHandler, "the handler is a web handler");
|
||
is(data.uriTemplate, `${handlerUrl}?val=%s`, "correct url template");
|
||
chromeScript.destroy();
|
||
|
||
extension.sendMessage("open", "ext+foo:test");
|
||
let id = await extension.awaitMessage("opened");
|
||
|
||
let query = await extension.awaitMessage("test-query");
|
||
is(query, "?val=ext%2Bfoo%3Atest", "test query ok");
|
||
is(id, await extension.awaitMessage("test-tab"), "id should match opened tab");
|
||
|
||
extension.sendMessage("close", id);
|
||
await extension.awaitMessage("closed");
|
||
|
||
// Test that handling a URL from the commandline works.
|
||
chromeScript = SpecialPowers.loadChromeScript(() => {
|
||
/* eslint-env mozilla/chrome-script */
|
||
const CONTENT_HANDLING_URL =
|
||
"chrome://mozapps/content/handling/permissionDialog.xhtml";
|
||
const { BrowserTestUtils } = ChromeUtils.importESModule(
|
||
"resource://testing-common/BrowserTestUtils.sys.mjs"
|
||
);
|
||
let cmdLineHandler = Cc["@mozilla.org/browser/final-clh;1"].getService(
|
||
Ci.nsICommandLineHandler
|
||
);
|
||
let fakeCmdLine = Cu.createCommandLine(
|
||
["-url", "ext+foo:cmdline"],
|
||
null,
|
||
Ci.nsICommandLine.STATE_REMOTE_EXPLICIT
|
||
);
|
||
cmdLineHandler.handle(fakeCmdLine);
|
||
|
||
// We aren't awaiting for this promise to resolve since it returns undefined
|
||
// (because it returns the reference to the dialog window that we close, below)
|
||
// once the callback promise below finishes, and because its not needed for anything
|
||
// outside of this loadChromeScript block.
|
||
BrowserTestUtils.promiseAlertDialogOpen(
|
||
null,
|
||
CONTENT_HANDLING_URL,
|
||
{
|
||
isSubDialog: true,
|
||
async callback(dialogWin) {
|
||
is(dialogWin.document.documentURI, CONTENT_HANDLING_URL, "Open dialog is the permission dialog")
|
||
|
||
let closePromise = BrowserTestUtils.waitForEvent(
|
||
dialogWin.browsingContext.topChromeWindow,
|
||
"dialogclose",
|
||
true,
|
||
);
|
||
let dialog = dialogWin.document.querySelector("dialog");
|
||
let btn = dialog.getButton("accept");
|
||
// The security delay disables this button, just bypass it.
|
||
btn.disabled = false;
|
||
btn.click();
|
||
return closePromise;
|
||
}
|
||
}
|
||
);
|
||
});
|
||
query = await extension.awaitMessage("test-query");
|
||
is(query, "?val=ext%2Bfoo%3Acmdline", "cmdline query ok");
|
||
id = await extension.awaitMessage("test-tab");
|
||
extension.sendMessage("close", id);
|
||
await extension.awaitMessage("closed");
|
||
chromeScript.destroy();
|
||
|
||
// Test the protocol in a private window, watch for the
|
||
// console error.
|
||
consoleMonitor.start([{ message: /NS_ERROR_FILE_NOT_FOUND/ }]);
|
||
|
||
// Expect the chooser window to be open, close it.
|
||
chromeScript = SpecialPowers.loadChromeScript(() => {
|
||
/* eslint-env mozilla/chrome-script */
|
||
const CONTENT_HANDLING_URL =
|
||
"chrome://mozapps/content/handling/appChooser.xhtml";
|
||
const { BrowserTestUtils } = ChromeUtils.importESModule(
|
||
"resource://testing-common/BrowserTestUtils.sys.mjs"
|
||
);
|
||
|
||
sendAsyncMessage("listenWindow");
|
||
|
||
// We aren't awaiting for this promise to resolve since it returns undefined
|
||
// (because it returns the reference to the dialog window that we close, below)
|
||
// once the callback promise below finishes, and because its not needed for anything
|
||
// outside of this loadChromeScript block.
|
||
BrowserTestUtils.promiseAlertDialogOpen(
|
||
null,
|
||
CONTENT_HANDLING_URL,
|
||
{
|
||
isSubDialog: true,
|
||
async callback(dialogWin) {
|
||
is(dialogWin.document.documentURI, CONTENT_HANDLING_URL, "Open dialog is the app chooser dialog")
|
||
|
||
let entry = dialogWin.document.getElementById("items")
|
||
.firstChild;
|
||
sendAsyncMessage("handling", {
|
||
name: entry.getAttribute("name"),
|
||
disabled: entry.disabled,
|
||
});
|
||
|
||
let closePromise = BrowserTestUtils.waitForEvent(
|
||
dialogWin.browsingContext.topChromeWindow,
|
||
"dialogclose",
|
||
true,
|
||
);
|
||
dialogWin.close();
|
||
return closePromise;
|
||
}
|
||
}
|
||
);
|
||
|
||
sendAsyncMessage("listenDialog");
|
||
});
|
||
|
||
// Wait for the chrome script to attach window listener
|
||
await chromeScript.promiseOneMessage("listenWindow");
|
||
|
||
let listenDialog = chromeScript.promiseOneMessage("listenDialog");
|
||
let windowOpen = pb_extension.awaitMessage("opened");
|
||
|
||
pb_extension.sendMessage("open", "ext+foo:test");
|
||
|
||
// Wait for chrome script to attach dialog listener
|
||
await listenDialog;
|
||
let { tabId, windowId } = await windowOpen;
|
||
|
||
let testData = chromeScript.promiseOneMessage("handling");
|
||
let navPromise = pb_extension.awaitMessage("navigated");
|
||
pb_extension.sendMessage("nav", { url: "ext+foo:test", tabId });
|
||
await navPromise;
|
||
await consoleMonitor.finished();
|
||
let entry = await testData;
|
||
|
||
is(entry.name, "a foo protocol handler", "entry is correct");
|
||
ok(entry.disabled, "handler is disabled");
|
||
|
||
let promiseClosed = pb_extension.awaitMessage("closed");
|
||
pb_extension.sendMessage("close", windowId);
|
||
await promiseClosed;
|
||
await pb_extension.unload();
|
||
|
||
// Shutdown the addon, then ensure the protocol was removed.
|
||
await extension.unload();
|
||
chromeScript = SpecialPowers.loadChromeScript(() => {
|
||
/* eslint-env mozilla/chrome-script */
|
||
addMessageListener("setup", () => {
|
||
const protoSvc = Cc[
|
||
"@mozilla.org/uriloader/external-protocol-service;1"
|
||
].getService(Ci.nsIExternalProtocolService);
|
||
let protoInfo = protoSvc.getProtocolHandlerInfo("ext+foo");
|
||
sendAsyncMessage(
|
||
"preferredApplicationHandler",
|
||
!protoInfo.preferredApplicationHandler
|
||
);
|
||
let handlers = protoInfo.possibleApplicationHandlers;
|
||
|
||
sendAsyncMessage("handlerData", {
|
||
preferredApplicationHandler: !protoInfo.preferredApplicationHandler,
|
||
handlers: handlers.length,
|
||
});
|
||
});
|
||
});
|
||
|
||
msg = chromeScript.promiseOneMessage("handlerData");
|
||
chromeScript.sendAsyncMessage("setup");
|
||
data = await msg;
|
||
ok(data.preferredApplicationHandler, "no preferred handler is set");
|
||
is(data.handlers, 0, "no handler is set");
|
||
chromeScript.destroy();
|
||
});
|
||
|
||
add_task(async function test_protocolHandler_two() {
|
||
let extensionData = {
|
||
manifest: {
|
||
protocol_handlers: [
|
||
{
|
||
protocol: "ext+foo",
|
||
name: "a foo protocol handler",
|
||
uriTemplate: "foo.html?val=%s",
|
||
},
|
||
{
|
||
protocol: "ext+foo",
|
||
name: "another foo protocol handler",
|
||
uriTemplate: "foo2.html?val=%s",
|
||
},
|
||
],
|
||
},
|
||
};
|
||
|
||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||
await extension.startup();
|
||
|
||
// Ensure that the protocol handler is configured, and set it as default,
|
||
// but because there are two handlers, the dialog is not bypassed. We
|
||
// don't test the actual dialog ui, it's been here forever and works based
|
||
// on the alwaysAskBeforeHandling value.
|
||
let chromeScript = SpecialPowers.loadChromeScript(protocolChromeScript);
|
||
|
||
let msg = chromeScript.promiseOneMessage("handlerData");
|
||
chromeScript.sendAsyncMessage("setup", {
|
||
protocol: "ext+foo",
|
||
principalOrigins: [],
|
||
});
|
||
let data = await msg;
|
||
ok(
|
||
data.preferredAction,
|
||
"using a helper application is the preferred action"
|
||
);
|
||
ok(data.preferredApplicationHandler, "preferred handler is set");
|
||
is(data.handlers, 2, "two handlers are set");
|
||
ok(data.alwaysAskBeforeHandling, "will show dialog");
|
||
ok(data.isWebHandler, "the handler is a web handler");
|
||
chromeScript.destroy();
|
||
await extension.unload();
|
||
});
|
||
|
||
add_task(async function test_protocolHandler_https_target() {
|
||
let extensionData = {
|
||
manifest: {
|
||
protocol_handlers: [
|
||
{
|
||
protocol: "ext+foo",
|
||
name: "http target",
|
||
uriTemplate: "https://example.com/foo.html?val=%s",
|
||
},
|
||
],
|
||
},
|
||
};
|
||
|
||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||
await extension.startup();
|
||
ok(true, "https uriTemplate target works");
|
||
await extension.unload();
|
||
});
|
||
|
||
add_task(async function test_protocolHandler_http_target() {
|
||
let extensionData = {
|
||
manifest: {
|
||
protocol_handlers: [
|
||
{
|
||
protocol: "ext+foo",
|
||
name: "http target",
|
||
uriTemplate: "http://example.com/foo.html?val=%s",
|
||
},
|
||
],
|
||
},
|
||
};
|
||
|
||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||
await extension.startup();
|
||
ok(true, "http uriTemplate target works");
|
||
await extension.unload();
|
||
});
|
||
|
||
add_task(async function test_protocolHandler_restricted_protocol() {
|
||
let extensionData = {
|
||
manifest: {
|
||
protocol_handlers: [
|
||
{
|
||
protocol: "http",
|
||
name: "take over the http protocol",
|
||
uriTemplate: "http.html?val=%s",
|
||
},
|
||
],
|
||
},
|
||
};
|
||
|
||
consoleMonitor.start([
|
||
{ message: /processing protocol_handlers\.0\.protocol/ },
|
||
]);
|
||
|
||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||
await Assert.rejects(
|
||
extension.startup(),
|
||
/startup failed/,
|
||
"unable to register restricted handler protocol"
|
||
);
|
||
|
||
await consoleMonitor.finished();
|
||
});
|
||
|
||
add_task(async function test_protocolHandler_restricted_uriTemplate() {
|
||
let extensionData = {
|
||
manifest: {
|
||
protocol_handlers: [
|
||
{
|
||
protocol: "ext+foo",
|
||
name: "take over the http protocol",
|
||
uriTemplate: "ftp://example.com/file.txt",
|
||
},
|
||
],
|
||
},
|
||
};
|
||
|
||
consoleMonitor.start([
|
||
{ message: /processing protocol_handlers\.0\.uriTemplate/ },
|
||
]);
|
||
|
||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||
await Assert.rejects(
|
||
extension.startup(),
|
||
/startup failed/,
|
||
"unable to register restricted handler uriTemplate"
|
||
);
|
||
|
||
await consoleMonitor.finished();
|
||
});
|
||
|
||
add_task(async function test_protocolHandler_duplicate() {
|
||
let extensionData = {
|
||
manifest: {
|
||
protocol_handlers: [
|
||
{
|
||
protocol: "ext+foo",
|
||
name: "foo protocol",
|
||
uriTemplate: "foo.html?val=%s",
|
||
},
|
||
{
|
||
protocol: "ext+foo",
|
||
name: "foo protocol",
|
||
uriTemplate: "foo.html?val=%s",
|
||
},
|
||
],
|
||
},
|
||
};
|
||
|
||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||
await extension.startup();
|
||
|
||
// Get the count of handlers installed.
|
||
let chromeScript = SpecialPowers.loadChromeScript(() => {
|
||
/* eslint-env mozilla/chrome-script */
|
||
addMessageListener("setup", () => {
|
||
const protoSvc = Cc[
|
||
"@mozilla.org/uriloader/external-protocol-service;1"
|
||
].getService(Ci.nsIExternalProtocolService);
|
||
let protoInfo = protoSvc.getProtocolHandlerInfo("ext+foo");
|
||
let handlers = protoInfo.possibleApplicationHandlers;
|
||
sendAsyncMessage("handlerData", handlers.length);
|
||
});
|
||
});
|
||
|
||
let msg = chromeScript.promiseOneMessage("handlerData");
|
||
chromeScript.sendAsyncMessage("setup");
|
||
let data = await msg;
|
||
is(data, 1, "cannot re-register the same handler config");
|
||
chromeScript.destroy();
|
||
await extension.unload();
|
||
});
|
||
|
||
// Test that the tabs.onUpdated event is fired for extension protocol handlers,
|
||
// even if the protocol handler does not exist and opens the error page for
|
||
// "The address wasn’t understood".
|
||
add_task(async function test_protocolHandler_onUpdated_missing_handler() {
|
||
let extensionData = {
|
||
manifest: {
|
||
permissions: ["tabs"]
|
||
},
|
||
|
||
background() {
|
||
let urlSeen = false;
|
||
let tabPromise = Promise.withResolvers();
|
||
const updateListener = async (tabId, changeInfo) => {
|
||
let tab = await tabPromise.promise;
|
||
if (tab.id != tabId) {
|
||
return;
|
||
}
|
||
browser.test.log(`tabs.onUpdated fired with changeInfo ${JSON.stringify(changeInfo)}`);
|
||
if (!urlSeen && changeInfo.url == "ext+missing:test") {
|
||
urlSeen = true;
|
||
}
|
||
if (urlSeen && changeInfo.status == "complete") {
|
||
browser.tabs.onUpdated.removeListener(updateListener);
|
||
await browser.tabs.remove(tabId);
|
||
browser.test.notifyPass();
|
||
}
|
||
};
|
||
browser.tabs.onUpdated.addListener(updateListener);
|
||
|
||
browser.test.log("Waiting for tabs.onUpdated event for 'ext+missing:test' with `complete` status.");
|
||
browser.tabs.create({ url: "ext+missing:test" }).then(
|
||
tab => tabPromise.resolve(tab)
|
||
);
|
||
},
|
||
};
|
||
|
||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||
await extension.startup();
|
||
await extension.awaitFinish();
|
||
await extension.unload();
|
||
});
|
||
|
||
// Test that a protocol handler will work if ftp is enabled
|
||
add_task(async function test_ftp_protocolHandler() {
|
||
let extensionData = {
|
||
manifest: {
|
||
protocol_handlers: [
|
||
{
|
||
protocol: "ftp",
|
||
name: "an ftp protocol handler",
|
||
uriTemplate: "ftp.html?val=%s",
|
||
},
|
||
],
|
||
},
|
||
|
||
async background() {
|
||
let url = "ftp://example.com/file.txt";
|
||
browser.test.onMessage.addListener(async () => {
|
||
await browser.tabs.create({ url });
|
||
});
|
||
},
|
||
|
||
files: {
|
||
"ftp.js": function() {
|
||
browser.test.sendMessage("test-query", location.search);
|
||
},
|
||
"ftp.html": `<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<script src="ftp.js"><\/script>
|
||
</head>
|
||
</html>`,
|
||
},
|
||
};
|
||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||
await extension.startup();
|
||
const handlerUrl = `moz-extension://${extension.uuid}/ftp.html`;
|
||
|
||
let chromeScript = SpecialPowers.loadChromeScript(protocolChromeScript);
|
||
|
||
// Set the preferredAction to this extension as ftp will default to system. If
|
||
// we didn't bypass the dialog for this test, the user would get asked in this case.
|
||
let msg = chromeScript.promiseOneMessage("set");
|
||
chromeScript.sendAsyncMessage("setPreferredAction", {
|
||
protocol: "ftp",
|
||
template: handlerUrl,
|
||
});
|
||
await msg;
|
||
|
||
msg = chromeScript.promiseOneMessage("handlerData");
|
||
chromeScript.sendAsyncMessage("setup", { protocol: "ftp", principalOrigins: [] });
|
||
let data = await msg;
|
||
ok(
|
||
data.preferredAction,
|
||
"using a helper application is the preferred action"
|
||
);
|
||
ok(data.preferredApplicationHandler, "handler was set as default handler");
|
||
is(data.handlers, 1, "one handler is set");
|
||
ok(!data.alwaysAskBeforeHandling, "will not show dialog");
|
||
ok(data.isWebHandler, "the handler is a web handler");
|
||
is(data.uriTemplate, `${handlerUrl}?val=%s`, "correct url template");
|
||
|
||
chromeScript.destroy();
|
||
|
||
extension.sendMessage("run");
|
||
let query = await extension.awaitMessage("test-query");
|
||
is(query, "?val=ftp%3A%2F%2Fexample.com%2Ffile.txt", "test query ok");
|
||
await extension.unload();
|
||
});
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|