豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit ecef712

Browse files
authored
feat: include source-mapped stack trace for uncaught errors (#876)
Note that we replace the existing "pageerror" handler with our new `UncaughtError` handler. The latter has a structured stack trace attached which we can source map via DevTools. This regresses the current functionality slightly, as we lose "pageerror"s for workers and oopif.
1 parent a08f550 commit ecef712

File tree

5 files changed

+53
-18
lines changed

5 files changed

+53
-18
lines changed

src/McpContext.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
UniverseManager,
1515
urlsEqual,
1616
} from './DevtoolsUtils.js';
17-
import type {ListenerMap} from './PageCollector.js';
17+
import type {ListenerMap, UncaughtError} from './PageCollector.js';
1818
import {NetworkCollector, ConsoleCollector} from './PageCollector.js';
1919
import {Locator} from './third_party/index.js';
2020
import type {DevTools} from './third_party/index.js';
@@ -156,14 +156,8 @@ export class McpContext implements Context {
156156
console: event => {
157157
collect(event);
158158
},
159-
pageerror: event => {
160-
if (event instanceof Error) {
161-
collect(event);
162-
} else {
163-
const error = new Error(`${event}`);
164-
error.stack = undefined;
165-
collect(error);
166-
}
159+
uncaughtError: event => {
160+
collect(event);
167161
},
168162
issue: event => {
169163
collect(event);
@@ -245,7 +239,7 @@ export class McpContext implements Context {
245239

246240
getConsoleData(
247241
includePreservedMessages?: boolean,
248-
): Array<ConsoleMessage | Error | DevTools.AggregatedIssue> {
242+
): Array<ConsoleMessage | Error | DevTools.AggregatedIssue | UncaughtError> {
249243
const page = this.getSelectedPage();
250244
return this.#consoleCollector.getData(page, includePreservedMessages);
251245
}
@@ -255,14 +249,14 @@ export class McpContext implements Context {
255249
}
256250

257251
getConsoleMessageStableId(
258-
message: ConsoleMessage | Error | DevTools.AggregatedIssue,
252+
message: ConsoleMessage | Error | DevTools.AggregatedIssue | UncaughtError,
259253
): number {
260254
return this.#consoleCollector.getIdForResource(message);
261255
}
262256

263257
getConsoleMessageById(
264258
id: number,
265-
): ConsoleMessage | Error | DevTools.AggregatedIssue {
259+
): ConsoleMessage | Error | DevTools.AggregatedIssue | UncaughtError {
266260
return this.#consoleCollector.getById(this.getSelectedPage(), id);
267261
}
268262

src/McpResponse.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {IssueFormatter} from './formatters/IssueFormatter.js';
99
import {NetworkFormatter} from './formatters/NetworkFormatter.js';
1010
import {SnapshotFormatter} from './formatters/SnapshotFormatter.js';
1111
import type {McpContext} from './McpContext.js';
12+
import {UncaughtError} from './PageCollector.js';
1213
import {DevTools} from './third_party/index.js';
1314
import type {
1415
ConsoleMessage,
@@ -276,8 +277,8 @@ export class McpResponse implements Response {
276277
this.#attachedConsoleMessageId,
277278
);
278279
const consoleMessageStableId = this.#attachedConsoleMessageId;
279-
if ('args' in message) {
280-
const consoleMessage = message as ConsoleMessage;
280+
if ('args' in message || message instanceof UncaughtError) {
281+
const consoleMessage = message as ConsoleMessage | UncaughtError;
281282
const devTools = context.getDevToolsUniverse();
282283
detailedConsoleMessage = await ConsoleFormatter.from(consoleMessage, {
283284
id: consoleMessageStableId,
@@ -332,8 +333,8 @@ export class McpResponse implements Response {
332333
async (item): Promise<ConsoleFormatter | IssueFormatter | null> => {
333334
const consoleMessageStableId =
334335
context.getConsoleMessageStableId(item);
335-
if ('args' in item) {
336-
const consoleMessage = item as ConsoleMessage;
336+
if ('args' in item || item instanceof UncaughtError) {
337+
const consoleMessage = item as ConsoleMessage | UncaughtError;
337338
const devTools = context.getDevToolsUniverse();
338339
return await ConsoleFormatter.from(consoleMessage, {
339340
id: consoleMessageStableId,

src/PageCollector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ export class PageCollector<T> {
236236
}
237237

238238
export class ConsoleCollector extends PageCollector<
239-
ConsoleMessage | Error | DevTools.AggregatedIssue
239+
ConsoleMessage | Error | DevTools.AggregatedIssue | UncaughtError
240240
> {
241241
#subscribedPages = new WeakMap<Page, PageEventSubscriber>();
242242

tests/tools/console.test.js.snapshot

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@ at Iife (main.js:10:2)
1111
at <anonymous> (main.js:9:0)
1212
`;
1313

14+
exports[`console > get_console_message > applies source maps to stack traces of uncaught exceptions 1`] = `
15+
# test response
16+
ID: 1
17+
Message: error> Uncaught Error: b00m!
18+
### Stack trace
19+
at bar (main.js:2:8)
20+
at foo (main.js:6:2)
21+
at Iife (main.js:10:2)
22+
at <anonymous> (main.js:9:0)
23+
`;
24+
1425
exports[`console > get_console_message > issues type > gets issue details with node id parsing 1`] = `
1526
# test response
1627
ID: 1

tests/tools/console.test.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ describe('console', () => {
4949
await listConsoleMessages.handler({params: {}}, response, context);
5050
const formattedResponse = await response.handle('test', context);
5151
const textContent = getTextContent(formattedResponse.content[0]);
52-
assert.ok(textContent.includes('msgid=1 [error] undefined (0 args)'));
52+
assert.ok(textContent.includes('msgid=1 [error] Uncaught (0 args)'));
5353
});
5454
});
5555

@@ -257,5 +257,34 @@ describe('console', () => {
257257
t.assert.snapshot?.(rawText);
258258
});
259259
});
260+
261+
it('applies source maps to stack traces of uncaught exceptions', async t => {
262+
server.addRoute('/main.min.js', (_req, res) => {
263+
res.setHeader('Content-Type', 'text/javascript');
264+
res.statusCode = 200;
265+
res.end(`function n(){throw new Error("b00m!")}function o(){n()}(function n(){o()})();
266+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJiYXIiLCJFcnJvciIsImZvbyIsIklpZmUiXSwic291cmNlcyI6WyIuL21haW4uanMiXSwic291cmNlc0NvbnRlbnQiOlsiXG5mdW5jdGlvbiBiYXIoKSB7XG4gIHRocm93IG5ldyBFcnJvcignYjAwbSEnKTtcbn1cblxuZnVuY3Rpb24gZm9vKCkge1xuICBiYXIoKTtcbn1cblxuKGZ1bmN0aW9uIElpZmUoKSB7XG4gIGZvbygpO1xufSkoKTtcblxuIl0sIm1hcHBpbmdzIjoiQUFDQSxTQUFTQSxJQUNQLE1BQU0sSUFBSUMsTUFBTSxRQUNsQixDQUVBLFNBQVNDLElBQ1BGLEdBQ0YsRUFFQSxTQUFVRyxJQUNSRCxHQUNELEVBRkQiLCJpZ25vcmVMaXN0IjpbXX0=
267+
`);
268+
});
269+
server.addHtmlRoute(
270+
'/index.html',
271+
`<script src="${server.getRoute('/main.min.js')}"></script>`,
272+
);
273+
274+
await withMcpContext(async (response, context) => {
275+
const page = await context.newPage();
276+
await page.goto(server.getRoute('/index.html'));
277+
278+
await getConsoleMessage.handler(
279+
{params: {msgid: 1}},
280+
response,
281+
context,
282+
);
283+
const formattedResponse = await response.handle('test', context);
284+
const rawText = getTextContent(formattedResponse.content[0]);
285+
286+
t.assert.snapshot?.(rawText);
287+
});
288+
});
260289
});
261290
});

0 commit comments

Comments
 (0)