Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

"use strict";
// There is a rejection emitted when a JS file fails to load. On Android,
// extensions run on the main process and this rejection causes test failures,
// which is essentially why we need to allow the rejection below.
PromiseTestUtils.allowMatchingRejectionsGlobally(
/Unable to load script.*content_script/
);
const server = createHttpServer();
server.registerDirectory("/data/", do_get_file("data"));
const BASE_URL = `http://localhost:${server.identity.primaryPort}/data`;
function computeSHA256Hash(text) {
const hasher = Cc["@mozilla.org/security/hash;1"].createInstance(
Ci.nsICryptoHash
);
hasher.init(Ci.nsICryptoHash.SHA256);
hasher.update(
text.split("").map(c => c.charCodeAt(0)),
text.length
);
return hasher.finish(true);
}
// This function represents a dummy content or background script that the test
// cases below should attempt to load but it shouldn't be loaded because we
// check the extensions of JavaScript files in `nsJARChannel`.
function scriptThatShouldNotBeLoaded() {
browser.test.fail("this should not be executed");
}
function scriptThatAlwaysRuns() {
browser.test.sendMessage("content-script-loaded");
}
// We use these variables in combination with `scriptThatAlwaysRuns()` to send a
// signal to the extension and avoid the page to be closed too soon.
const alwaysRunsFileName = "always_run.js";
const alwaysRunsContentScript = {
matches: ["<all_urls>"],
js: [alwaysRunsFileName],
run_at: "document_start",
};
add_task(async function test_content_script_filename_without_extension() {
// Filenames without any extension should not be loaded.
let invalidFileName = "content_script";
let extensionData = {
manifest: {
content_scripts: [
alwaysRunsContentScript,
{
matches: ["<all_urls>"],
js: [invalidFileName],
},
],
},
files: {
[invalidFileName]: scriptThatShouldNotBeLoaded,
[alwaysRunsFileName]: scriptThatAlwaysRuns,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
let contentPage = await ExtensionTestUtils.loadContentPage(
`${BASE_URL}/file_sample.html`
);
await extension.awaitMessage("content-script-loaded");
await contentPage.close();
await extension.unload();
});
add_task(async function test_content_script_filename_with_invalid_extension() {
let validFileName = "content_script.js";
let invalidFileName = "content_script.xyz";
let extensionData = {
manifest: {
content_scripts: [
alwaysRunsContentScript,
{
matches: ["<all_urls>"],
js: [validFileName, invalidFileName],
},
],
},
files: {
// This makes sure that, when one of the content scripts fails to load,
// none of the content scripts are executed.
[validFileName]: scriptThatShouldNotBeLoaded,
[invalidFileName]: scriptThatShouldNotBeLoaded,
[alwaysRunsFileName]: scriptThatAlwaysRuns,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
let contentPage = await ExtensionTestUtils.loadContentPage(
`${BASE_URL}/file_sample.html`
);
await extension.awaitMessage("content-script-loaded");
await contentPage.close();
await extension.unload();
});
add_task(async function test_bg_script_injects_script_with_invalid_ext() {
function backgroundScript() {
browser.test.sendMessage("background-script-loaded");
}
let validFileName = "background.js";
let invalidFileName = "invalid_background.xyz";
let extensionData = {
background() {
const script = document.createElement("script");
script.src = "./invalid_background.xyz";
document.head.appendChild(script);
const validScript = document.createElement("script");
validScript.src = "./background.js";
document.head.appendChild(validScript);
},
files: {
[invalidFileName]: scriptThatShouldNotBeLoaded,
[validFileName]: backgroundScript,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("background-script-loaded");
await extension.unload();
});
add_task(async function test_background_scripts() {
function backgroundScript() {
browser.test.sendMessage("background-script-loaded");
}
let validFileName = "background.js";
let invalidFileName = "invalid_background.xyz";
let extensionData = {
manifest: {
background: {
scripts: [invalidFileName, validFileName],
},
},
files: {
[invalidFileName]: scriptThatShouldNotBeLoaded,
[validFileName]: backgroundScript,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("background-script-loaded");
await extension.unload();
});
add_task(async function test_background_page_injects_scripts_inline() {
function injectedBackgroundScript() {
browser.test.log(
"inline script injectedBackgroundScript has been executed"
);
browser.test.sendMessage("background-script-loaded");
}
let backgroundHtmlPage = "background_page.html";
let validFileName = "injected_background.js";
let invalidFileName = "invalid_background.xyz";
let inlineScript = `(${function () {
const script = document.createElement("script");
script.src = "./invalid_background.xyz";
document.head.appendChild(script);
const validScript = document.createElement("script");
validScript.src = "./injected_background.js";
document.head.appendChild(validScript);
}})()`;
const inlineScriptSHA256 = computeSHA256Hash(inlineScript);
info(
`Computed sha256 for the inline script injectedBackgroundScript: ${inlineScriptSHA256}`
);
let extensionData = {
manifest: {
background: { page: backgroundHtmlPage },
content_security_policy: [
"script-src",
"'self'",
`'sha256-${inlineScriptSHA256}'`,
";",
].join(" "),
},
files: {
[invalidFileName]: scriptThatShouldNotBeLoaded,
[validFileName]: injectedBackgroundScript,
"pre-script.js": () => {
window.onsecuritypolicyviolation = evt => {
const { violatedDirective, originalPolicy } = evt;
browser.test.fail(
`Unexpected csp violation: ${JSON.stringify({
violatedDirective,
originalPolicy,
})}`
);
// Let the test to fail immediately when an unexpected csp violation
// prevented the inline script from being executed successfully.
browser.test.sendMessage("background-script-loaded");
};
},
[backgroundHtmlPage]: `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"></head>
<script src="pre-script.js"></script>
<script>${inlineScript}</script>
</head>
</html>`,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("background-script-loaded");
await extension.unload();
});
add_task(async function test_background_page_injects_scripts() {
// This is the initial background script loaded in the HTML page.
function backgroundScript() {
const script = document.createElement("script");
script.src = "./invalid_background.xyz";
document.head.appendChild(script);
const validScript = document.createElement("script");
validScript.src = "./injected_background.js";
document.head.appendChild(validScript);
}
// This is the script injected by the script defined in `backgroundScript()`.
function injectedBackgroundScript() {
browser.test.sendMessage("background-script-loaded");
}
let backgroundHtmlPage = "background_page.html";
let validFileName = "injected_background.js";
let invalidFileName = "invalid_background.xyz";
let extensionData = {
manifest: {
background: { page: backgroundHtmlPage },
},
files: {
[invalidFileName]: scriptThatShouldNotBeLoaded,
[validFileName]: injectedBackgroundScript,
[backgroundHtmlPage]: `
<html>
<head>
<meta charset="utf-8"></head>
<script src="./background.js"></script>
</head>
</html>`,
"background.js": backgroundScript,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
await extension.awaitMessage("background-script-loaded");
await extension.unload();
});
add_task(async function test_background_script_registers_content_script() {
let invalidFileName = "content_script";
let extensionData = {
manifest: {
permissions: ["<all_urls>"],
},
async background() {
await browser.contentScripts.register({
js: [{ file: "/content_script" }],
matches: ["<all_urls>"],
});
browser.test.sendMessage("background-script-loaded");
},
files: {
[invalidFileName]: scriptThatShouldNotBeLoaded,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
let contentPage = await ExtensionTestUtils.loadContentPage(
`${BASE_URL}/file_sample.html`
);
await extension.awaitMessage("background-script-loaded");
await contentPage.close();
await extension.unload();
});
add_task(async function test_web_accessible_resources() {
function contentScript() {
const script = document.createElement("script");
script.src = browser.runtime.getURL("content_script.css");
script.onerror = () => {
browser.test.sendMessage("second-content-script-loaded");
};
document.head.appendChild(script);
}
let contentScriptFileName = "content_script.js";
let invalidFileName = "content_script.css";
let extensionData = {
manifest: {
web_accessible_resources: [invalidFileName],
content_scripts: [
alwaysRunsContentScript,
{
matches: ["<all_urls>"],
js: [contentScriptFileName],
},
],
},
files: {
[invalidFileName]: scriptThatShouldNotBeLoaded,
[contentScriptFileName]: contentScript,
[alwaysRunsFileName]: scriptThatAlwaysRuns,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
let contentPage = await ExtensionTestUtils.loadContentPage(
`${BASE_URL}/file_sample.html`
);
await extension.awaitMessage("content-script-loaded");
await extension.awaitMessage("second-content-script-loaded");
await contentPage.close();
await extension.unload();
});