diff --git a/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts b/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts index e0763acdf7809..66c5d278dac7c 100644 --- a/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts @@ -114,9 +114,9 @@ export class BrowserContextDispatcher extends Dispatcher { @@ -432,7 +432,7 @@ export class Page extends SdkObject { return marked === -1 ? this._consoleMessages : this._consoleMessages.slice(marked + 1); } - addPageError(error: Error, location: types.ConsoleMessageLocation) { + addPageError(error: Error, location: types.ConsoleMessageLocation | undefined) { const pageError: PageError = { error, location }; this._pageErrors.push(pageError); ensureArrayLimit(this._pageErrors, 200); // Avoid unbounded memory growth. diff --git a/packages/playwright-core/src/server/trace/recorder/tracing.ts b/packages/playwright-core/src/server/trace/recorder/tracing.ts index 5351b2c2b25e5..80709b3c91852 100644 --- a/packages/playwright-core/src/server/trace/recorder/tracing.ts +++ b/packages/playwright-core/src/server/trace/recorder/tracing.ts @@ -643,9 +643,9 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps params: { error: serializeError(pageError.error), location: { - url: pageError.location.url, - line: pageError.location.lineNumber, - column: pageError.location.columnNumber, + url: pageError.location?.url ?? '', + line: pageError.location?.lineNumber ?? 0, + column: pageError.location?.columnNumber ?? 0, }, }, pageId: page.guid, diff --git a/tests/library/browsercontext-events.spec.ts b/tests/library/browsercontext-events.spec.ts index 9afc08def24d2..d9c973c08a8a8 100644 --- a/tests/library/browsercontext-events.spec.ts +++ b/tests/library/browsercontext-events.spec.ts @@ -278,3 +278,28 @@ test('download event should work @smoke', async ({ page, server }) => { expect(download.suggestedFilename()).toBe('file.txt'); expect(download.page()).toBe(page); }); + +test('weberror event should not crash when Firefox omits location in uncaughtError', { + annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/41169' }, +}, async ({ page, toImpl, browserName }) => { + // Firefox can omit the location field in Page.uncaughtError protocol events + // when an uncaught error fires during mid-navigation. Inject a synthetic event + // without location to verify the driver does not crash. + test.skip(browserName !== 'firefox', 'Firefox-only: tests FF protocol behaviour'); + const webErrors: Error[] = []; + page.context().on('weberror', e => webErrors.push(e.error())); + const pageErrors: Error[] = []; + page.on('pageerror', e => pageErrors.push(e)); + + (toImpl(page) as any).delegate._session.emit('Page.uncaughtError', { + frameId: '', + message: 'Error: no-location-error', + stack: '', + // location intentionally absent — simulates the protocol omitting it + }); + + await page.waitForTimeout(500); + expect(pageErrors).toHaveLength(1); + expect(pageErrors[0].message).toBe('no-location-error'); + expect(webErrors).toHaveLength(1); +});