/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ add_task(async function test_message_properties() { const listenerId = await listenToConsoleMessage("error"); await logConsoleMessage({ message: "foo" }); const { level, message, timeStamp, stack } = await getConsoleMessage( listenerId ); is(level, "error", "Received expected log level"); is(message, "foo", "Received expected log message"); // Services.console.logMessage() doesn't include a stack. is(stack, undefined, "No stack present"); is(typeof timeStamp, "number", "timestamp is of expected type number"); // Clear the console to avoid side effects with other tests in this file. await clearConsole(); }); add_task(async function test_level() { for (const level of ["error", "info", "warn"]) { const listenerId = await listenToConsoleMessage(level); await logConsoleMessage({ message: "foo", level }); const message = await getConsoleMessage(listenerId); is(message.level, level, "Received expected log level"); } // Clear the console to avoid side effects with other tests in this file. await clearConsole(); }); add_task(async function test_stacktrace() { const script = ` function foo() { throw new Error("cheese"); } function bar() { foo(); } bar(); `; const listenerId = await listenToConsoleMessage("error"); await createScriptNode(script); const { message, level, stacktrace } = await getConsoleMessage(listenerId); is(level, "error", "Received expected log level"); is(message, "Error: cheese", "Received expected log message"); ok(Array.isArray(stacktrace), "frames is of expected type Array"); Assert.greaterOrEqual(stacktrace.length, 4, "Got at least 4 stack frames"); // First 3 stack frames are from the injected script and one more frame comes // from head.js (chrome scope) where we inject the script. checkStackFrame(stacktrace[0], "about:blank", "foo", 2, 28); checkStackFrame(stacktrace[1], "about:blank", "bar", 3, 22); checkStackFrame(stacktrace[2], "about:blank", "", 4, 5); checkStackFrame( stacktrace[3], "chrome://mochitests/content/browser/remote/shared/listeners/test/browser/head.js", "", 34, 29 ); // Clear the console to avoid side effects with other tests in this file. await clearConsole(); }); function logConsoleMessage(options = {}) { info(`Log console message ${options.message}`); return SpecialPowers.spawn(gBrowser.selectedBrowser, [options], _options => { const { level = "error" } = _options; const levelToFlags = { error: Ci.nsIScriptError.errorFlag, info: Ci.nsIScriptError.infoFlag, warn: Ci.nsIScriptError.warningFlag, }; const scriptError = Cc["@mozilla.org/scripterror;1"].createInstance( Ci.nsIScriptError ); scriptError.initWithWindowID( _options.message, _options.sourceName || "sourceName", null, _options.lineNumber || 0, _options.columnNumber || 0, levelToFlags[level], _options.category || "javascript", content.windowGlobalChild.innerWindowId ); Services.console.logMessage(scriptError); }); } function listenToConsoleMessage(level) { info("Listen to a console message in content"); return SpecialPowers.spawn( gBrowser.selectedBrowser, [level], async _level => { const innerWindowId = content.windowGlobalChild.innerWindowId; const { ConsoleListener } = ChromeUtils.importESModule( "chrome://remote/content/shared/listeners/ConsoleListener.sys.mjs" ); const consoleListener = new ConsoleListener(innerWindowId); const onMessage = consoleListener.once(_level); consoleListener.startListening(); const listenerId = Math.random(); content[listenerId] = { consoleListener, onMessage }; return listenerId; } ); } function getConsoleMessage(listenerId) { info("Retrieve the message event captured for listener: " + listenerId); return SpecialPowers.spawn( gBrowser.selectedBrowser, [listenerId], async _listenerId => { const { consoleListener, onMessage } = content[_listenerId]; const message = await onMessage; consoleListener.destroy(); return message; } ); } function checkStackFrame( frame, filename, functionName, lineNumber, columnNumber ) { is(frame.filename, filename, "Received expected filename for frame"); is( frame.functionName, functionName, "Received expected function name for frame" ); is(frame.lineNumber, lineNumber, "Received expected line for frame"); is(frame.columnNumber, columnNumber, "Received expected column for frame"); }