diff --git a/src/chromium/crProtocolHelper.ts b/src/chromium/crProtocolHelper.ts index bcc7b3c948..bbcf8eaec3 100644 --- a/src/chromium/crProtocolHelper.ts +++ b/src/chromium/crProtocolHelper.ts @@ -91,9 +91,21 @@ export function toConsoleMessageLocation(stackTrace: Protocol.Runtime.StackTrace } export function exceptionToError(exceptionDetails: Protocol.Runtime.ExceptionDetails): Error { - const message = getExceptionMessage(exceptionDetails); + const messageWithStack = getExceptionMessage(exceptionDetails); + const lines = messageWithStack.split('\n'); + const firstStackTraceLine = lines.findIndex(line => line.startsWith(' at')); + let message = ''; + let stack = ''; + if (firstStackTraceLine === -1) { + message = messageWithStack; + } else { + message = lines.slice(0, firstStackTraceLine).join('\n'); + stack = messageWithStack; + } + const match = message.match(/^[a-zA-Z0-0_]*Error: (.*)$/); + if (match) + message = match[1]; const err = new Error(message); - // Don't report clientside error with a node stack attached - err.stack = 'Error: ' + err.message; // Stack is supposed to contain error message as the first line. + err.stack = stack; return err; } diff --git a/src/firefox/ffPage.ts b/src/firefox/ffPage.ts index 7245912a3c..115cf85f74 100644 --- a/src/firefox/ffPage.ts +++ b/src/firefox/ffPage.ts @@ -184,7 +184,8 @@ export class FFPage implements PageDelegate { } _onUncaughtError(params: Protocol.Page.uncaughtErrorPayload) { - const error = new Error(params.message); + const message = params.message.startsWith('Error: ') ? params.message.substring(7) : params.message; + const error = new Error(message); error.stack = params.stack; this._page.emit(Events.Page.PageError, error); } diff --git a/src/helper.ts b/src/helper.ts index 08d6ceab9d..fac74aaac8 100644 --- a/src/helper.ts +++ b/src/helper.ts @@ -149,16 +149,13 @@ class Helper { Helper.removeEventListeners([listener]); clearTimeout(eventTimeout); } - const result = await Promise.race([promise, abortPromise]).then(r => { + return await Promise.race([promise, abortPromise]).then(r => { cleanup(); return r; }, e => { cleanup(); throw e; }); - if (result instanceof Error) - throw result; - return result; } static async waitWithTimeout(promise: Promise, taskName: string, timeout: number): Promise { diff --git a/src/webkit/wkPage.ts b/src/webkit/wkPage.ts index 5961ef8152..efee111bce 100644 --- a/src/webkit/wkPage.ts +++ b/src/webkit/wkPage.ts @@ -454,8 +454,15 @@ export class WKPage implements PageDelegate { return; } if (level === 'error' && source === 'javascript') { - const error = new Error(text); - error.stack = 'Error: ' + error.message; // Nullify stack. Stack is supposed to contain error message as the first line. + const message = text.startsWith('Error: ') ? text.substring(7) : text; + const error = new Error(message); + if (event.message.stackTrace) { + error.stack = event.message.stackTrace.map(callFrame => { + return `${callFrame.functionName}@${callFrame.url}:${callFrame.lineNumber}:${callFrame.columnNumber}`; + }).join('\n'); + } else { + error.stack = ''; + } this._page.emit(Events.Page.PageError, error); return; } diff --git a/test/assets/error.html b/test/assets/error.html index 100c1d2dc4..26978c466b 100644 --- a/test/assets/error.html +++ b/test/assets/error.html @@ -11,6 +11,8 @@ function b() { } function c() { - throw new Error('Fancy error!'); + window.e = new Error('Fancy error!'); + throw window.e; } +//# sourceURL=myscript.js diff --git a/test/page.spec.js b/test/page.spec.js index 9c2e858aca..4b644d9c5e 100644 --- a/test/page.spec.js +++ b/test/page.spec.js @@ -493,13 +493,18 @@ describe('Page.exposeFunction', function() { describe('Page.Events.PageError', function() { it('should fire', async({page, server}) => { - let error = null; - page.once('pageerror', e => error = e); - await Promise.all([ + const [error] = await Promise.all([ + page.waitForEvent('pageerror'), page.goto(server.PREFIX + '/error.html'), - new Promise(f => page.on('pageerror', f)) ]); - expect(error.message).toContain('Fancy'); + expect(error.name).toBe('Error'); + expect(error.message).toBe('Fancy error!'); + let stack = await page.evaluate(() => window.e.stack); + // Note that WebKit does not use sourceURL for some reason and reports the stack of the 'throw' statement + // instead of the Error constructor call. + if (WEBKIT) + stack = stack.replace('14:25', '15:19'); + expect(error.stack).toBe(stack); }); });