diff --git a/package-lock.json b/package-lock.json index 010c91e24..985ef6684 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12828,7 +12828,8 @@ "version": "14.4.3", "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", - "dev": true + "dev": true, + "requires": {} }, "@types/aria-query": { "version": "5.0.1", @@ -13482,7 +13483,8 @@ "version": "6.6.2", "resolved": "https://registry.npmjs.org/@webref/css/-/css-6.6.2.tgz", "integrity": "sha512-BtX/sMtWl6eJfspxTQfmINpSEP/BvwQz1OL1FEiPffRDRZVEP9s4Nf/pyf16o9j/1SEj1LmevUCHABzSsktDvQ==", - "dev": true + "dev": true, + "requires": {} }, "accepts": { "version": "1.3.8", @@ -13504,7 +13506,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "acorn-walk": { "version": "8.2.0", @@ -14968,7 +14971,8 @@ "version": "8.5.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true + "dev": true, + "requires": {} }, "eslint-import-resolver-node": { "version": "0.3.7", @@ -15121,7 +15125,8 @@ "version": "0.0.7", "resolved": "https://registry.npmjs.org/eslint-plugin-turbo/-/eslint-plugin-turbo-0.0.7.tgz", "integrity": "sha512-iajOH8eD4jha3duztGVBD1BEmvNrQBaA/y3HFHf91vMDRYRwH7BpHSDFtxydDpk5ghlhRxG299SFxz7D6z4MBQ==", - "dev": true + "dev": true, + "requires": {} }, "eslint-scope": { "version": "5.1.1", @@ -17051,7 +17056,8 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true + "dev": true, + "requires": {} }, "jest-regex-util": { "version": "29.4.3", diff --git a/packages/happy-dom/src/event/EventTarget.ts b/packages/happy-dom/src/event/EventTarget.ts index 7a57a1f62..608f62928 100644 --- a/packages/happy-dom/src/event/EventTarget.ts +++ b/packages/happy-dom/src/event/EventTarget.ts @@ -140,8 +140,12 @@ export default abstract class EventTarget implements IEventTarget { if (typeof this[onEventName] === 'function') { // We can end up in a never ending loop if the listener for the error event on Window also throws an error. - if (window && (this !== window || event.type !== 'error')) { - WindowErrorUtility.captureErrorSync(window, this[onEventName].bind(this, event)); + if ( + window && + (this !== window || event.type !== 'error') && + !window.happyDOM.settings.disableErrorCapturing + ) { + WindowErrorUtility.captureError(window, this[onEventName].bind(this, event)); } else { this[onEventName].call(this, event); } @@ -169,14 +173,18 @@ export default abstract class EventTarget implements IEventTarget { } // We can end up in a never ending loop if the listener for the error event on Window also throws an error. - if (window && (this !== window || event.type !== 'error')) { + if ( + window && + (this !== window || event.type !== 'error') && + !window.happyDOM.settings.disableErrorCapturing + ) { if ((listener).handleEvent) { - WindowErrorUtility.captureErrorSync( + WindowErrorUtility.captureError( window, (listener).handleEvent.bind(this, event) ); } else { - WindowErrorUtility.captureErrorSync( + WindowErrorUtility.captureError( window, (<(event: Event) => void>listener).bind(this, event) ); diff --git a/packages/happy-dom/src/nodes/html-link-element/HTMLLinkElementUtility.ts b/packages/happy-dom/src/nodes/html-link-element/HTMLLinkElementUtility.ts index 808122390..687635ab7 100644 --- a/packages/happy-dom/src/nodes/html-link-element/HTMLLinkElementUtility.ts +++ b/packages/happy-dom/src/nodes/html-link-element/HTMLLinkElementUtility.ts @@ -24,32 +24,41 @@ export default class HTMLLinkElementUtility { if (href !== null && rel && rel.toLowerCase() === 'stylesheet' && element.isConnected) { if (element.ownerDocument.defaultView.happyDOM.settings.disableCSSFileLoading) { - WindowErrorUtility.dispatchError( - element, - new DOMException( - `Failed to load external stylesheet "${href}". CSS file loading is disabled.`, - DOMExceptionNameEnum.notSupportedError - ) + const error = new DOMException( + `Failed to load external stylesheet "${href}". CSS file loading is disabled.`, + DOMExceptionNameEnum.notSupportedError ); - + WindowErrorUtility.dispatchError(element, error); + if (element.ownerDocument.defaultView.happyDOM.settings.disableErrorCapturing) { + throw error; + } return; } (element.ownerDocument)._readyStateManager.startTask(); - const code: string | null = await WindowErrorUtility.captureErrorAsync( - element, - async () => await ResourceFetch.fetch(element.ownerDocument, href) - ); + let code: string | null = null; + let error: Error | null = null; + + try { + code = await ResourceFetch.fetch(element.ownerDocument, href); + } catch (e) { + error = e; + } - if (code) { + (element.ownerDocument)._readyStateManager.endTask(); + + if (error) { + WindowErrorUtility.dispatchError(element, error); + if (element.ownerDocument.defaultView.happyDOM.settings.disableErrorCapturing) { + throw error; + } + } else { const styleSheet = new CSSStyleSheet(); styleSheet.replaceSync(code); (element.sheet) = styleSheet; element.dispatchEvent(new Event('load')); } - - (element.ownerDocument)._readyStateManager.endTask(); } } } diff --git a/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElement.ts b/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElement.ts index 15601c8dc..b505886cb 100644 --- a/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElement.ts +++ b/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElement.ts @@ -189,9 +189,13 @@ export default class HTMLScriptElement extends HTMLElement implements IHTMLScrip type === 'application/x-javascript' || type.startsWith('text/javascript')) ) { - WindowErrorUtility.captureErrorSync(this.ownerDocument.defaultView, () => - this.ownerDocument.defaultView.eval(textContent) - ); + if (this.ownerDocument.defaultView.happyDOM.settings.disableErrorCapturing) { + this.ownerDocument.defaultView.eval(textContent); + } else { + WindowErrorUtility.captureError(this.ownerDocument.defaultView, () => + this.ownerDocument.defaultView.eval(textContent) + ); + } } } } diff --git a/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElementUtility.ts b/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElementUtility.ts index fe4a5e0b6..d0e813b4c 100644 --- a/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElementUtility.ts +++ b/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElementUtility.ts @@ -25,40 +25,69 @@ export default class HTMLScriptElementUtility { element.ownerDocument.defaultView.happyDOM.settings.disableJavaScriptFileLoading || element.ownerDocument.defaultView.happyDOM.settings.disableJavaScriptEvaluation ) { - WindowErrorUtility.dispatchError( - element, - new DOMException( - `Failed to load external script "${src}". JavaScript file loading is disabled.`, - DOMExceptionNameEnum.notSupportedError - ) + const error = new DOMException( + `Failed to load external script "${src}". JavaScript file loading is disabled.`, + DOMExceptionNameEnum.notSupportedError ); + WindowErrorUtility.dispatchError(element, error); + if (element.ownerDocument.defaultView.happyDOM.settings.disableErrorCapturing) { + throw error; + } return; } if (async) { (element.ownerDocument)._readyStateManager.startTask(); - const code = await WindowErrorUtility.captureErrorAsync( - element, - async () => await ResourceFetch.fetch(element.ownerDocument, src) - ); + let code: string | null = null; + let error: Error | null = null; - if (code) { - WindowErrorUtility.captureErrorSync(element.ownerDocument.defaultView, () => - element.ownerDocument.defaultView.eval(code) - ); - element.dispatchEvent(new Event('load')); + try { + code = await ResourceFetch.fetch(element.ownerDocument, src); + } catch (e) { + error = e; } + (element.ownerDocument)._readyStateManager.endTask(); + + if (error) { + WindowErrorUtility.dispatchError(element, error); + if (element.ownerDocument.defaultView.happyDOM.settings.disableErrorCapturing) { + throw error; + } + } else { + if (element.ownerDocument.defaultView.happyDOM.settings.disableErrorCapturing) { + element.ownerDocument.defaultView.eval(code); + } else { + WindowErrorUtility.captureError(element.ownerDocument.defaultView, () => + element.ownerDocument.defaultView.eval(code) + ); + } + element.dispatchEvent(new Event('load')); + } } else { - const code = WindowErrorUtility.captureErrorSync(element, () => - ResourceFetch.fetchSync(element.ownerDocument, src) - ); + let code: string | null = null; + let error: Error | null = null; + + try { + code = ResourceFetch.fetchSync(element.ownerDocument, src); + } catch (e) { + error = e; + } - if (code) { - WindowErrorUtility.captureErrorSync(element.ownerDocument.defaultView, () => - element.ownerDocument.defaultView.eval(code) - ); + if (error) { + WindowErrorUtility.dispatchError(element, error); + if (element.ownerDocument.defaultView.happyDOM.settings.disableErrorCapturing) { + throw error; + } + } else { + if (element.ownerDocument.defaultView.happyDOM.settings.disableErrorCapturing) { + element.ownerDocument.defaultView.eval(code); + } else { + WindowErrorUtility.captureError(element.ownerDocument.defaultView, () => + element.ownerDocument.defaultView.eval(code) + ); + } element.dispatchEvent(new Event('load')); } } diff --git a/packages/happy-dom/src/window/IHappyDOMOptions.ts b/packages/happy-dom/src/window/IHappyDOMOptions.ts index b005c4db2..92ebb25bd 100644 --- a/packages/happy-dom/src/window/IHappyDOMOptions.ts +++ b/packages/happy-dom/src/window/IHappyDOMOptions.ts @@ -12,6 +12,7 @@ export default interface IHappyDOMOptions { disableCSSFileLoading?: boolean; disableIframePageLoading?: boolean; disableComputedStyleRendering?: boolean; + disableErrorCapturing?: boolean; enableFileSystemHttpRequests?: boolean; navigator?: { userAgent?: string; diff --git a/packages/happy-dom/src/window/IHappyDOMSettings.ts b/packages/happy-dom/src/window/IHappyDOMSettings.ts index 3212c13b5..1b2afeb00 100644 --- a/packages/happy-dom/src/window/IHappyDOMSettings.ts +++ b/packages/happy-dom/src/window/IHappyDOMSettings.ts @@ -7,6 +7,7 @@ export default interface IHappyDOMSettings { disableCSSFileLoading: boolean; disableIframePageLoading: boolean; disableComputedStyleRendering: boolean; + disableErrorCapturing: boolean; enableFileSystemHttpRequests: boolean; navigator: { userAgent: string; diff --git a/packages/happy-dom/src/window/Window.ts b/packages/happy-dom/src/window/Window.ts index 93ea64236..67562cb04 100644 --- a/packages/happy-dom/src/window/Window.ts +++ b/packages/happy-dom/src/window/Window.ts @@ -210,6 +210,7 @@ export default class Window extends EventTarget implements IWindow { disableCSSFileLoading: false, disableIframePageLoading: false, disableComputedStyleRendering: false, + disableErrorCapturing: false, enableFileSystemHttpRequests: false, navigator: { userAgent: `Mozilla/5.0 (X11; ${ @@ -736,7 +737,11 @@ export default class Window extends EventTarget implements IWindow { public setTimeout(callback: Function, delay = 0, ...args: unknown[]): NodeJS.Timeout { const id = this._setTimeout(() => { this.happyDOM.asyncTaskManager.endTimer(id); - WindowErrorUtility.captureErrorSync(this, () => callback(...args)); + if (this.happyDOM.settings.disableErrorCapturing) { + callback(...args); + } else { + WindowErrorUtility.captureError(this, () => callback(...args)); + } }, delay); this.happyDOM.asyncTaskManager.startTimer(id); return id; @@ -762,11 +767,15 @@ export default class Window extends EventTarget implements IWindow { */ public setInterval(callback: Function, delay = 0, ...args: unknown[]): NodeJS.Timeout { const id = this._setInterval(() => { - WindowErrorUtility.captureErrorSync( - this, - () => callback(...args), - () => this.clearInterval(id) - ); + if (this.happyDOM.settings.disableErrorCapturing) { + callback(...args); + } else { + WindowErrorUtility.captureError( + this, + () => callback(...args), + () => this.clearInterval(id) + ); + } }, delay); this.happyDOM.asyncTaskManager.startTimer(id); return id; @@ -811,8 +820,13 @@ export default class Window extends EventTarget implements IWindow { const taskId = this.happyDOM.asyncTaskManager.startTask(() => (isAborted = true)); this._queueMicrotask(() => { if (!isAborted) { - WindowErrorUtility.captureErrorSync(this, <() => unknown>callback); this.happyDOM.asyncTaskManager.endTask(taskId); + + if (this.happyDOM.settings.disableErrorCapturing) { + callback(); + } else { + WindowErrorUtility.captureError(this, <() => unknown>callback); + } } }); } diff --git a/packages/happy-dom/src/window/WindowErrorUtility.ts b/packages/happy-dom/src/window/WindowErrorUtility.ts index b831370d2..7c76b5482 100644 --- a/packages/happy-dom/src/window/WindowErrorUtility.ts +++ b/packages/happy-dom/src/window/WindowErrorUtility.ts @@ -6,32 +6,6 @@ import { IElement } from '../index.js'; * Error utility. */ export default class WindowErrorUtility { - /** - * Calls a function asynchronously wrapped in a try/catch block to capture errors and dispatch error events. - * - * It will also output the errors to the console. - * - * @param elementOrWindow Element or Window. - * @param callback Callback. - * @param [cleanup] Cleanup callback on error. - * @returns Promise. - */ - public static async captureErrorAsync( - elementOrWindow: IWindow | IElement, - callback: () => Promise, - cleanup?: () => void - ): Promise { - try { - return await callback(); - } catch (error) { - this.dispatchError(elementOrWindow, error); - if (cleanup) { - cleanup(); - } - } - return null; - } - /** * Calls a function synchronously wrapped in a try/catch block to capture errors and dispatch error events. * If the callback returns a Promise, it will catch errors from the promise. @@ -43,7 +17,7 @@ export default class WindowErrorUtility { * @param [cleanup] Cleanup callback on error. * @returns Result. */ - public static captureErrorSync( + public static captureError( elementOrWindow: IWindow | IElement, callback: () => T, cleanup?: () => void diff --git a/packages/happy-dom/test/nodes/html-script-element/HTMLScriptElement.test.ts b/packages/happy-dom/test/nodes/html-script-element/HTMLScriptElement.test.ts index eacf6efdd..588c33553 100644 --- a/packages/happy-dom/test/nodes/html-script-element/HTMLScriptElement.test.ts +++ b/packages/happy-dom/test/nodes/html-script-element/HTMLScriptElement.test.ts @@ -485,5 +485,17 @@ describe('HTMLScriptElement', () => { true ); }); + + it('Throws an exception when appending an element that contains invalid Javascript and Window.happyDOM.settings.disableErrorCapturing is set to true.', () => { + const element = document.createElement('script'); + + window.happyDOM.settings.disableErrorCapturing = true; + + element.text = 'globalThis.test = /;'; + + expect(() => { + document.body.appendChild(element); + }).toThrow(new TypeError('Invalid regular expression: missing /')); + }); }); }); diff --git a/packages/happy-dom/test/window/Window.test.ts b/packages/happy-dom/test/window/Window.test.ts index c5d80563e..5a14d1451 100644 --- a/packages/happy-dom/test/window/Window.test.ts +++ b/packages/happy-dom/test/window/Window.test.ts @@ -132,6 +132,7 @@ describe('Window', () => { expect(windowWithOptions.happyDOM.settings.disableJavaScriptFileLoading).toBe(false); expect(windowWithOptions.happyDOM.settings.disableCSSFileLoading).toBe(false); expect(windowWithOptions.happyDOM.settings.disableIframePageLoading).toBe(false); + expect(windowWithOptions.happyDOM.settings.disableErrorCapturing).toBe(false); expect(windowWithOptions.happyDOM.settings.enableFileSystemHttpRequests).toBe(false); expect(windowWithOptions.happyDOM.settings.navigator.userAgent).toBe('test'); expect(windowWithOptions.happyDOM.settings.device.prefersColorScheme).toBe('dark'); @@ -150,6 +151,7 @@ describe('Window', () => { expect(windowWithoutOptions.happyDOM.settings.disableJavaScriptFileLoading).toBe(false); expect(windowWithoutOptions.happyDOM.settings.disableCSSFileLoading).toBe(false); expect(windowWithoutOptions.happyDOM.settings.disableIframePageLoading).toBe(false); + expect(windowWithoutOptions.happyDOM.settings.disableErrorCapturing).toBe(false); expect(windowWithoutOptions.happyDOM.settings.enableFileSystemHttpRequests).toBe(false); expect(windowWithoutOptions.happyDOM.settings.navigator.userAgent).toBe( `Mozilla/5.0 (${GET_NAVIGATOR_PLATFORM()}) AppleWebKit/537.36 (KHTML, like Gecko) HappyDOM/${ @@ -821,11 +823,6 @@ describe('Window', () => { const result = <() => number>window.eval('() => 5'); expect(result()).toBe(5); }); - - it('Captures errors and triggers an error event.', () => { - const result = <() => number>window.eval('() => 5'); - expect(result()).toBe(5); - }); }); describe('setTimeout()', () => { diff --git a/packages/jest-environment/src/index.ts b/packages/jest-environment/src/index.ts index b2e7aa4b3..4f7b8783a 100644 --- a/packages/jest-environment/src/index.ts +++ b/packages/jest-environment/src/index.ts @@ -5,7 +5,7 @@ import * as JestUtil from 'jest-util'; import { ModuleMocker } from 'jest-mock'; import { LegacyFakeTimers, ModernFakeTimers } from '@jest/fake-timers'; import { JestEnvironment, EnvironmentContext } from '@jest/environment'; -import { Window, IWindow, ErrorEvent } from 'happy-dom'; +import { Window, IWindow } from 'happy-dom'; import { Script } from 'vm'; import { Global, Config } from '@jest/types'; @@ -15,10 +15,12 @@ import { Global, Config } from '@jest/types'; export default class HappyDOMEnvironment implements JestEnvironment { public fakeTimers: LegacyFakeTimers = null; public fakeTimersModern: ModernFakeTimers = null; - public window: IWindow = new Window({ console: globalThis.console }); + public window: IWindow = new Window({ + console: globalThis.console, + settings: { disableErrorCapturing: true } + }); public global: Global.Global = (this.window); public moduleMocker: ModuleMocker = new ModuleMocker((this.window)); - private errorEventListener: (event: ErrorEvent) => void | null = null; /** * Constructor. @@ -73,14 +75,6 @@ export default class HappyDOMEnvironment implements JestEnvironment { this.window.happyDOM.setURL('http://localhost/'); } - // Report uncaught errors. - this.errorEventListener = (event: ErrorEvent) => { - if (this.window['_listeners']?.['error']?.length === 0 && event.error !== null) { - process.emit('uncaughtException', event.error); - } - }; - this.window.addEventListener('error', this.errorEventListener); - this.fakeTimers = new LegacyFakeTimers({ config: projectConfig, global: (this.window), @@ -125,11 +119,6 @@ export default class HappyDOMEnvironment implements JestEnvironment { ((this.global)).happyDOM.cancelAsync(); - if (this.errorEventListener) { - this.window.removeEventListener('error', this.errorEventListener); - this.errorEventListener = null; - } - this.global = null; this.moduleMocker = null; this.fakeTimers = null; diff --git a/packages/uncaught-exception-observer/src/UncaughtExceptionObserver.ts b/packages/uncaught-exception-observer/src/UncaughtExceptionObserver.ts index 78ce81533..2e4933054 100644 --- a/packages/uncaught-exception-observer/src/UncaughtExceptionObserver.ts +++ b/packages/uncaught-exception-observer/src/UncaughtExceptionObserver.ts @@ -27,14 +27,17 @@ export default class UncaughtExceptionObserver { (this.constructor).listenerCount++; this.uncaughtExceptionListener = ( - error: Error, + error: unknown, origin: 'uncaughtException' | 'unhandledRejection' ) => { if (origin === 'unhandledRejection') { return; } - if (error instanceof this.window.Error && error.stack?.includes('/happy-dom/')) { + if ( + (error instanceof this.window.Error || error instanceof this.window.DOMException) && + error.stack?.includes('/happy-dom/') + ) { this.window.console.error(error); this.window.dispatchEvent( new this.window.ErrorEvent('error', { error, message: error.message }) @@ -52,8 +55,11 @@ 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('/happy-dom/')) { + this.uncaughtRejectionListener = (error: unknown) => { + if ( + (error instanceof this.window.Error || error instanceof this.window.DOMException) && + error.stack?.includes('/happy-dom/') + ) { this.window.console.error(error); this.window.dispatchEvent( new this.window.ErrorEvent('error', { error, message: error.message }) diff --git a/packages/uncaught-exception-observer/test/UncaughtExceptionObserver.test.ts b/packages/uncaught-exception-observer/test/UncaughtExceptionObserver.test.ts index a361f7e01..a3b42305f 100644 --- a/packages/uncaught-exception-observer/test/UncaughtExceptionObserver.test.ts +++ b/packages/uncaught-exception-observer/test/UncaughtExceptionObserver.test.ts @@ -1,7 +1,7 @@ import { Window, ErrorEvent, IResponse } from 'happy-dom'; import UncaughtExceptionObserver from '../lib/UncaughtExceptionObserver.js'; -async function itObservesUnhandledRejections(): Promise { +async function itObservesUnhandledFetchRejections(): Promise { const window = new Window(); const document = window.document; const observer = new UncaughtExceptionObserver(); @@ -45,6 +45,45 @@ async function itObservesUnhandledRejections(): Promise { } } +async function itObservesUnhandledJavaScriptFetchRejections(): Promise { + const window = new Window(); + const document = window.document; + const observer = new UncaughtExceptionObserver(); + let errorEvent: ErrorEvent | null = null; + + window.happyDOM.settings.disableErrorCapturing = true; + + observer.observe(window); + + window.addEventListener('error', (event) => (errorEvent = event)); + + document.write(` + + `); + + await new Promise((resolve) => setTimeout(resolve, 10)); + + observer.disconnect(); + + if (!(errorEvent instanceof window.ErrorEvent)) { + throw new Error('Error event not dispatched.'); + } + + if ( + errorEvent.error.message !== + 'Fetch to "https://localhost:3000/404.js" failed. Error: connect ECONNREFUSED 127.0.0.1:3000' + ) { + throw new Error('Error message not correct.'); + } + + if ( + errorEvent.message !== + 'Fetch to "https://localhost:3000/404.js" failed. Error: connect ECONNREFUSED 127.0.0.1:3000' + ) { + throw new Error('Error message not correct.'); + } +} + async function itObservesUncaughtExceptions(): Promise { const window = new Window(); const document = window.document; @@ -96,7 +135,8 @@ async function itObservesUncaughtExceptions(): Promise { async function main(): Promise { try { - await itObservesUnhandledRejections(); + await itObservesUnhandledFetchRejections(); + await itObservesUnhandledJavaScriptFetchRejections(); await itObservesUncaughtExceptions(); } catch (error) { // eslint-disable-next-line no-console