309 lines
9.4 KiB
JavaScript
309 lines
9.4 KiB
JavaScript
/* 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 chromeSpawnedWorker = new hud.iframeWindow.Worker(
|
||
getRootDirectory(gTestPath) + "test-parent-worker.js"
|
||
);
|
||
|
||
// 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,
|
||
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"
|
||
);
|
||
}
|