summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_errors.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_contentscript_errors.js')
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_contentscript_errors.js150
1 files changed, 150 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_errors.js b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_errors.js
new file mode 100644
index 0000000000..6fae3b838a
--- /dev/null
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_errors.js
@@ -0,0 +1,150 @@
+"use strict";
+
+const server = createHttpServer();
+server.registerDirectory("/data/", do_get_file("data"));
+
+const BASE_URL = `http://localhost:${server.identity.primaryPort}/data`;
+const TEST_URL_1 = `${BASE_URL}/file_sample.html`;
+const TEST_URL_2 = `${BASE_URL}/file_content_script_errors.html`;
+
+// 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_cached_contentscript_on_document_start() {
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ content_scripts: [
+ // Use distinct content scripts as some will throw and would prevent executing the next script
+ {
+ matches: ["http://*/*/file_content_script_errors.html"],
+ js: ["script1.js"],
+ run_at: "document_start",
+ },
+ {
+ matches: ["http://*/*/file_content_script_errors.html"],
+ js: ["script2.js"],
+ run_at: "document_start",
+ },
+ {
+ matches: ["http://*/*/file_content_script_errors.html"],
+ js: ["script3.js"],
+ run_at: "document_start",
+ },
+ {
+ matches: ["http://*/*/file_content_script_errors.html"],
+ js: ["script4.js"],
+ run_at: "document_start",
+ },
+ {
+ matches: ["http://*/*/file_content_script_errors.html"],
+ js: ["script5.js"],
+ run_at: "document_start",
+ },
+ ],
+ },
+
+ files: {
+ "script1.js": `
+ throw new Error("Object exception");
+ `,
+ "script2.js": `
+ throw "String exception";
+ `,
+ "script3.js": `
+ undefinedSymbol();
+ `,
+ "script4.js": `
+ )
+ `,
+ "script5.js": `
+ Promise.reject("rejected promise");
+
+ (async () => {
+ /* make the async, really async */
+ await new Promise(r => setTimeout(r, 0));
+ throw new Error("async function exception");
+ })();
+
+ setTimeout(() => {
+ asyncUndefinedSymbol();
+ });
+
+ /* Use a delay in order to resume test execution after these async errors */
+ setTimeout(() => {
+ browser.test.sendMessage("content-script-loaded");
+ }, 500);
+ `,
+ },
+ });
+
+ // Error messages, in roughly the order they appear above.
+ let expectedMessages = [
+ "Error: Object exception",
+ "uncaught exception: String exception",
+ "ReferenceError: undefinedSymbol is not defined",
+ "SyntaxError: expected expression, got ')'",
+ "uncaught exception: rejected promise",
+ "Error: async function exception",
+ "ReferenceError: asyncUndefinedSymbol is not defined",
+ ];
+
+ await extension.startup();
+
+ // Load a first page in order to be able to register a console listener in the content process.
+ // This has to be done in the same domain of the second page to stay in the same process.
+ let contentPage = await ExtensionTestUtils.loadContentPage(TEST_URL_1);
+
+ // Listen to the errors logged in the content process.
+ let errorsPromise = ContentTask.spawn(contentPage.browser, {}, async () => {
+ return new Promise(resolve => {
+ function listener(error0) {
+ let error = error0.QueryInterface(Ci.nsIScriptError);
+
+ // Ignore errors from ExtensionContent.jsm
+ if (!error.innerWindowID) {
+ return;
+ }
+
+ this.collectedErrors.push({
+ innerWindowID: error.innerWindowID,
+ message: error.errorMessage,
+ });
+ if (this.collectedErrors.length == 7) {
+ Services.console.unregisterListener(this);
+ resolve(this.collectedErrors);
+ }
+ }
+ listener.collectedErrors = [];
+ Services.console.registerListener(listener);
+ });
+ });
+
+ // Reload the page and check that the cached content script is still able to
+ // run on document_start.
+ await contentPage.loadURL(TEST_URL_2);
+
+ let errors = await errorsPromise;
+
+ await extension.awaitMessage("content-script-loaded");
+
+ equal(errors.length, 7);
+ let messages = [];
+ for (const { innerWindowID, message } of errors) {
+ equal(
+ innerWindowID,
+ contentPage.browser.innerWindowID,
+ `Message ${message} has the innerWindowID set`
+ );
+
+ messages.push(message);
+ }
+
+ messages.sort();
+ expectedMessages.sort();
+ Assert.deepEqual(messages, expectedMessages, "Got the expected errors");
+
+ await extension.unload();
+
+ await contentPage.close();
+});