From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- ..._console_service_callFunctionAndLogException.js | 265 +++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 xpcom/tests/unit/test_console_service_callFunctionAndLogException.js (limited to 'xpcom/tests/unit/test_console_service_callFunctionAndLogException.js') diff --git a/xpcom/tests/unit/test_console_service_callFunctionAndLogException.js b/xpcom/tests/unit/test_console_service_callFunctionAndLogException.js new file mode 100644 index 0000000000..eeb9ceb425 --- /dev/null +++ b/xpcom/tests/unit/test_console_service_callFunctionAndLogException.js @@ -0,0 +1,265 @@ +let lastMessage; +const consoleListener = { + observe(message) { + dump(" >> new message: " + message.errorMessage + "\n"); + lastMessage = message; + }, +}; +Services.console.registerListener(consoleListener); + +// The Console Service notifies its listener after one event loop cycle. +// So wait for one tick after each action dispatching a message/error to the service. +function waitForATick() { + return new Promise(resolve => Services.tm.dispatchToMainThread(resolve)); +} + +add_task(async function customScriptError() { + const scriptError = Cc["@mozilla.org/scripterror;1"].createInstance( + Ci.nsIScriptError + ); + scriptError.init( + "foo", + "file.js", + null, + 1, + 2, + Ci.nsIScriptError.warningFlag, + "some javascript" + ); + Services.console.logMessage(scriptError); + + await waitForATick(); + + Assert.equal( + lastMessage, + scriptError, + "We receive the exact same nsIScriptError object" + ); + + Assert.equal(lastMessage.errorMessage, "foo"); + Assert.equal(lastMessage.sourceName, "file.js"); + Assert.equal(lastMessage.lineNumber, 1); + Assert.equal(lastMessage.columnNumber, 2); + Assert.equal(lastMessage.flags, Ci.nsIScriptError.warningFlag); + Assert.equal(lastMessage.category, "some javascript"); + + Assert.equal( + lastMessage.stack, + undefined, + "Custom nsIScriptError object created from JS can't convey any stack" + ); +}); + +add_task(async function callFunctionAndLogExceptionWithChromeGlobal() { + try { + Services.console.callFunctionAndLogException(globalThis, function () { + throw new Error("custom exception"); + }); + Assert.fail("callFunctionAndLogException should throw"); + } catch (e) { + Assert.equal( + e.name, + "NS_ERROR_XPC_JAVASCRIPT_ERROR", + "callFunctionAndLogException thrown" + ); + } + + await waitForATick(); + + Assert.ok(!!lastMessage, "Got the message"); + Assert.ok( + lastMessage instanceof Ci.nsIScriptError, + "This is a nsIScriptError" + ); + + Assert.equal(lastMessage.errorMessage, "Error: custom exception"); + Assert.equal(lastMessage.sourceName, _TEST_FILE); + Assert.equal(lastMessage.lineNumber, 56); + Assert.equal(lastMessage.columnNumber, 13); + Assert.equal(lastMessage.flags, Ci.nsIScriptError.errorFlag); + Assert.equal(lastMessage.category, "chrome javascript"); + Assert.ok(lastMessage.stack, "It has a stack"); + Assert.equal(lastMessage.stack.source, _TEST_FILE); + Assert.equal(lastMessage.stack.line, 56); + Assert.equal(lastMessage.stack.column, 13); + Assert.ok(!!lastMessage.stack.parent, "stack has a parent frame"); + Assert.equal( + lastMessage.innerWindowID, + 0, + "The message isn't bound to any WindowGlobal" + ); +}); + +add_task(async function callFunctionAndLogExceptionWithContentGlobal() { + const window = createContentWindow(); + try { + Services.console.callFunctionAndLogException(window, function () { + throw new Error("another custom exception"); + }); + Assert.fail("callFunctionAndLogException should throw"); + } catch (e) { + Assert.equal( + e.name, + "NS_ERROR_XPC_JAVASCRIPT_ERROR", + "callFunctionAndLogException thrown" + ); + } + + await waitForATick(); + + Assert.ok(!!lastMessage, "Got the message"); + Assert.ok( + lastMessage instanceof Ci.nsIScriptError, + "This is a nsIScriptError" + ); + + Assert.equal(lastMessage.errorMessage, "Error: another custom exception"); + Assert.equal(lastMessage.sourceName, _TEST_FILE); + Assert.equal(lastMessage.lineNumber, 97); + Assert.equal(lastMessage.columnNumber, 13); + Assert.equal(lastMessage.flags, Ci.nsIScriptError.errorFlag); + Assert.equal(lastMessage.category, "content javascript"); + Assert.ok(lastMessage.stack, "It has a stack"); + Assert.equal(lastMessage.stack.source, _TEST_FILE); + Assert.equal(lastMessage.stack.line, 97); + Assert.equal(lastMessage.stack.column, 13); + Assert.ok(!!lastMessage.stack.parent, "stack has a parent frame"); + Assert.ok( + !!window.windowGlobalChild.innerWindowId, + "The window has a innerWindowId" + ); + Assert.equal( + lastMessage.innerWindowID, + window.windowGlobalChild.innerWindowId, + "The message is bound to the content window" + ); +}); + +add_task(async function callFunctionAndLogExceptionForContentScriptSandboxes() { + const { sandbox, window } = createContentScriptSandbox(); + Cu.evalInSandbox( + `function foo() { throw new Error("sandbox exception"); }`, + sandbox, + null, + "sandbox-file.js", + 1, + 0 + ); + try { + Services.console.callFunctionAndLogException(window, sandbox.foo); + Assert.fail("callFunctionAndLogException should throw"); + } catch (e) { + Assert.equal( + e.name, + "NS_ERROR_XPC_JAVASCRIPT_ERROR", + "callFunctionAndLogException thrown" + ); + } + + await waitForATick(); + + Assert.ok(!!lastMessage, "Got the message"); + // Note that it is important to "instanceof" in order to expose the nsIScriptError attributes. + Assert.ok( + lastMessage instanceof Ci.nsIScriptError, + "This is a nsIScriptError" + ); + + Assert.equal(lastMessage.errorMessage, "Error: sandbox exception"); + Assert.equal(lastMessage.sourceName, "sandbox-file.js"); + Assert.equal(lastMessage.lineNumber, 1); + Assert.equal(lastMessage.columnNumber, 24); + Assert.equal(lastMessage.flags, Ci.nsIScriptError.errorFlag); + Assert.equal(lastMessage.category, "content javascript"); + Assert.ok(lastMessage.stack, "It has a stack"); + Assert.equal(lastMessage.stack.source, "sandbox-file.js"); + Assert.equal(lastMessage.stack.line, 1); + Assert.equal(lastMessage.stack.column, 24); + Assert.ok(!!lastMessage.stack.parent, "stack has a parent frame"); + Assert.ok( + !!window.windowGlobalChild.innerWindowId, + "The sandbox's prototype is a window and has a innerWindowId" + ); + Assert.equal( + lastMessage.innerWindowID, + window.windowGlobalChild.innerWindowId, + "The message is bound to the sandbox's prototype WindowGlobal" + ); +}); + +add_task( + async function callFunctionAndLogExceptionForContentScriptSandboxesWrappedInChrome() { + const { sandbox, window } = createContentScriptSandbox(); + Cu.evalInSandbox( + `function foo() { throw new Error("sandbox exception"); }`, + sandbox, + null, + "sandbox-file.js", + 1, + 0 + ); + try { + Services.console.callFunctionAndLogException(window, function () { + sandbox.foo(); + }); + Assert.fail("callFunctionAndLogException should throw"); + } catch (e) { + Assert.equal( + e.name, + "NS_ERROR_XPC_JAVASCRIPT_ERROR", + "callFunctionAndLogException thrown" + ); + } + + await waitForATick(); + + Assert.ok(!!lastMessage, "Got the message"); + // Note that it is important to "instanceof" in order to expose the nsIScriptError attributes. + Assert.ok( + lastMessage instanceof Ci.nsIScriptError, + "This is a nsIScriptError" + ); + + Assert.ok( + !!window.windowGlobalChild.innerWindowId, + "The sandbox's prototype is a window and has a innerWindowId" + ); + Assert.equal( + lastMessage.innerWindowID, + window.windowGlobalChild.innerWindowId, + "The message is bound to the sandbox's prototype WindowGlobal" + ); + } +); + +add_task(function teardown() { + Services.console.unregisterListener(consoleListener); +}); + +// We are in xpcshell, so we can't have a real DOM Window as in Firefox +// but let's try to have a fake one. +function createContentWindow() { + const principal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com/" + ); + + const webnav = Services.appShell.createWindowlessBrowser(false); + + webnav.docShell.createAboutBlankContentViewer(principal, principal); + + return webnav.document.defaultView; +} + +// Create a Sandbox as in WebExtension content scripts +function createContentScriptSandbox() { + const window = createContentWindow(); + // The sandboxPrototype is the key here in order to + // make xpc::SandboxWindowOrNull ignore the sandbox + // and instead retrieve its prototype and link the error message + // to the window instead of the sandbox. + return { + sandbox: Cu.Sandbox(window, { sandboxPrototype: window }), + window, + }; +} -- cgit v1.2.3