270 lines
7.3 KiB
JavaScript
270 lines
7.3 KiB
JavaScript
"use strict";
|
|
|
|
const server = createHttpServer();
|
|
server.registerDirectory("/data/", do_get_file("data"));
|
|
|
|
const BASE_URL = `http://localhost:${server.identity.primaryPort}/data`;
|
|
|
|
// ExtensionContent.jsm needs to know when it's running from xpcshell,
|
|
// to use the right timeout for content scripts executed at document_idle.
|
|
ExtensionTestUtils.mockAppInfo();
|
|
|
|
add_task(async function test_contentscript_runAt() {
|
|
function background() {
|
|
browser.runtime.onMessage.addListener(
|
|
([msg, expectedStates, readyState]) => {
|
|
if (msg == "chrome-namespace-ok") {
|
|
browser.test.sendMessage(msg);
|
|
return;
|
|
}
|
|
|
|
browser.test.assertEq("script-run", msg, "message type is correct");
|
|
browser.test.assertTrue(
|
|
expectedStates.includes(readyState),
|
|
`readyState "${readyState}" is one of [${expectedStates}]`
|
|
);
|
|
browser.test.sendMessage("script-run-" + expectedStates[0]);
|
|
}
|
|
);
|
|
}
|
|
|
|
function contentScriptStart() {
|
|
browser.runtime.sendMessage([
|
|
"script-run",
|
|
["loading"],
|
|
document.readyState,
|
|
]);
|
|
}
|
|
function contentScriptEnd() {
|
|
browser.runtime.sendMessage([
|
|
"script-run",
|
|
["interactive", "complete"],
|
|
document.readyState,
|
|
]);
|
|
}
|
|
function contentScriptIdle() {
|
|
browser.runtime.sendMessage([
|
|
"script-run",
|
|
["complete"],
|
|
document.readyState,
|
|
]);
|
|
}
|
|
|
|
function contentScript() {
|
|
let manifest = browser.runtime.getManifest();
|
|
void manifest.applications.gecko.id;
|
|
browser.runtime.sendMessage(["chrome-namespace-ok"]);
|
|
}
|
|
|
|
let extensionData = {
|
|
manifest: {
|
|
browser_specific_settings: {
|
|
gecko: { id: "contentscript@tests.mozilla.org" },
|
|
},
|
|
content_scripts: [
|
|
{
|
|
matches: ["http://*/*/file_sample.html"],
|
|
js: ["content_script_start.js"],
|
|
run_at: "document_start",
|
|
},
|
|
{
|
|
matches: ["http://*/*/file_sample.html"],
|
|
js: ["content_script_end.js"],
|
|
run_at: "document_end",
|
|
},
|
|
{
|
|
matches: ["http://*/*/file_sample.html"],
|
|
js: ["content_script_idle.js"],
|
|
run_at: "document_idle",
|
|
},
|
|
{
|
|
matches: ["http://*/*/file_sample.html"],
|
|
js: ["content_script_idle.js"],
|
|
// Test default `run_at`.
|
|
},
|
|
{
|
|
matches: ["http://*/*/file_sample.html"],
|
|
js: ["content_script.js"],
|
|
run_at: "document_idle",
|
|
},
|
|
],
|
|
},
|
|
background,
|
|
|
|
files: {
|
|
"content_script_start.js": contentScriptStart,
|
|
"content_script_end.js": contentScriptEnd,
|
|
"content_script_idle.js": contentScriptIdle,
|
|
"content_script.js": contentScript,
|
|
},
|
|
};
|
|
|
|
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
|
|
|
let loadingCount = 0;
|
|
let interactiveCount = 0;
|
|
let completeCount = 0;
|
|
extension.onMessage("script-run-loading", () => {
|
|
loadingCount++;
|
|
});
|
|
extension.onMessage("script-run-interactive", () => {
|
|
interactiveCount++;
|
|
});
|
|
|
|
let completePromise = new Promise(resolve => {
|
|
extension.onMessage("script-run-complete", () => {
|
|
completeCount++;
|
|
if (completeCount > 1) {
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
|
|
let chromeNamespacePromise = extension.awaitMessage("chrome-namespace-ok");
|
|
|
|
await extension.startup();
|
|
|
|
let contentPage = await ExtensionTestUtils.loadContentPage(
|
|
`${BASE_URL}/file_sample.html`
|
|
);
|
|
|
|
await Promise.all([completePromise, chromeNamespacePromise]);
|
|
|
|
await contentPage.close();
|
|
|
|
equal(loadingCount, 1, "document_start script ran exactly once");
|
|
equal(interactiveCount, 1, "document_end script ran exactly once");
|
|
equal(completeCount, 2, "document_idle script ran exactly twice");
|
|
|
|
await extension.unload();
|
|
});
|
|
|
|
add_task(async function test_contentscript_window_open() {
|
|
if (AppConstants.DEBUG && Services.appinfo.browserTabsRemoteAutostart) {
|
|
return;
|
|
}
|
|
|
|
let script = async () => {
|
|
/* globals x */
|
|
browser.test.assertEq(1, x, "Should only run once");
|
|
|
|
if (top !== window) {
|
|
// Wait for our parent page to load, then set a timeout to wait for the
|
|
// document.open call, so we make sure to not tear down the extension
|
|
// until after we've done the document.open.
|
|
await new Promise(resolve => {
|
|
top.addEventListener("load", () => setTimeout(resolve, 0), {
|
|
once: true,
|
|
});
|
|
});
|
|
}
|
|
|
|
browser.test.sendMessage("content-script", [location.href, top === window]);
|
|
};
|
|
|
|
let extension = ExtensionTestUtils.loadExtension({
|
|
manifest: {
|
|
browser_specific_settings: {
|
|
gecko: { id: "contentscript@tests.mozilla.org" },
|
|
},
|
|
content_scripts: [
|
|
{
|
|
matches: ["<all_urls>"],
|
|
js: ["content_script.js"],
|
|
run_at: "document_start",
|
|
match_about_blank: true,
|
|
all_frames: true,
|
|
},
|
|
],
|
|
},
|
|
|
|
files: {
|
|
"content_script.js": `
|
|
var x = (x || 0) + 1;
|
|
(${script})();
|
|
`,
|
|
},
|
|
});
|
|
|
|
await extension.startup();
|
|
|
|
let url = `${BASE_URL}/file_document_open.html`;
|
|
let contentPage = await ExtensionTestUtils.loadContentPage(url);
|
|
|
|
let [pageURL, pageIsTop] = await extension.awaitMessage("content-script");
|
|
|
|
// Sometimes we get a content script load for the initial about:blank
|
|
// top level frame here, sometimes we don't. Either way is fine, as long as we
|
|
// don't get two loads into the same document.open() document.
|
|
if (pageURL === "about:blank") {
|
|
equal(pageIsTop, true);
|
|
[pageURL, pageIsTop] = await extension.awaitMessage("content-script");
|
|
}
|
|
|
|
Assert.deepEqual([pageURL, pageIsTop], [url, true]);
|
|
|
|
let [frameURL, isTop] = await extension.awaitMessage("content-script");
|
|
Assert.deepEqual([frameURL, isTop], [url, false]);
|
|
|
|
await contentPage.close();
|
|
await extension.unload();
|
|
});
|
|
|
|
// This test verify that a cached script is still able to catch the document
|
|
// while it is still loading (when we do not block the document parsing as
|
|
// we do for a non cached script).
|
|
add_task(async function test_cached_contentscript_on_document_start() {
|
|
let extension = ExtensionTestUtils.loadExtension({
|
|
manifest: {
|
|
content_scripts: [
|
|
{
|
|
matches: ["http://localhost/*/file_document_open.html"],
|
|
js: ["content_script.js"],
|
|
run_at: "document_start",
|
|
},
|
|
],
|
|
},
|
|
|
|
files: {
|
|
"content_script.js": `
|
|
browser.test.sendMessage("content-script-loaded", {
|
|
url: window.location.href,
|
|
documentReadyState: document.readyState,
|
|
});
|
|
`,
|
|
},
|
|
});
|
|
|
|
await extension.startup();
|
|
|
|
let url = `${BASE_URL}/file_document_open.html`;
|
|
let contentPage = await ExtensionTestUtils.loadContentPage(url);
|
|
|
|
let msg = await extension.awaitMessage("content-script-loaded");
|
|
Assert.deepEqual(
|
|
msg,
|
|
{
|
|
url,
|
|
documentReadyState: "loading",
|
|
},
|
|
"Got the expected url and document.readyState from a non cached script"
|
|
);
|
|
|
|
// Reload the page and check that the cached content script is still able to
|
|
// run on document_start.
|
|
await contentPage.loadURL(url);
|
|
|
|
let msgFromCached = await extension.awaitMessage("content-script-loaded");
|
|
Assert.deepEqual(
|
|
msgFromCached,
|
|
{
|
|
url,
|
|
documentReadyState: "loading",
|
|
},
|
|
"Got the expected url and document.readyState from a cached script"
|
|
);
|
|
|
|
await extension.unload();
|
|
|
|
await contentPage.close();
|
|
});
|