diff --git a/packages/happy-dom/src/console/VirtualConsoleLogLevelEnum.ts b/packages/happy-dom/src/console/VirtualConsoleLogLevelEnum.ts index 2244fffa5..9a692d1be 100644 --- a/packages/happy-dom/src/console/VirtualConsoleLogLevelEnum.ts +++ b/packages/happy-dom/src/console/VirtualConsoleLogLevelEnum.ts @@ -4,9 +4,9 @@ * @see https://console.spec.whatwg.org/#loglevel-severity */ enum VirtualConsoleLogLevelEnum { - error = 0, - warn = 1, - info = 2, - log = 3 + log = 0, + info = 1, + warn = 2, + error = 3 } export default VirtualConsoleLogLevelEnum; diff --git a/packages/happy-dom/src/console/VirtualConsoleUtility.ts b/packages/happy-dom/src/console/VirtualConsoleUtility.ts index db03d551c..b76a56d17 100644 --- a/packages/happy-dom/src/console/VirtualConsoleUtility.ts +++ b/packages/happy-dom/src/console/VirtualConsoleUtility.ts @@ -11,14 +11,14 @@ export default class VirtualConsoleUtility { public static stringifyMessage(message: Array): string { let output = ''; for (const part of message) { - if (typeof part === 'object') { + if (typeof part === 'object' && (part === null || part.constructor.name === 'Object')) { try { output += JSON.stringify(part, null, 3); } catch (error) { output += '["Failed stringify object in log entry."]'; } } else { - output += part; + output += String(part); } } return output; diff --git a/packages/happy-dom/src/window/WindowErrorUtility.ts b/packages/happy-dom/src/window/WindowErrorUtility.ts index fabe0d273..5823a4553 100644 --- a/packages/happy-dom/src/window/WindowErrorUtility.ts +++ b/packages/happy-dom/src/window/WindowErrorUtility.ts @@ -56,10 +56,12 @@ export default class WindowErrorUtility { */ public static dispatchError(elementOrWindow: IWindow | IElement, error: Error): void { if ((elementOrWindow).console) { - (elementOrWindow).console.error(error); + (elementOrWindow).console.error(error.message + '\n' + error.stack); elementOrWindow.dispatchEvent(new ErrorEvent('error', { message: error.message, error })); } else { - (elementOrWindow).ownerDocument.defaultView.console.error(error); + (elementOrWindow).ownerDocument.defaultView.console.error( + error.message + '\n' + error.stack + ); (elementOrWindow).dispatchEvent( new ErrorEvent('error', { message: error.message, error }) ); diff --git a/packages/uncaught-exception-observer/src/UncaughtExceptionObserver.ts b/packages/uncaught-exception-observer/src/UncaughtExceptionObserver.ts index 5be0ad681..aca382582 100644 --- a/packages/uncaught-exception-observer/src/UncaughtExceptionObserver.ts +++ b/packages/uncaught-exception-observer/src/UncaughtExceptionObserver.ts @@ -34,17 +34,15 @@ export default class UncaughtExceptionObserver { return; } - if ( - error instanceof this.window.Error && - error.stack?.includes('at main (eval') && - error.stack?.includes('/happy-dom/') - ) { - this.window.console.error(error); + if (error instanceof this.window.Error && error.stack?.includes('/happy-dom/')) { + this.window.console.error(error.message + '\n' + error.stack); this.window.dispatchEvent(new ErrorEvent('error', { error, message: error.message })); } else if ( process.listenerCount('uncaughtException') === (this.constructor).listenerCount ) { + // eslint-disable-next-line no-console + console.error(error.message + '\n' + error.stack); // Exit if there are no other listeners handling the error. process.exit(1); } @@ -53,17 +51,15 @@ export default class UncaughtExceptionObserver { // The "uncaughtException" event is not always triggered for unhandled rejections. // Therefore we want to use the "unhandledRejection" event as well. this.uncaughtRejectionListener = (error: Error) => { - if ( - error instanceof this.window.Error && - error.stack?.includes('at main (eval') && - error.stack?.includes('/happy-dom/') - ) { - this.window.console.error(error); + if (error instanceof this.window.Error && error.stack?.includes('/happy-dom/')) { + this.window.console.error(error.message + '\n' + error.stack); this.window.dispatchEvent(new ErrorEvent('error', { error, message: error.message })); } else if ( process.listenerCount('unhandledRejection') === (this.constructor).listenerCount ) { + // eslint-disable-next-line no-console + console.error(error.message + '\n' + error.stack); // Exit if there are no other listeners handling the error. process.exit(1); } @@ -77,6 +73,10 @@ export default class UncaughtExceptionObserver { * Disconnects observer. */ public disconnect(): void { + if (!this.window) { + return; + } + (this.constructor).listenerCount--; process.off('uncaughtException', this.uncaughtExceptionListener); diff --git a/packages/uncaught-exception-observer/test/UncaughtExceptionObserver.test.ts b/packages/uncaught-exception-observer/test/UncaughtExceptionObserver.test.ts index ff47e6cf8..eb3bbb647 100644 --- a/packages/uncaught-exception-observer/test/UncaughtExceptionObserver.test.ts +++ b/packages/uncaught-exception-observer/test/UncaughtExceptionObserver.test.ts @@ -55,7 +55,7 @@ async function itObservesUncaughtExceptions(): Promise { window.addEventListener('error', (event) => (errorEvent = event)); - window['customSetTimeout'] = setTimeout; + window['customSetTimeout'] = setTimeout.bind(globalThis); document.write(`