Skip to content

Commit 649f37f

Browse files
authored
fix(pageerror): report correct error message and stack (#1862)
The error stack matches the browser format.
1 parent 4d8c057 commit 649f37f

File tree

6 files changed

+40
-16
lines changed

6 files changed

+40
-16
lines changed

src/chromium/crProtocolHelper.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,21 @@ export function toConsoleMessageLocation(stackTrace: Protocol.Runtime.StackTrace
9191
}
9292

9393
export function exceptionToError(exceptionDetails: Protocol.Runtime.ExceptionDetails): Error {
94-
const message = getExceptionMessage(exceptionDetails);
94+
const messageWithStack = getExceptionMessage(exceptionDetails);
95+
const lines = messageWithStack.split('\n');
96+
const firstStackTraceLine = lines.findIndex(line => line.startsWith(' at'));
97+
let message = '';
98+
let stack = '';
99+
if (firstStackTraceLine === -1) {
100+
message = messageWithStack;
101+
} else {
102+
message = lines.slice(0, firstStackTraceLine).join('\n');
103+
stack = messageWithStack;
104+
}
105+
const match = message.match(/^[a-zA-Z0-0_]*Error: (.*)$/);
106+
if (match)
107+
message = match[1];
95108
const err = new Error(message);
96-
// Don't report clientside error with a node stack attached
97-
err.stack = 'Error: ' + err.message; // Stack is supposed to contain error message as the first line.
109+
err.stack = stack;
98110
return err;
99111
}

src/firefox/ffPage.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,8 @@ export class FFPage implements PageDelegate {
184184
}
185185

186186
_onUncaughtError(params: Protocol.Page.uncaughtErrorPayload) {
187-
const error = new Error(params.message);
187+
const message = params.message.startsWith('Error: ') ? params.message.substring(7) : params.message;
188+
const error = new Error(message);
188189
error.stack = params.stack;
189190
this._page.emit(Events.Page.PageError, error);
190191
}

src/helper.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,16 +149,13 @@ class Helper {
149149
Helper.removeEventListeners([listener]);
150150
clearTimeout(eventTimeout);
151151
}
152-
const result = await Promise.race([promise, abortPromise]).then(r => {
152+
return await Promise.race([promise, abortPromise]).then(r => {
153153
cleanup();
154154
return r;
155155
}, e => {
156156
cleanup();
157157
throw e;
158158
});
159-
if (result instanceof Error)
160-
throw result;
161-
return result;
162159
}
163160

164161
static async waitWithTimeout<T>(promise: Promise<T>, taskName: string, timeout: number): Promise<T> {

src/webkit/wkPage.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,15 @@ export class WKPage implements PageDelegate {
454454
return;
455455
}
456456
if (level === 'error' && source === 'javascript') {
457-
const error = new Error(text);
458-
error.stack = 'Error: ' + error.message; // Nullify stack. Stack is supposed to contain error message as the first line.
457+
const message = text.startsWith('Error: ') ? text.substring(7) : text;
458+
const error = new Error(message);
459+
if (event.message.stackTrace) {
460+
error.stack = event.message.stackTrace.map(callFrame => {
461+
return `${callFrame.functionName}@${callFrame.url}:${callFrame.lineNumber}:${callFrame.columnNumber}`;
462+
}).join('\n');
463+
} else {
464+
error.stack = '';
465+
}
459466
this._page.emit(Events.Page.PageError, error);
460467
return;
461468
}

test/assets/error.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
}
1212

1313
function c() {
14-
throw new Error('Fancy error!');
14+
window.e = new Error('Fancy error!');
15+
throw window.e;
1516
}
17+
//# sourceURL=myscript.js
1618
</script>

test/page.spec.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -493,13 +493,18 @@ describe('Page.exposeFunction', function() {
493493

494494
describe('Page.Events.PageError', function() {
495495
it('should fire', async({page, server}) => {
496-
let error = null;
497-
page.once('pageerror', e => error = e);
498-
await Promise.all([
496+
const [error] = await Promise.all([
497+
page.waitForEvent('pageerror'),
499498
page.goto(server.PREFIX + '/error.html'),
500-
new Promise(f => page.on('pageerror', f))
501499
]);
502-
expect(error.message).toContain('Fancy');
500+
expect(error.name).toBe('Error');
501+
expect(error.message).toBe('Fancy error!');
502+
let stack = await page.evaluate(() => window.e.stack);
503+
// Note that WebKit does not use sourceURL for some reason and reports the stack of the 'throw' statement
504+
// instead of the Error constructor call.
505+
if (WEBKIT)
506+
stack = stack.replace('14:25', '15:19');
507+
expect(error.stack).toBe(stack);
503508
});
504509
});
505510

0 commit comments

Comments
 (0)