diff --git a/packages/puppeteer-core/src/api/locators/locators.ts b/packages/puppeteer-core/src/api/locators/locators.ts index d88cc0a17df..ea77dc94a1c 100644 --- a/packages/puppeteer-core/src/api/locators/locators.ts +++ b/packages/puppeteer-core/src/api/locators/locators.ts @@ -172,19 +172,23 @@ export abstract class Locator extends EventEmitter { }); }, retryAndRaceWithSignalAndTimer: ( - signal?: AbortSignal + signal?: AbortSignal, + cause?: Error ): OperatorFunction => { const candidates = []; if (signal) { candidates.push( fromEvent(signal, 'abort').pipe( map(() => { + if (signal.reason instanceof Error) { + signal.reason.cause = cause; + } throw signal.reason; }) ) ); } - candidates.push(timeout(this._timeout)); + candidates.push(timeout(this._timeout, cause)); return pipe( retry({delay: RETRY_DELAY}), raceWith(...candidates) @@ -368,6 +372,7 @@ export abstract class Locator extends EventEmitter { options?: Readonly ): Observable { const signal = options?.signal; + const cause = new Error('Locator.click'); return this._wait(options).pipe( this.operators.conditions( [ @@ -388,7 +393,7 @@ export abstract class Locator extends EventEmitter { }) ); }), - this.operators.retryAndRaceWithSignalAndTimer(signal) + this.operators.retryAndRaceWithSignalAndTimer(signal, cause) ); } @@ -398,6 +403,7 @@ export abstract class Locator extends EventEmitter { options?: Readonly ): Observable { const signal = options?.signal; + const cause = new Error('Locator.fill'); return this._wait(options).pipe( this.operators.conditions( [ @@ -521,7 +527,7 @@ export abstract class Locator extends EventEmitter { }) ); }), - this.operators.retryAndRaceWithSignalAndTimer(signal) + this.operators.retryAndRaceWithSignalAndTimer(signal, cause) ); } @@ -530,6 +536,7 @@ export abstract class Locator extends EventEmitter { options?: Readonly ): Observable { const signal = options?.signal; + const cause = new Error('Locator.hover'); return this._wait(options).pipe( this.operators.conditions( [ @@ -549,7 +556,7 @@ export abstract class Locator extends EventEmitter { }) ); }), - this.operators.retryAndRaceWithSignalAndTimer(signal) + this.operators.retryAndRaceWithSignalAndTimer(signal, cause) ); } @@ -558,6 +565,7 @@ export abstract class Locator extends EventEmitter { options?: Readonly ): Observable { const signal = options?.signal; + const cause = new Error('Locator.scroll'); return this._wait(options).pipe( this.operators.conditions( [ @@ -590,7 +598,7 @@ export abstract class Locator extends EventEmitter { }) ); }), - this.operators.retryAndRaceWithSignalAndTimer(signal) + this.operators.retryAndRaceWithSignalAndTimer(signal, cause) ); } @@ -617,9 +625,10 @@ export abstract class Locator extends EventEmitter { * @public */ async waitHandle(options?: Readonly): Promise> { + const cause = new Error('Locator.waitHandle'); return await firstValueFrom( this._wait(options).pipe( - this.operators.retryAndRaceWithSignalAndTimer(options?.signal) + this.operators.retryAndRaceWithSignalAndTimer(options?.signal, cause) ) ); } diff --git a/packages/puppeteer-core/src/common/Errors.ts b/packages/puppeteer-core/src/common/Errors.ts index 4d0a43ea33a..46a3548cf37 100644 --- a/packages/puppeteer-core/src/common/Errors.ts +++ b/packages/puppeteer-core/src/common/Errors.ts @@ -13,8 +13,8 @@ export class PuppeteerError extends Error { /** * @internal */ - constructor(message?: string) { - super(message); + constructor(message?: string, options?: ErrorOptions) { + super(message, options); this.name = this.constructor.name; } diff --git a/packages/puppeteer-core/src/common/util.ts b/packages/puppeteer-core/src/common/util.ts index f84453c612e..44d22ae01de 100644 --- a/packages/puppeteer-core/src/common/util.ts +++ b/packages/puppeteer-core/src/common/util.ts @@ -312,12 +312,12 @@ export function validateDialogType( /** * @internal */ -export function timeout(ms: number): Observable { +export function timeout(ms: number, cause?: Error): Observable { return ms === 0 ? NEVER : timer(ms).pipe( map(() => { - throw new TimeoutError(`Timed out after waiting ${ms}ms`); + throw new TimeoutError(`Timed out after waiting ${ms}ms`, {cause}); }) ); }