From 1e911a58b04704df02c03410ebcaa7f76f885658 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Mon, 13 Jul 2026 12:49:49 +0200 Subject: [PATCH 1/3] fix(core): surface abort reasons in errors Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4700825d-f132-4fcc-ba57-109da3fb9e77 --- .../playwright-core/src/server/dispatchers/dispatcher.ts | 2 +- packages/playwright-core/src/server/frames.ts | 5 +---- packages/playwright-core/src/server/progress.ts | 3 +++ tests/page/expect-timeout.spec.ts | 5 +++-- tests/page/page-click.spec.ts | 7 ++++--- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/playwright-core/src/server/dispatchers/dispatcher.ts b/packages/playwright-core/src/server/dispatchers/dispatcher.ts index 1cf7edeb70ac2..3bb60565fa7c5 100644 --- a/packages/playwright-core/src/server/dispatchers/dispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/dispatcher.ts @@ -312,7 +312,7 @@ export class DispatcherConnection { return; } if (method === '__abort__') { - await this._activeProgressControllers.get(`call@${params.id}`)?.abort(new AbortError(undefined, { cause: params.reason })); + await this._activeProgressControllers.get(`call@${params.id}`)?.abort(new AbortError(params.reason)); return; } if (!dispatcher) { diff --git a/packages/playwright-core/src/server/frames.ts b/packages/playwright-core/src/server/frames.ts index 44de2e8249066..20ae2660de8f9 100644 --- a/packages/playwright-core/src/server/frames.ts +++ b/packages/playwright-core/src/server/frames.ts @@ -16,7 +16,6 @@ */ import yaml from 'yaml'; -import { assertionAbortedMessage } from '@isomorphic/abortSignal'; import { parseAriaSnapshotUnsafe } from '@isomorphic/ariaSnapshot'; import { isInvalidSelectorError } from '@isomorphic/selectorParser'; import { ManualPromise } from '@isomorphic/manualPromise'; @@ -29,7 +28,7 @@ import { makeWaitForNextTask } from '@utils/task'; import { createGuid } from '@utils/crypto'; import { BrowserContext } from './browserContext'; import * as dom from './dom'; -import { TimeoutError, AbortError, isTargetClosedError } from './errors'; +import { TimeoutError, isTargetClosedError } from './errors'; import { prepareFilesForUpload } from './fileUploadUtils'; import { FrameSelectors } from './frameSelectors'; import { helper } from './helper'; @@ -1545,8 +1544,6 @@ export class Frame extends SdkObject { progress.log(e.message); if (e instanceof TimeoutError) details.timedOut = true; - if (e instanceof AbortError) - details.customErrorMessage = assertionAbortedMessage(e.cause); throw new ExpectError(details); } } diff --git a/packages/playwright-core/src/server/progress.ts b/packages/playwright-core/src/server/progress.ts index 8e97ce83aa083..a916e1c86168e 100644 --- a/packages/playwright-core/src/server/progress.ts +++ b/packages/playwright-core/src/server/progress.ts @@ -64,12 +64,15 @@ export class ProgressController { async abort(error: Error) { + const causeMessage = error.cause instanceof Error ? error.cause.message : error.cause === undefined ? error.message : String(error.cause); if (this._state === 'running') { + this.metadata.log.push(causeMessage); (error as any)[kAbortErrorSymbol] = true; this._state = { error }; this._forceAbortPromise.reject(error); this._controller.abort(error); } else if (this._state === 'before') { + this.metadata.log.push(causeMessage); (error as any)[kAbortErrorSymbol] = true; this._pendingAbortError = error; } diff --git a/tests/page/expect-timeout.spec.ts b/tests/page/expect-timeout.spec.ts index 6615cbbc46a89..f1c4440efb287 100644 --- a/tests/page/expect-timeout.spec.ts +++ b/tests/page/expect-timeout.spec.ts @@ -133,11 +133,12 @@ test('should fail like a timeout when the signal is aborted mid-assertion', asyn Locator: locator('span') Expected: visible -Error: The assertion was aborted: stop it +Error: element(s) not found Call log: - Expect "toBeVisible" with timeout 5000ms - - waiting for locator('span')`); + - waiting for locator('span') + - stop it`); }); test('should fail like a timeout when toHaveText is aborted mid-assertion', async ({ page }) => { diff --git a/tests/page/page-click.spec.ts b/tests/page/page-click.spec.ts index 8649e738ac1e8..888ffc3d55422 100644 --- a/tests/page/page-click.spec.ts +++ b/tests/page/page-click.spec.ts @@ -1368,11 +1368,11 @@ it('should abort via signal', async ({ page }) => { // Give the action time to start and emit call log entries before aborting. await page.waitForTimeout(500); - const reason = new Error('Aborted by user'); + const reason = new Error('foo bar'); controller.abort(reason); const error = await promise; - expect(error.message).toContain('The operation was aborted'); - expect(error.message).toContain(`Call log:`); + expect(error.message).toContain('locator.click: foo bar'); + expect(error.message).toMatch(/Call log:[\s\S]*foo bar/); expect(error.name).toBe('AbortError'); expect(error.cause).toBe(reason); }); @@ -1384,6 +1384,7 @@ it('should throw an Error when aborted in-flight with a string reason', async ({ controller.abort('aborted by user'); const error = await promise.catch(e => e); expect(error).toBeInstanceOf(Error); + expect(error.message).toContain('locator.click: aborted by user'); expect(error.name).toBe('AbortError'); expect(error.cause).toBe('aborted by user'); }); From 92295b6bb13f7dc97cb5aad1cce2cfa5149ebf7d Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Mon, 13 Jul 2026 13:05:54 +0200 Subject: [PATCH 2/3] fix(core): prefix abort reasons in call logs Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4700825d-f132-4fcc-ba57-109da3fb9e77 --- packages/playwright-core/src/server/progress.ts | 5 +++-- tests/page/expect-timeout.spec.ts | 2 +- tests/page/page-click.spec.ts | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/playwright-core/src/server/progress.ts b/packages/playwright-core/src/server/progress.ts index a916e1c86168e..d9360f4eac35e 100644 --- a/packages/playwright-core/src/server/progress.ts +++ b/packages/playwright-core/src/server/progress.ts @@ -65,14 +65,15 @@ export class ProgressController { async abort(error: Error) { const causeMessage = error.cause instanceof Error ? error.cause.message : error.cause === undefined ? error.message : String(error.cause); + const logMessage = `operation was aborted: ${causeMessage}`; if (this._state === 'running') { - this.metadata.log.push(causeMessage); + this.metadata.log.push(logMessage); (error as any)[kAbortErrorSymbol] = true; this._state = { error }; this._forceAbortPromise.reject(error); this._controller.abort(error); } else if (this._state === 'before') { - this.metadata.log.push(causeMessage); + this.metadata.log.push(logMessage); (error as any)[kAbortErrorSymbol] = true; this._pendingAbortError = error; } diff --git a/tests/page/expect-timeout.spec.ts b/tests/page/expect-timeout.spec.ts index f1c4440efb287..6753716a1c25b 100644 --- a/tests/page/expect-timeout.spec.ts +++ b/tests/page/expect-timeout.spec.ts @@ -138,7 +138,7 @@ Error: element(s) not found Call log: - Expect "toBeVisible" with timeout 5000ms - waiting for locator('span') - - stop it`); + - operation was aborted: stop it`); }); test('should fail like a timeout when toHaveText is aborted mid-assertion', async ({ page }) => { diff --git a/tests/page/page-click.spec.ts b/tests/page/page-click.spec.ts index 888ffc3d55422..30416d9dd3a5b 100644 --- a/tests/page/page-click.spec.ts +++ b/tests/page/page-click.spec.ts @@ -1372,7 +1372,7 @@ it('should abort via signal', async ({ page }) => { controller.abort(reason); const error = await promise; expect(error.message).toContain('locator.click: foo bar'); - expect(error.message).toMatch(/Call log:[\s\S]*foo bar/); + expect(error.message).toMatch(/Call log:[\s\S]*operation was aborted: foo bar/); expect(error.name).toBe('AbortError'); expect(error.cause).toBe(reason); }); From 8174aa478f98eaa19a60b60cde86f85332ff8ff0 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Mon, 13 Jul 2026 16:57:03 +0200 Subject: [PATCH 3/3] fix(core): use abort error message in call logs Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4700825d-f132-4fcc-ba57-109da3fb9e77 --- packages/playwright-core/src/server/progress.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/playwright-core/src/server/progress.ts b/packages/playwright-core/src/server/progress.ts index d9360f4eac35e..78d3298257238 100644 --- a/packages/playwright-core/src/server/progress.ts +++ b/packages/playwright-core/src/server/progress.ts @@ -62,10 +62,8 @@ export class ProgressController { }); } - async abort(error: Error) { - const causeMessage = error.cause instanceof Error ? error.cause.message : error.cause === undefined ? error.message : String(error.cause); - const logMessage = `operation was aborted: ${causeMessage}`; + const logMessage = `operation was aborted: ${error.message}`; if (this._state === 'running') { this.metadata.log.push(logMessage); (error as any)[kAbortErrorSymbol] = true;