summaryrefslogtreecommitdiffstats
path: root/devtools/client/webconsole/test/browser/browser_console.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/webconsole/test/browser/browser_console.js')
-rw-r--r--devtools/client/webconsole/test/browser/browser_console.js315
1 files changed, 315 insertions, 0 deletions
diff --git a/devtools/client/webconsole/test/browser/browser_console.js b/devtools/client/webconsole/test/browser/browser_console.js
new file mode 100644
index 0000000000..131678415b
--- /dev/null
+++ b/devtools/client/webconsole/test/browser/browser_console.js
@@ -0,0 +1,315 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the basic features of the Browser Console.
+
+"use strict";
+
+requestLongerTimeout(2);
+
+const TEST_URI =
+ "http://example.com/browser/devtools/client/webconsole/" +
+ "test/browser/test-console.html?" +
+ Date.now();
+
+const TEST_XHR_ERROR_URI = `http://example.com/404.html?${Date.now()}`;
+
+const TEST_IMAGE =
+ "http://example.com/browser/devtools/client/webconsole/" +
+ "test/test-image.png";
+
+add_task(async function () {
+ // Needed for the execute() call in `testMessages`.
+ await pushPref("security.allow_parent_unrestricted_js_loads", true);
+ await pushPref("devtools.browserconsole.enableNetworkMonitoring", true);
+ await pushPref("devtools.browsertoolbox.scope", "everything");
+
+ // Open a parent process tab to check it doesn't have impact
+ const aboutRobotsTab = await addTab("about:robots");
+ // And open the "actual" test tab
+ const tab = await addTab(TEST_URI);
+
+ await testMessages();
+
+ info("Close tab");
+ await removeTab(tab);
+ await removeTab(aboutRobotsTab);
+});
+
+async function testMessages() {
+ const opened = waitForBrowserConsole();
+ let hud = BrowserConsoleManager.getBrowserConsole();
+ ok(!hud, "browser console is not open");
+
+ // The test harness does override the global's console property to replace it with
+ // a Console.sys.mjs instance (https://searchfox.org/mozilla-central/rev/c5c002f81f08a73e04868e0c2bf0eb113f200b03/testing/mochitest/api.js#75-78)
+ // So here we reset the console property with the native console (which is luckily
+ // stored in `nativeConsole`).
+ const overriddenConsole = globalThis.console;
+ globalThis.console = globalThis.nativeConsole;
+
+ info("wait for the browser console to open with ctrl-shift-j");
+ EventUtils.synthesizeKey("j", { accelKey: true, shiftKey: true }, window);
+
+ hud = await opened;
+ ok(hud, "browser console opened");
+
+ info("Check that we don't display the non-native console API warning");
+ // Wait a bit to let room for the message to be displayed
+ await wait(1000);
+ is(
+ await findMessageVirtualizedByType({
+ hud,
+ text: "The Web Console logging API",
+ typeSelector: ".warn",
+ }),
+ undefined,
+ "The message about disabled console API is not displayed"
+ );
+ // Set the overidden console back.
+ globalThis.console = overriddenConsole;
+
+ await clearOutput(hud);
+
+ await setFilterState(hud, {
+ netxhr: true,
+ css: true,
+ });
+
+ executeSoon(() => {
+ expectUncaughtException();
+ // eslint-disable-next-line no-undef
+ foobarException();
+ });
+
+ // Add a message from a chrome window.
+ hud.iframeWindow.console.log("message from chrome window");
+
+ // Spawn worker from a chrome window and log a message and an error
+ const workerCode = `console.log("message in parent worker");
+ throw new Error("error in parent worker");`;
+ const blob = new hud.iframeWindow.Blob([workerCode], {
+ type: "application/javascript",
+ });
+ const chromeSpawnedWorker = new hud.iframeWindow.Worker(
+ URL.createObjectURL(blob)
+ );
+
+ // Spawn Chrome worker from a chrome window and log a message
+ // It's important to use the browser console global so the message gets assigned
+ // a non-numeric innerID in Console.cpp
+ const browserConsoleGlobal = Cu.getGlobalForObject(hud);
+ const chromeWorker = new browserConsoleGlobal.ChromeWorker(
+ URL.createObjectURL(
+ new browserConsoleGlobal.Blob(
+ [`console.log("message in chrome worker")`],
+ {
+ type: "application/javascript",
+ }
+ )
+ )
+ );
+
+ const sandbox = new Cu.Sandbox(null, {
+ wantComponents: false,
+ wantGlobalProperties: ["URL", "URLSearchParams"],
+ });
+ const error = Cu.evalInSandbox(
+ `new Error("error from nuked globals");`,
+ sandbox
+ );
+ console.error(error);
+ Cu.nukeSandbox(sandbox);
+
+ const componentsException = new Components.Exception("Components.Exception");
+ console.error(componentsException);
+
+ // Check privileged error message from a content process
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ (async function () {
+ throw new Error("privileged content process error message");
+ })();
+ });
+
+ // Add a message from a content window.
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ content.wrappedJSObject.console.log("message from content window");
+ content.wrappedJSObject.throwError("error from content window");
+
+ content.testWorker = new content.Worker("./test-worker.js");
+ content.testWorker.postMessage({
+ type: "log",
+ message: "message in content worker",
+ });
+ content.testWorker.postMessage({
+ type: "error",
+ message: "error in content worker",
+ });
+ });
+
+ // Test eval.
+ execute(hud, "`Parent Process Location: ${document.location.href}`");
+
+ // Test eval frame script
+ gBrowser.selectedBrowser.messageManager.loadFrameScript(
+ `data:application/javascript,console.log("framescript-message")`,
+ false
+ );
+
+ // Check for network requests.
+ const xhr = new XMLHttpRequest();
+ xhr.onload = () => console.log("xhr loaded, status is: " + xhr.status);
+ xhr.open("get", TEST_URI, true);
+ xhr.send();
+
+ // Check for xhr error.
+ const xhrErr = new XMLHttpRequest();
+ xhrErr.onload = () => {
+ console.log("xhr error loaded, status is: " + xhrErr.status);
+ };
+ xhrErr.open("get", TEST_XHR_ERROR_URI, true);
+ xhrErr.send();
+
+ // Check that Fetch requests are categorized as "XHR".
+ await fetch(TEST_IMAGE);
+ console.log("fetch loaded");
+
+ // Check messages logged with Services.console.logMessage
+ const scriptErrorMessage = Cc["@mozilla.org/scripterror;1"].createInstance(
+ Ci.nsIScriptError
+ );
+ scriptErrorMessage.initWithWindowID(
+ "Error from Services.console.logMessage",
+ gBrowser.currentURI.prePath,
+ null,
+ 0,
+ 0,
+ Ci.nsIScriptError.warningFlag,
+ // platform-specific category to test case for Bug 1770160
+ "chrome javascript",
+ gBrowser.selectedBrowser.innerWindowID
+ );
+ Services.console.logMessage(scriptErrorMessage);
+
+ // Check messages logged in content with Log.sys.mjs
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ const { Log } = ChromeUtils.importESModule(
+ "resource://gre/modules/Log.sys.mjs"
+ );
+ const logger = Log.repository.getLogger("TEST_LOGGER_" + Date.now());
+ logger.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
+ logger.level = Log.Level.Info;
+ logger.info("Log.sys.mjs content process messsage");
+ });
+
+ // Check CSS warnings in parent process
+ await execute(hud, `document.body.style.backgroundColor = "rainbow"`);
+
+ // Wait enough so any duplicated message would have the time to be rendered
+ await wait(1000);
+
+ await checkUniqueMessageExists(
+ hud,
+ "message from chrome window",
+ ".console-api"
+ );
+ await checkUniqueMessageExists(hud, "error from nuked globals", ".error");
+ await checkUniqueMessageExists(
+ hud,
+ "privileged content process error message",
+ ".error"
+ );
+ await checkUniqueMessageExists(
+ hud,
+ "message from content window",
+ ".console-api"
+ );
+ await checkUniqueMessageExists(hud, "error from content window", ".error");
+ await checkUniqueMessageExists(
+ hud,
+ `"Parent Process Location: chrome://browser/content/browser.xhtml"`,
+ ".result"
+ );
+ await checkUniqueMessageExists(hud, "framescript-message", ".console-api");
+ await checkUniqueMessageExists(
+ hud,
+ "Error from Services.console.logMessage",
+ ".warn"
+ );
+ await checkUniqueMessageExists(hud, "foobarException", ".error");
+ await checkUniqueMessageExists(hud, "test-console.html", ".network");
+ await checkUniqueMessageExists(hud, "404.html", ".network");
+ await checkUniqueMessageExists(hud, "test-image.png", ".network");
+ await checkUniqueMessageExists(
+ hud,
+ "Log.sys.mjs content process messsage",
+ ".console-api"
+ );
+ await checkUniqueMessageExists(
+ hud,
+ "message in content worker",
+ ".console-api"
+ );
+ await checkUniqueMessageExists(hud, "error in content worker", ".error");
+ await checkUniqueMessageExists(
+ hud,
+ "message in parent worker",
+ ".console-api"
+ );
+ await checkUniqueMessageExists(hud, "error in parent worker", ".error");
+ await checkUniqueMessageExists(
+ hud,
+ "message in chrome worker",
+ ".console-api"
+ );
+ await checkUniqueMessageExists(
+ hud,
+ "Expected color but found ‘rainbow’",
+ ".warn"
+ );
+ await checkUniqueMessageExists(
+ hud,
+ "Expected color but found ‘bled’",
+ ".warn"
+ );
+
+ await checkComponentExceptionMessage(hud, componentsException);
+
+ await resetFilters(hud);
+
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ content.testWorker.terminate();
+ delete content.testWorker;
+ });
+ chromeSpawnedWorker.terminate();
+ chromeWorker.terminate();
+ info("Close the Browser Console");
+ await safeCloseBrowserConsole();
+}
+
+async function checkComponentExceptionMessage(hud, exception) {
+ const msgNode = await checkUniqueMessageExists(
+ hud,
+ "Components.Exception",
+ ".error"
+ );
+ const framesNode = await waitFor(() => msgNode.querySelector(".pane.frames"));
+ ok(framesNode, "The Components.Exception stack is displayed right away");
+
+ const frameNodes = framesNode.querySelectorAll(".frame");
+ Assert.greater(frameNodes.length, 1, "Got at least one frame in the stack");
+ is(
+ frameNodes[0].querySelector(".line").textContent,
+ String(exception.lineNumber),
+ "The stack displayed by default refers to Components.Exception passed as argument"
+ );
+
+ const [, line] = msgNode
+ .querySelector(".frame-link-line")
+ .textContent.split(":");
+ is(
+ line,
+ String(exception.lineNumber + 1),
+ "The link on the top right refers to the console.error callsite"
+ );
+}