mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: remove the usages of raw target closed message constant (#27669)
This commit is contained in:
parent
5262e5ab35
commit
091f6883f5
@ -281,7 +281,7 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
|
|||||||
const waiter = Waiter.createForEvent(this, event);
|
const waiter = Waiter.createForEvent(this, event);
|
||||||
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
|
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
|
||||||
if (event !== Events.AndroidDevice.Close)
|
if (event !== Events.AndroidDevice.Close)
|
||||||
waiter.rejectOnEvent(this, Events.AndroidDevice.Close, new TargetClosedError());
|
waiter.rejectOnEvent(this, Events.AndroidDevice.Close, () => new TargetClosedError());
|
||||||
const result = await waiter.waitForEvent(this, event, predicate as any);
|
const result = await waiter.waitForEvent(this, event, predicate as any);
|
||||||
waiter.dispose();
|
waiter.dispose();
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -40,6 +40,7 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
|
|||||||
|
|
||||||
// Used from @playwright/test fixtures.
|
// Used from @playwright/test fixtures.
|
||||||
_connectHeaders?: HeadersArray;
|
_connectHeaders?: HeadersArray;
|
||||||
|
_closeReason: string | undefined;
|
||||||
|
|
||||||
static from(browser: channels.BrowserChannel): Browser {
|
static from(browser: channels.BrowserChannel): Browser {
|
||||||
return (browser as any)._object;
|
return (browser as any)._object;
|
||||||
@ -131,6 +132,7 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
|
|||||||
}
|
}
|
||||||
|
|
||||||
async close(options: { reason?: string } = {}): Promise<void> {
|
async close(options: { reason?: string } = {}): Promise<void> {
|
||||||
|
this._closeReason = options.reason;
|
||||||
try {
|
try {
|
||||||
if (this._shouldCloseConnectionOnClose)
|
if (this._shouldCloseConnectionOnClose)
|
||||||
this._connection.close();
|
this._connection.close();
|
||||||
|
|||||||
@ -64,6 +64,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||||||
readonly _isChromium: boolean;
|
readonly _isChromium: boolean;
|
||||||
private _harRecorders = new Map<string, { path: string, content: 'embed' | 'attach' | 'omit' | undefined }>();
|
private _harRecorders = new Map<string, { path: string, content: 'embed' | 'attach' | 'omit' | undefined }>();
|
||||||
private _closeWasCalled = false;
|
private _closeWasCalled = false;
|
||||||
|
private _closeReason: string | undefined;
|
||||||
|
|
||||||
static from(context: channels.BrowserContextChannel): BrowserContext {
|
static from(context: channels.BrowserContextChannel): BrowserContext {
|
||||||
return (context as any)._object;
|
return (context as any)._object;
|
||||||
@ -337,6 +338,10 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||||||
await this._channel.setNetworkInterceptionPatterns({ patterns });
|
await this._channel.setNetworkInterceptionPatterns({ patterns });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_effectiveCloseReason(): string | undefined {
|
||||||
|
return this._closeReason || this._browser?._closeReason;
|
||||||
|
}
|
||||||
|
|
||||||
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
|
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
|
||||||
return this._wrapApiCall(async () => {
|
return this._wrapApiCall(async () => {
|
||||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||||
@ -344,7 +349,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||||||
const waiter = Waiter.createForEvent(this, event);
|
const waiter = Waiter.createForEvent(this, event);
|
||||||
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
|
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
|
||||||
if (event !== Events.BrowserContext.Close)
|
if (event !== Events.BrowserContext.Close)
|
||||||
waiter.rejectOnEvent(this, Events.BrowserContext.Close, new TargetClosedError());
|
waiter.rejectOnEvent(this, Events.BrowserContext.Close, () => new TargetClosedError(this._effectiveCloseReason()));
|
||||||
const result = await waiter.waitForEvent(this, event, predicate as any);
|
const result = await waiter.waitForEvent(this, event, predicate as any);
|
||||||
waiter.dispose();
|
waiter.dispose();
|
||||||
return result;
|
return result;
|
||||||
@ -386,6 +391,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||||||
async close(options: { reason?: string } = {}): Promise<void> {
|
async close(options: { reason?: string } = {}): Promise<void> {
|
||||||
if (this._closeWasCalled)
|
if (this._closeWasCalled)
|
||||||
return;
|
return;
|
||||||
|
this._closeReason = options.reason;
|
||||||
this._closeWasCalled = true;
|
this._closeWasCalled = true;
|
||||||
await this._wrapApiCall(async () => {
|
await this._wrapApiCall(async () => {
|
||||||
await this._browserType?._willCloseContext(this);
|
await this._browserType?._willCloseContext(this);
|
||||||
|
|||||||
@ -184,9 +184,7 @@ export class Connection extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
close(cause?: Error) {
|
close(cause?: Error) {
|
||||||
this._closedError = new TargetClosedError();
|
this._closedError = new TargetClosedError(cause?.toString());
|
||||||
if (cause)
|
|
||||||
rewriteErrorMessage(this._closedError, this._closedError.message + '\nCaused by: ' + cause.toString());
|
|
||||||
for (const callback of this._callbacks.values())
|
for (const callback of this._callbacks.values())
|
||||||
callback.reject(this._closedError);
|
callback.reject(this._closedError);
|
||||||
this._callbacks.clear();
|
this._callbacks.clear();
|
||||||
|
|||||||
@ -121,7 +121,7 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
|
|||||||
const waiter = Waiter.createForEvent(this, event);
|
const waiter = Waiter.createForEvent(this, event);
|
||||||
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
|
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
|
||||||
if (event !== Events.ElectronApplication.Close)
|
if (event !== Events.ElectronApplication.Close)
|
||||||
waiter.rejectOnEvent(this, Events.ElectronApplication.Close, new TargetClosedError());
|
waiter.rejectOnEvent(this, Events.ElectronApplication.Close, () => new TargetClosedError());
|
||||||
const result = await waiter.waitForEvent(this, event, predicate as any);
|
const result = await waiter.waitForEvent(this, event, predicate as any);
|
||||||
waiter.dispose();
|
waiter.dispose();
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -36,7 +36,6 @@ import { urlMatches } from '../utils/network';
|
|||||||
import type * as api from '../../types/types';
|
import type * as api from '../../types/types';
|
||||||
import type * as structs from '../../types/structs';
|
import type * as structs from '../../types/structs';
|
||||||
import { debugLogger } from '../common/debugLogger';
|
import { debugLogger } from '../common/debugLogger';
|
||||||
import { TargetClosedError } from '../common/errors';
|
|
||||||
|
|
||||||
export type WaitForNavigationOptions = {
|
export type WaitForNavigationOptions = {
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
@ -105,8 +104,8 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
|
|||||||
private _setupNavigationWaiter(options: { timeout?: number }): Waiter {
|
private _setupNavigationWaiter(options: { timeout?: number }): Waiter {
|
||||||
const waiter = new Waiter(this._page!, '');
|
const waiter = new Waiter(this._page!, '');
|
||||||
if (this._page!.isClosed())
|
if (this._page!.isClosed())
|
||||||
waiter.rejectImmediately(new TargetClosedError());
|
waiter.rejectImmediately(this._page!._closeErrorWithReason());
|
||||||
waiter.rejectOnEvent(this._page!, Events.Page.Close, new TargetClosedError());
|
waiter.rejectOnEvent(this._page!, Events.Page.Close, () => this._page!._closeErrorWithReason());
|
||||||
waiter.rejectOnEvent(this._page!, Events.Page.Crash, new Error('Navigation failed because page crashed!'));
|
waiter.rejectOnEvent(this._page!, Events.Page.Crash, new Error('Navigation failed because page crashed!'));
|
||||||
waiter.rejectOnEvent<Frame>(this._page!, Events.Page.FrameDetached, new Error('Navigating frame was detached!'), frame => frame === this);
|
waiter.rejectOnEvent<Frame>(this._page!, Events.Page.FrameDetached, new Error('Navigating frame was detached!'), frame => frame === this);
|
||||||
const timeout = this._page!._timeoutSettings.navigationTimeout(options);
|
const timeout = this._page!._timeoutSettings.navigationTimeout(options);
|
||||||
|
|||||||
@ -34,7 +34,6 @@ import { MultiMap } from '../utils/multimap';
|
|||||||
import { APIResponse } from './fetch';
|
import { APIResponse } from './fetch';
|
||||||
import type { Serializable } from '../../types/structs';
|
import type { Serializable } from '../../types/structs';
|
||||||
import type { BrowserContext } from './browserContext';
|
import type { BrowserContext } from './browserContext';
|
||||||
import { TargetClosedError } from '../common/errors';
|
|
||||||
|
|
||||||
export type NetworkCookie = {
|
export type NetworkCookie = {
|
||||||
name: string,
|
name: string,
|
||||||
@ -611,7 +610,7 @@ export class WebSocket extends ChannelOwner<channels.WebSocketChannel> implement
|
|||||||
waiter.rejectOnEvent(this, Events.WebSocket.Error, new Error('Socket error'));
|
waiter.rejectOnEvent(this, Events.WebSocket.Error, new Error('Socket error'));
|
||||||
if (event !== Events.WebSocket.Close)
|
if (event !== Events.WebSocket.Close)
|
||||||
waiter.rejectOnEvent(this, Events.WebSocket.Close, new Error('Socket closed'));
|
waiter.rejectOnEvent(this, Events.WebSocket.Close, new Error('Socket closed'));
|
||||||
waiter.rejectOnEvent(this._page, Events.Page.Close, new TargetClosedError());
|
waiter.rejectOnEvent(this._page, Events.Page.Close, () => this._page._closeErrorWithReason());
|
||||||
const result = await waiter.waitForEvent(this, event, predicate as any);
|
const result = await waiter.waitForEvent(this, event, predicate as any);
|
||||||
waiter.dispose();
|
waiter.dispose();
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import type * as structs from '../../types/structs';
|
import type * as structs from '../../types/structs';
|
||||||
import type * as api from '../../types/types';
|
import type * as api from '../../types/types';
|
||||||
import { isTargetClosedError, TargetClosedError, kTargetClosedErrorMessage } from '../common/errors';
|
import { isTargetClosedError, TargetClosedError } from '../common/errors';
|
||||||
import { urlMatches } from '../utils/network';
|
import { urlMatches } from '../utils/network';
|
||||||
import { TimeoutSettings } from '../common/timeoutSettings';
|
import { TimeoutSettings } from '../common/timeoutSettings';
|
||||||
import type * as channels from '@protocol/channels';
|
import type * as channels from '@protocol/channels';
|
||||||
@ -93,6 +93,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||||||
readonly _timeoutSettings: TimeoutSettings;
|
readonly _timeoutSettings: TimeoutSettings;
|
||||||
private _video: Video | null = null;
|
private _video: Video | null = null;
|
||||||
readonly _opener: Page | null;
|
readonly _opener: Page | null;
|
||||||
|
private _closeReason: string | undefined;
|
||||||
|
|
||||||
static from(page: channels.PageChannel): Page {
|
static from(page: channels.PageChannel): Page {
|
||||||
return (page as any)._object;
|
return (page as any)._object;
|
||||||
@ -140,8 +141,8 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||||||
|
|
||||||
this.coverage = new Coverage(this._channel);
|
this.coverage = new Coverage(this._channel);
|
||||||
|
|
||||||
this.once(Events.Page.Close, () => this._closedOrCrashedScope.close(kTargetClosedErrorMessage));
|
this.once(Events.Page.Close, () => this._closedOrCrashedScope.close(this._closeErrorWithReason()));
|
||||||
this.once(Events.Page.Crash, () => this._closedOrCrashedScope.close(kTargetClosedErrorMessage));
|
this.once(Events.Page.Crash, () => this._closedOrCrashedScope.close(new TargetClosedError()));
|
||||||
|
|
||||||
this._setEventToSubscriptionMapping(new Map<string, channels.PageUpdateSubscriptionParams['event']>([
|
this._setEventToSubscriptionMapping(new Map<string, channels.PageUpdateSubscriptionParams['event']>([
|
||||||
[Events.Page.Console, 'console'],
|
[Events.Page.Console, 'console'],
|
||||||
@ -387,6 +388,10 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||||||
return this._waitForEvent(event, optionsOrPredicate, `waiting for event "${event}"`);
|
return this._waitForEvent(event, optionsOrPredicate, `waiting for event "${event}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_closeErrorWithReason(): TargetClosedError {
|
||||||
|
return new TargetClosedError(this._closeReason || this._browserContext._effectiveCloseReason());
|
||||||
|
}
|
||||||
|
|
||||||
private async _waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions, logLine?: string): Promise<any> {
|
private async _waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions, logLine?: string): Promise<any> {
|
||||||
return this._wrapApiCall(async () => {
|
return this._wrapApiCall(async () => {
|
||||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||||
@ -398,7 +403,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||||||
if (event !== Events.Page.Crash)
|
if (event !== Events.Page.Crash)
|
||||||
waiter.rejectOnEvent(this, Events.Page.Crash, new Error('Page crashed'));
|
waiter.rejectOnEvent(this, Events.Page.Crash, new Error('Page crashed'));
|
||||||
if (event !== Events.Page.Close)
|
if (event !== Events.Page.Close)
|
||||||
waiter.rejectOnEvent(this, Events.Page.Close, new TargetClosedError());
|
waiter.rejectOnEvent(this, Events.Page.Close, () => this._closeErrorWithReason());
|
||||||
const result = await waiter.waitForEvent(this, event, predicate as any);
|
const result = await waiter.waitForEvent(this, event, predicate as any);
|
||||||
waiter.dispose();
|
waiter.dispose();
|
||||||
return result;
|
return result;
|
||||||
@ -513,7 +518,8 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||||||
await this._channel.bringToFront();
|
await this._channel.bringToFront();
|
||||||
}
|
}
|
||||||
|
|
||||||
async close(options: { runBeforeUnload?: boolean } = { runBeforeUnload: undefined }) {
|
async close(options: { runBeforeUnload?: boolean, reason?: string } = {}) {
|
||||||
|
this._closeReason = options.reason;
|
||||||
try {
|
try {
|
||||||
if (this._ownedContext)
|
if (this._ownedContext)
|
||||||
await this._ownedContext.close();
|
await this._ownedContext.close();
|
||||||
|
|||||||
@ -50,9 +50,9 @@ export class Waiter {
|
|||||||
return this.waitForPromise(promise, dispose);
|
return this.waitForPromise(promise, dispose);
|
||||||
}
|
}
|
||||||
|
|
||||||
rejectOnEvent<T = void>(emitter: EventEmitter, event: string, error: Error, predicate?: (arg: T) => boolean | Promise<boolean>) {
|
rejectOnEvent<T = void>(emitter: EventEmitter, event: string, error: Error | (() => Error), predicate?: (arg: T) => boolean | Promise<boolean>) {
|
||||||
const { promise, dispose } = waitForEvent(emitter, event, predicate);
|
const { promise, dispose } = waitForEvent(emitter, event, predicate);
|
||||||
this._rejectOn(promise.then(() => { throw error; }), dispose);
|
this._rejectOn(promise.then(() => { throw (typeof error === 'function' ? error() : error); }), dispose);
|
||||||
}
|
}
|
||||||
|
|
||||||
rejectOnTimeout(timeout: number, message: string) {
|
rejectOnTimeout(timeout: number, message: string) {
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import type { BrowserContext } from './browserContext';
|
|||||||
import type * as api from '../../types/types';
|
import type * as api from '../../types/types';
|
||||||
import type * as structs from '../../types/structs';
|
import type * as structs from '../../types/structs';
|
||||||
import { LongStandingScope } from '../utils';
|
import { LongStandingScope } from '../utils';
|
||||||
import { kTargetClosedErrorMessage } from '../common/errors';
|
import { TargetClosedError } from '../common/errors';
|
||||||
|
|
||||||
export class Worker extends ChannelOwner<channels.WorkerChannel> implements api.Worker {
|
export class Worker extends ChannelOwner<channels.WorkerChannel> implements api.Worker {
|
||||||
_page: Page | undefined; // Set for web workers.
|
_page: Page | undefined; // Set for web workers.
|
||||||
@ -43,7 +43,7 @@ export class Worker extends ChannelOwner<channels.WorkerChannel> implements api.
|
|||||||
this._context._serviceWorkers.delete(this);
|
this._context._serviceWorkers.delete(this);
|
||||||
this.emit(Events.Worker.Close, this);
|
this.emit(Events.Worker.Close, this);
|
||||||
});
|
});
|
||||||
this.once(Events.Worker.Close, () => this._closedScope.close(kTargetClosedErrorMessage));
|
this.once(Events.Worker.Close, () => this._closedScope.close(this._page?._closeErrorWithReason() || new TargetClosedError()));
|
||||||
}
|
}
|
||||||
|
|
||||||
url(): string {
|
url(): string {
|
||||||
|
|||||||
@ -25,16 +25,13 @@ class CustomError extends Error {
|
|||||||
|
|
||||||
export class TimeoutError extends CustomError {}
|
export class TimeoutError extends CustomError {}
|
||||||
|
|
||||||
export const kTargetClosedErrorMessage = 'Target page, context or browser has been closed';
|
|
||||||
export const kTargetCrashedErrorMessage = 'Target crashed';
|
|
||||||
|
|
||||||
export class TargetClosedError extends Error {
|
export class TargetClosedError extends Error {
|
||||||
constructor() {
|
constructor(cause?: string, logs?: string) {
|
||||||
super(kTargetClosedErrorMessage);
|
super((cause || 'Target page, context or browser has been closed') + (logs || ''));
|
||||||
this.name = this.constructor.name;
|
this.name = this.constructor.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isTargetClosedError(error: Error) {
|
export function isTargetClosedError(error: Error) {
|
||||||
return error instanceof TargetClosedError || error.message.includes(kTargetClosedErrorMessage);
|
return error instanceof TargetClosedError || error.name === 'TargetClosedError';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { TimeoutError } from '../common/errors';
|
import { TargetClosedError, TimeoutError } from '../common/errors';
|
||||||
import type { SerializedError, SerializedValue } from '@protocol/channels';
|
import type { SerializedError, SerializedValue } from '@protocol/channels';
|
||||||
|
|
||||||
export function serializeError(e: any): SerializedError {
|
export function serializeError(e: any): SerializedError {
|
||||||
@ -34,6 +34,11 @@ export function parseError(error: SerializedError): Error {
|
|||||||
e.stack = error.error.stack || '';
|
e.stack = error.error.stack || '';
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
if (error.error.name === 'TargetClosedError') {
|
||||||
|
const e = new TargetClosedError(error.error.message);
|
||||||
|
e.stack = error.error.stack || '';
|
||||||
|
return e;
|
||||||
|
}
|
||||||
const e = new Error(error.error.message);
|
const e = new Error(error.error.message);
|
||||||
e.stack = error.error.stack || '';
|
e.stack = error.error.stack || '';
|
||||||
e.name = error.error.name;
|
e.name = error.error.name;
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import type * as channels from '@protocol/channels';
|
|||||||
import { serializeError } from '../../protocol/serializers';
|
import { serializeError } from '../../protocol/serializers';
|
||||||
import { findValidator, ValidationError, createMetadataValidator, type ValidatorContext } from '../../protocol/validator';
|
import { findValidator, ValidationError, createMetadataValidator, type ValidatorContext } from '../../protocol/validator';
|
||||||
import { assert, isUnderTest, monotonicTime, rewriteErrorMessage } from '../../utils';
|
import { assert, isUnderTest, monotonicTime, rewriteErrorMessage } from '../../utils';
|
||||||
import { TargetClosedError, isTargetClosedError, kTargetClosedErrorMessage, kTargetCrashedErrorMessage } from '../../common/errors';
|
import { TargetClosedError, isTargetClosedError } from '../../common/errors';
|
||||||
import type { CallMetadata } from '../instrumentation';
|
import type { CallMetadata } from '../instrumentation';
|
||||||
import { SdkObject } from '../instrumentation';
|
import { SdkObject } from '../instrumentation';
|
||||||
import type { PlaywrightDispatcher } from './playwrightDispatcher';
|
import type { PlaywrightDispatcher } from './playwrightDispatcher';
|
||||||
@ -330,15 +330,17 @@ export class DispatcherConnection {
|
|||||||
const validator = findValidator(dispatcher._type, method, 'Result');
|
const validator = findValidator(dispatcher._type, method, 'Result');
|
||||||
callMetadata.result = validator(result, '', { tChannelImpl: this._tChannelImplToWire.bind(this), binary: this._isLocal ? 'buffer' : 'toBase64' });
|
callMetadata.result = validator(result, '', { tChannelImpl: this._tChannelImplToWire.bind(this), binary: this._isLocal ? 'buffer' : 'toBase64' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (isTargetClosedError(e) && sdkObject)
|
if (isTargetClosedError(e) && sdkObject) {
|
||||||
rewriteErrorMessage(e, closeReason(sdkObject));
|
const reason = closeReason(sdkObject);
|
||||||
if (isProtocolError(e)) {
|
if (reason)
|
||||||
|
rewriteErrorMessage(e, reason);
|
||||||
|
} else if (isProtocolError(e)) {
|
||||||
if (e.type === 'closed') {
|
if (e.type === 'closed') {
|
||||||
const closedReason = sdkObject ? closeReason(sdkObject) : kTargetClosedErrorMessage;
|
const reason = sdkObject ? closeReason(sdkObject) : undefined;
|
||||||
rewriteErrorMessage(e, closedReason + e.browserLogMessage());
|
e = new TargetClosedError(reason, e.browserLogMessage());
|
||||||
|
} else if (e.type === 'crashed') {
|
||||||
|
rewriteErrorMessage(e, 'Target crashed ' + e.browserLogMessage());
|
||||||
}
|
}
|
||||||
if (e.type === 'crashed')
|
|
||||||
rewriteErrorMessage(e, kTargetCrashedErrorMessage + e.browserLogMessage());
|
|
||||||
}
|
}
|
||||||
callMetadata.error = serializeError(e);
|
callMetadata.error = serializeError(e);
|
||||||
} finally {
|
} finally {
|
||||||
@ -357,8 +359,8 @@ export class DispatcherConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeReason(sdkObject: SdkObject) {
|
function closeReason(sdkObject: SdkObject): string | undefined {
|
||||||
return sdkObject.attribution.page?._closeReason ||
|
return sdkObject.attribution.page?._closeReason ||
|
||||||
sdkObject.attribution.context?._closeReason ||
|
sdkObject.attribution.context?._closeReason ||
|
||||||
sdkObject.attribution.browser?._closeReason || kTargetClosedErrorMessage;
|
sdkObject.attribution.browser?._closeReason;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1532,7 +1532,7 @@ export class Frame extends SdkObject {
|
|||||||
|
|
||||||
_onDetached() {
|
_onDetached() {
|
||||||
this._stopNetworkIdleTimer();
|
this._stopNetworkIdleTimer();
|
||||||
this._detachedScope.close('Frame was detached');
|
this._detachedScope.close(new Error('Frame was detached'));
|
||||||
for (const data of this._contextData.values()) {
|
for (const data of this._contextData.values()) {
|
||||||
if (data.context)
|
if (data.context)
|
||||||
data.context.contextDestroyed('Frame was detached');
|
data.context.contextDestroyed('Frame was detached');
|
||||||
|
|||||||
@ -73,7 +73,7 @@ export class ExecutionContext extends SdkObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contextDestroyed(reason: string) {
|
contextDestroyed(reason: string) {
|
||||||
this._contextDestroyedScope.close(reason);
|
this._contextDestroyedScope.close(new Error(reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _raceAgainstContextDestroyed<T>(promise: Promise<T>): Promise<T> {
|
async _raceAgainstContextDestroyed<T>(promise: Promise<T>): Promise<T> {
|
||||||
|
|||||||
@ -43,7 +43,7 @@ import type { TimeoutOptions } from '../common/types';
|
|||||||
import { isInvalidSelectorError } from '../utils/isomorphic/selectorParser';
|
import { isInvalidSelectorError } from '../utils/isomorphic/selectorParser';
|
||||||
import { parseEvaluationResultValue, source } from './isomorphic/utilityScriptSerializers';
|
import { parseEvaluationResultValue, source } from './isomorphic/utilityScriptSerializers';
|
||||||
import type { SerializedValue } from './isomorphic/utilityScriptSerializers';
|
import type { SerializedValue } from './isomorphic/utilityScriptSerializers';
|
||||||
import { kTargetClosedErrorMessage } from '../common/errors';
|
import { TargetClosedError } from '../common/errors';
|
||||||
|
|
||||||
export interface PageDelegate {
|
export interface PageDelegate {
|
||||||
readonly rawMouse: input.RawMouse;
|
readonly rawMouse: input.RawMouse;
|
||||||
@ -277,7 +277,7 @@ export class Page extends SdkObject {
|
|||||||
this.emit(Page.Events.Close);
|
this.emit(Page.Events.Close);
|
||||||
this._closedPromise.resolve();
|
this._closedPromise.resolve();
|
||||||
this.instrumentation.onPageClose(this);
|
this.instrumentation.onPageClose(this);
|
||||||
this.openScope.close(kTargetClosedErrorMessage);
|
this.openScope.close(new TargetClosedError());
|
||||||
}
|
}
|
||||||
|
|
||||||
_didCrash() {
|
_didCrash() {
|
||||||
@ -286,7 +286,7 @@ export class Page extends SdkObject {
|
|||||||
this.emit(Page.Events.Crash);
|
this.emit(Page.Events.Crash);
|
||||||
this._crashed = true;
|
this._crashed = true;
|
||||||
this.instrumentation.onPageClose(this);
|
this.instrumentation.onPageClose(this);
|
||||||
this.openScope.close('Page crashed');
|
this.openScope.close(new Error('Page crashed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onFileChooserOpened(handle: dom.ElementHandle) {
|
async _onFileChooserOpened(handle: dom.ElementHandle) {
|
||||||
@ -733,7 +733,7 @@ export class Worker extends SdkObject {
|
|||||||
if (this._existingExecutionContext)
|
if (this._existingExecutionContext)
|
||||||
this._existingExecutionContext.contextDestroyed('Worker was closed');
|
this._existingExecutionContext.contextDestroyed('Worker was closed');
|
||||||
this.emit(Worker.Events.Close, this);
|
this.emit(Worker.Events.Close, this);
|
||||||
this.openScope.close('Worker closed');
|
this.openScope.close(new Error('Worker closed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
async evaluateExpression(expression: string, isFunction: boolean | undefined, arg: any): Promise<any> {
|
async evaluateExpression(expression: string, isFunction: boolean | undefined, arg: any): Promise<any> {
|
||||||
|
|||||||
@ -58,7 +58,7 @@ export class ManualPromise<T = void> extends Promise<T> {
|
|||||||
|
|
||||||
export class LongStandingScope {
|
export class LongStandingScope {
|
||||||
private _terminateError: Error | undefined;
|
private _terminateError: Error | undefined;
|
||||||
private _terminateErrorMessage: string | undefined;
|
private _closeError: Error | undefined;
|
||||||
private _terminatePromises = new Map<ManualPromise<Error>, string[]>();
|
private _terminatePromises = new Map<ManualPromise<Error>, string[]>();
|
||||||
private _isClosed = false;
|
private _isClosed = false;
|
||||||
|
|
||||||
@ -69,14 +69,11 @@ export class LongStandingScope {
|
|||||||
p.resolve(error);
|
p.resolve(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(errorMessage: string) {
|
close(error: Error) {
|
||||||
this._isClosed = true;
|
this._isClosed = true;
|
||||||
this._terminateErrorMessage = errorMessage;
|
this._closeError = error;
|
||||||
for (const [p, frames] of this._terminatePromises) {
|
for (const [p, frames] of this._terminatePromises)
|
||||||
const error = new Error(errorMessage);
|
p.resolve(cloneError(error, frames));
|
||||||
error.stack = [error.name + ':' + errorMessage, ...frames].join('\n');
|
|
||||||
p.resolve(error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isClosed() {
|
isClosed() {
|
||||||
@ -97,11 +94,12 @@ export class LongStandingScope {
|
|||||||
|
|
||||||
private async _race(promises: Promise<any>[], safe: boolean, defaultValue?: any): Promise<any> {
|
private async _race(promises: Promise<any>[], safe: boolean, defaultValue?: any): Promise<any> {
|
||||||
const terminatePromise = new ManualPromise<Error>();
|
const terminatePromise = new ManualPromise<Error>();
|
||||||
|
const frames = captureRawStack();
|
||||||
if (this._terminateError)
|
if (this._terminateError)
|
||||||
terminatePromise.resolve(this._terminateError);
|
terminatePromise.resolve(this._terminateError);
|
||||||
if (this._terminateErrorMessage)
|
if (this._closeError)
|
||||||
terminatePromise.resolve(new Error(this._terminateErrorMessage));
|
terminatePromise.resolve(cloneError(this._closeError, frames));
|
||||||
this._terminatePromises.set(terminatePromise, captureRawStack());
|
this._terminatePromises.set(terminatePromise, frames);
|
||||||
try {
|
try {
|
||||||
return await Promise.race([
|
return await Promise.race([
|
||||||
terminatePromise.then(e => safe ? defaultValue : Promise.reject(e)),
|
terminatePromise.then(e => safe ? defaultValue : Promise.reject(e)),
|
||||||
@ -112,3 +110,11 @@ export class LongStandingScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cloneError(error: Error, frames: string[]) {
|
||||||
|
const clone = new Error();
|
||||||
|
clone.name = error.name;
|
||||||
|
clone.message = error.message;
|
||||||
|
clone.stack = [error.name + ':' + error.message, ...frames].join('\n');
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user