diff --git a/packages/playwright-core/src/cli/program.ts b/packages/playwright-core/src/cli/program.ts index 8616e3bbcd..dc3825feca 100644 --- a/packages/playwright-core/src/cli/program.ts +++ b/packages/playwright-core/src/cli/program.ts @@ -34,7 +34,7 @@ import { spawn } from 'child_process'; import { wrapInASCIIBox, isLikelyNpxGlobal, assert, gracefullyProcessExitDoNotHang, getPackageManagerExecCommand } from '../utils'; import type { Executable } from '../server'; import { registry, writeDockerVersion } from '../server'; -import { isTargetClosedError } from '../common/errors'; +import { isTargetClosedError } from '../client/errors'; const packageJSON = require('../../package.json'); diff --git a/packages/playwright-core/src/client/android.ts b/packages/playwright-core/src/client/android.ts index 8a9f1549d8..395fbda6c7 100644 --- a/packages/playwright-core/src/client/android.ts +++ b/packages/playwright-core/src/client/android.ts @@ -27,7 +27,7 @@ import { TimeoutSettings } from '../common/timeoutSettings'; import { Waiter } from './waiter'; import { EventEmitter } from 'events'; import { Connection } from './connection'; -import { isTargetClosedError, TargetClosedError } from '../common/errors'; +import { isTargetClosedError, TargetClosedError } from './errors'; import { raceAgainstDeadline } from '../utils/timeoutRunner'; import type { AndroidServerLauncherImpl } from '../androidServerImpl'; diff --git a/packages/playwright-core/src/client/api.ts b/packages/playwright-core/src/client/api.ts index 03d54c92d7..b41a85b854 100644 --- a/packages/playwright-core/src/client/api.ts +++ b/packages/playwright-core/src/client/api.ts @@ -29,7 +29,7 @@ export { Locator, FrameLocator } from './locator'; export { ElementHandle } from './elementHandle'; export { FileChooser } from './fileChooser'; export type { Logger } from './types'; -export { TimeoutError } from '../common/errors'; +export { TimeoutError } from './errors'; export { Frame } from './frame'; export { Keyboard, Mouse, Touchscreen } from './input'; export { JSHandle } from './jsHandle'; diff --git a/packages/playwright-core/src/client/browser.ts b/packages/playwright-core/src/client/browser.ts index f06e739799..0df8c73efb 100644 --- a/packages/playwright-core/src/client/browser.ts +++ b/packages/playwright-core/src/client/browser.ts @@ -21,7 +21,7 @@ import type { Page } from './page'; import { ChannelOwner } from './channelOwner'; import { Events } from './events'; import type { LaunchOptions, BrowserContextOptions, HeadersArray } from './types'; -import { isTargetClosedError } from '../common/errors'; +import { isTargetClosedError } from './errors'; import type * as api from '../../types/types'; import { CDPSession } from './cdpSession'; import type { BrowserType } from './browserType'; diff --git a/packages/playwright-core/src/client/browserContext.ts b/packages/playwright-core/src/client/browserContext.ts index b347dff782..10f9d82492 100644 --- a/packages/playwright-core/src/client/browserContext.ts +++ b/packages/playwright-core/src/client/browserContext.ts @@ -43,8 +43,7 @@ import { HarRouter } from './harRouter'; import { ConsoleMessage } from './consoleMessage'; import { Dialog } from './dialog'; import { WebError } from './webError'; -import { parseError } from '../protocol/serializers'; -import { TargetClosedError } from '../common/errors'; +import { TargetClosedError, parseError } from './errors'; export class BrowserContext extends ChannelOwner implements api.BrowserContext { _pages = new Set(); diff --git a/packages/playwright-core/src/client/connection.ts b/packages/playwright-core/src/client/connection.ts index 380ce04b9b..e7805e5243 100644 --- a/packages/playwright-core/src/client/connection.ts +++ b/packages/playwright-core/src/client/connection.ts @@ -25,7 +25,7 @@ import { Request, Response, Route, WebSocket } from './network'; import { Page, BindingCall } from './page'; import { Worker } from './worker'; import { Dialog } from './dialog'; -import { parseError } from '../protocol/serializers'; +import { parseError, TargetClosedError } from './errors'; import { CDPSession } from './cdpSession'; import { Playwright } from './playwright'; import { Electron, ElectronApplication } from './electron'; @@ -44,7 +44,6 @@ import { Tracing } from './tracing'; import { findValidator, ValidationError, type ValidatorContext } from '../protocol/validator'; import { createInstrumentation } from './clientInstrumentation'; import type { ClientInstrumentation } from './clientInstrumentation'; -import { TargetClosedError } from '../common/errors'; import { formatCallLog, rewriteErrorMessage } from '../utils'; class Root extends ChannelOwner { diff --git a/packages/playwright-core/src/client/electron.ts b/packages/playwright-core/src/client/electron.ts index 103ef5c193..5a05711f80 100644 --- a/packages/playwright-core/src/client/electron.ts +++ b/packages/playwright-core/src/client/electron.ts @@ -28,7 +28,7 @@ import { JSHandle, parseResult, serializeArgument } from './jsHandle'; import type { Page } from './page'; import type { Env, WaitForEventOptions, Headers, BrowserContextOptions } from './types'; import { Waiter } from './waiter'; -import { TargetClosedError } from '../common/errors'; +import { TargetClosedError } from './errors'; type ElectronOptions = Omit & { env?: Env, diff --git a/packages/playwright-core/src/client/errors.ts b/packages/playwright-core/src/client/errors.ts new file mode 100644 index 0000000000..06446ba3b6 --- /dev/null +++ b/packages/playwright-core/src/client/errors.ts @@ -0,0 +1,59 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { SerializedError } from '@protocol/channels'; +import { isError } from '../utils'; +import { parseSerializedValue, serializeValue } from '../protocol/serializers'; + +export class TimeoutError extends Error {} + +export class TargetClosedError extends Error { + constructor(cause?: string) { + super(cause || 'Target page, context or browser has been closed'); + } +} + +export function isTargetClosedError(error: Error) { + return error instanceof TargetClosedError; +} + +export function serializeError(e: any): SerializedError { + if (isError(e)) + return { error: { message: e.message, stack: e.stack, name: e.name } }; + return { value: serializeValue(e, value => ({ fallThrough: value })) }; +} + +export function parseError(error: SerializedError): Error { + if (!error.error) { + if (error.value === undefined) + throw new Error('Serialized error must have either an error or a value'); + return parseSerializedValue(error.value, undefined); + } + if (error.error.name === 'TimeoutError') { + const e = new TimeoutError(error.error.message); + e.stack = error.error.stack || ''; + 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); + e.stack = error.error.stack || ''; + e.name = error.error.name; + return e; +} diff --git a/packages/playwright-core/src/client/fetch.ts b/packages/playwright-core/src/client/fetch.ts index 307b92f3c3..45dca29720 100644 --- a/packages/playwright-core/src/client/fetch.ts +++ b/packages/playwright-core/src/client/fetch.ts @@ -28,7 +28,7 @@ import { RawHeaders } from './network'; import type { FilePayload, Headers, StorageState } from './types'; import type { Playwright } from './playwright'; import { Tracing } from './tracing'; -import { isTargetClosedError } from '../common/errors'; +import { isTargetClosedError } from './errors'; export type FetchOptions = { params?: { [key: string]: string; }, diff --git a/packages/playwright-core/src/client/page.ts b/packages/playwright-core/src/client/page.ts index afa70e1806..61e20bb28e 100644 --- a/packages/playwright-core/src/client/page.ts +++ b/packages/playwright-core/src/client/page.ts @@ -19,11 +19,10 @@ import fs from 'fs'; import path from 'path'; import type * as structs from '../../types/structs'; import type * as api from '../../types/types'; -import { isTargetClosedError, TargetClosedError } from '../common/errors'; +import { serializeError, isTargetClosedError, TargetClosedError } from './errors'; import { urlMatches } from '../utils/network'; import { TimeoutSettings } from '../common/timeoutSettings'; import type * as channels from '@protocol/channels'; -import { serializeError } from '../protocol/serializers'; import { assert, headersObjectToArray, isObject, isRegExp, isString, LongStandingScope, urlMatchesEqual } from '../utils'; import { mkdirIfNeeded } from '../utils/fileUtils'; import { Accessibility } from './accessibility'; diff --git a/packages/playwright-core/src/client/playwright.ts b/packages/playwright-core/src/client/playwright.ts index 0dd6e03cb2..593e0bd49f 100644 --- a/packages/playwright-core/src/client/playwright.ts +++ b/packages/playwright-core/src/client/playwright.ts @@ -15,7 +15,7 @@ */ import type * as channels from '@protocol/channels'; -import { TimeoutError } from '../common/errors'; +import { TimeoutError } from './errors'; import { Android } from './android'; import { BrowserType } from './browserType'; import { ChannelOwner } from './channelOwner'; diff --git a/packages/playwright-core/src/client/waiter.ts b/packages/playwright-core/src/client/waiter.ts index c88192868c..dbdefc5888 100644 --- a/packages/playwright-core/src/client/waiter.ts +++ b/packages/playwright-core/src/client/waiter.ts @@ -16,7 +16,7 @@ import type { EventEmitter } from 'events'; import { rewriteErrorMessage } from '../utils/stackTrace'; -import { TimeoutError } from '../common/errors'; +import { TimeoutError } from './errors'; import { createGuid } from '../utils'; import type * as channels from '@protocol/channels'; import type { ChannelOwner } from './channelOwner'; diff --git a/packages/playwright-core/src/client/worker.ts b/packages/playwright-core/src/client/worker.ts index 1429fcdcc1..31d5d3057f 100644 --- a/packages/playwright-core/src/client/worker.ts +++ b/packages/playwright-core/src/client/worker.ts @@ -23,7 +23,7 @@ import type { BrowserContext } from './browserContext'; import type * as api from '../../types/types'; import type * as structs from '../../types/structs'; import { LongStandingScope } from '../utils'; -import { TargetClosedError } from '../common/errors'; +import { TargetClosedError } from './errors'; export class Worker extends ChannelOwner implements api.Worker { _page: Page | undefined; // Set for web workers. diff --git a/packages/playwright-core/src/protocol/serializers.ts b/packages/playwright-core/src/protocol/serializers.ts index 92d584da38..b6880572b7 100644 --- a/packages/playwright-core/src/protocol/serializers.ts +++ b/packages/playwright-core/src/protocol/serializers.ts @@ -14,36 +14,7 @@ * limitations under the License. */ -import { TargetClosedError, TimeoutError } from '../common/errors'; -import type { SerializedError, SerializedValue } from '@protocol/channels'; - -export function serializeError(e: any): SerializedError { - if (isError(e)) - return { error: { message: e.message, stack: e.stack, name: e.name } }; - return { value: serializeValue(e, value => ({ fallThrough: value })) }; -} - -export function parseError(error: SerializedError): Error { - if (!error.error) { - if (error.value === undefined) - throw new Error('Serialized error must have either an error or a value'); - return parseSerializedValue(error.value, undefined); - } - if (error.error.name === 'TimeoutError') { - const e = new TimeoutError(error.error.message); - e.stack = error.error.stack || ''; - 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); - e.stack = error.error.stack || ''; - e.name = error.error.name; - return e; -} +import type { SerializedValue } from '@protocol/channels'; export function parseSerializedValue(value: SerializedValue, handles: any[] | undefined): any { return innerParseSerializedValue(value, handles, new Map()); diff --git a/packages/playwright-core/src/server/artifact.ts b/packages/playwright-core/src/server/artifact.ts index f82d092211..8824365b80 100644 --- a/packages/playwright-core/src/server/artifact.ts +++ b/packages/playwright-core/src/server/artifact.ts @@ -18,7 +18,7 @@ import fs from 'fs'; import { assert } from '../utils'; import { ManualPromise } from '../utils/manualPromise'; import { SdkObject } from './instrumentation'; -import { TargetClosedError } from '../common/errors'; +import { TargetClosedError } from './errors'; type SaveCallback = (localPath: string, error?: Error) => Promise; type CancelCallback = () => Promise; diff --git a/packages/playwright-core/src/server/chromium/crPage.ts b/packages/playwright-core/src/server/chromium/crPage.ts index 65c05700b1..fc6a02e29f 100644 --- a/packages/playwright-core/src/server/chromium/crPage.ts +++ b/packages/playwright-core/src/server/chromium/crPage.ts @@ -45,7 +45,7 @@ import { platformToFontFamilies } from './defaultFontFamilies'; import type { Protocol } from './protocol'; import { VideoRecorder } from './videoRecorder'; import { BrowserContext } from '../browserContext'; -import { TargetClosedError } from '../../common/errors'; +import { TargetClosedError } from '../errors'; const UTILITY_WORLD_NAME = '__playwright_utility_world__'; diff --git a/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts b/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts index bcfa3e7822..715865e613 100644 --- a/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts @@ -37,7 +37,7 @@ import { DialogDispatcher } from './dialogDispatcher'; import type { Page } from '../page'; import type { Dialog } from '../dialog'; import type { ConsoleMessage } from '../console'; -import { serializeError } from '../../protocol/serializers'; +import { serializeError } from '../errors'; import { ElementHandleDispatcher } from './elementHandlerDispatcher'; export class BrowserContextDispatcher extends Dispatcher implements channels.BrowserContextChannel { diff --git a/packages/playwright-core/src/server/dispatchers/dispatcher.ts b/packages/playwright-core/src/server/dispatchers/dispatcher.ts index 36f39704a7..c2facfa457 100644 --- a/packages/playwright-core/src/server/dispatchers/dispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/dispatcher.ts @@ -16,10 +16,9 @@ import { EventEmitter } from 'events'; import type * as channels from '@protocol/channels'; -import { serializeError } from '../../protocol/serializers'; import { findValidator, ValidationError, createMetadataValidator, type ValidatorContext } from '../../protocol/validator'; import { assert, isUnderTest, monotonicTime, rewriteErrorMessage } from '../../utils'; -import { TargetClosedError, isTargetClosedError } from '../../common/errors'; +import { TargetClosedError, isTargetClosedError, serializeError } from '../errors'; import type { CallMetadata } from '../instrumentation'; import { SdkObject } from '../instrumentation'; import type { PlaywrightDispatcher } from './playwrightDispatcher'; diff --git a/packages/playwright-core/src/server/dispatchers/jsonPipeDispatcher.ts b/packages/playwright-core/src/server/dispatchers/jsonPipeDispatcher.ts index 914879adc3..952e52c66f 100644 --- a/packages/playwright-core/src/server/dispatchers/jsonPipeDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/jsonPipeDispatcher.ts @@ -17,7 +17,7 @@ import type * as channels from '@protocol/channels'; import { Dispatcher } from './dispatcher'; import { createGuid } from '../../utils'; -import { serializeError } from '../../protocol/serializers'; +import { serializeError } from '../errors'; import type { LocalUtilsDispatcher } from './localUtilsDispatcher'; export class JsonPipeDispatcher extends Dispatcher<{ guid: string }, channels.JsonPipeChannel, LocalUtilsDispatcher> implements channels.JsonPipeChannel { diff --git a/packages/playwright-core/src/server/dispatchers/pageDispatcher.ts b/packages/playwright-core/src/server/dispatchers/pageDispatcher.ts index 2a40a27d18..6689ff218c 100644 --- a/packages/playwright-core/src/server/dispatchers/pageDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/pageDispatcher.ts @@ -19,7 +19,7 @@ import type { Frame } from '../frames'; import { Page, Worker } from '../page'; import type * as channels from '@protocol/channels'; import { Dispatcher, existingDispatcher } from './dispatcher'; -import { parseError } from '../../protocol/serializers'; +import { parseError } from '../errors'; import { FrameDispatcher } from './frameDispatcher'; import { RequestDispatcher } from './networkDispatchers'; import { ResponseDispatcher } from './networkDispatchers'; diff --git a/packages/playwright-core/src/common/errors.ts b/packages/playwright-core/src/server/errors.ts similarity index 51% rename from packages/playwright-core/src/common/errors.ts rename to packages/playwright-core/src/server/errors.ts index b8e6c9b11f..c3a63cb033 100644 --- a/packages/playwright-core/src/common/errors.ts +++ b/packages/playwright-core/src/server/errors.ts @@ -1,12 +1,11 @@ /** - * Copyright 2018 Google Inc. All rights reserved. - * Modifications copyright (c) Microsoft Corporation. + * Copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,23 +14,43 @@ * limitations under the License. */ +import type { SerializedError } from '@protocol/channels'; +import { isError } from '../utils'; +import { parseSerializedValue, serializeValue } from '../protocol/serializers'; + class CustomError extends Error { constructor(message: string) { super(message); this.name = this.constructor.name; - Error.captureStackTrace(this, this.constructor); } } export class TimeoutError extends CustomError {} -export class TargetClosedError extends Error { +export class TargetClosedError extends CustomError { constructor(cause?: string, logs?: string) { super((cause || 'Target page, context or browser has been closed') + (logs || '')); - this.name = this.constructor.name; } } export function isTargetClosedError(error: Error) { return error instanceof TargetClosedError || error.name === 'TargetClosedError'; } + +export function serializeError(e: any): SerializedError { + if (isError(e)) + return { error: { message: e.message, stack: e.stack, name: e.name } }; + return { value: serializeValue(e, value => ({ fallThrough: value })) }; +} + +export function parseError(error: SerializedError): Error { + if (!error.error) { + if (error.value === undefined) + throw new Error('Serialized error must have either an error or a value'); + return parseSerializedValue(error.value, undefined); + } + const e = new Error(error.error.message); + e.stack = error.error.stack || ''; + e.name = error.error.name; + return e; +} diff --git a/packages/playwright-core/src/server/firefox/ffBrowser.ts b/packages/playwright-core/src/server/firefox/ffBrowser.ts index 38233ea3dc..ab2f7f894e 100644 --- a/packages/playwright-core/src/server/firefox/ffBrowser.ts +++ b/packages/playwright-core/src/server/firefox/ffBrowser.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { TargetClosedError } from '../../common/errors'; +import { TargetClosedError } from '../errors'; import { assert } from '../../utils'; import type { BrowserOptions } from '../browser'; import { Browser } from '../browser'; diff --git a/packages/playwright-core/src/server/firefox/ffPage.ts b/packages/playwright-core/src/server/firefox/ffPage.ts index 51182b9441..389c24ccfd 100644 --- a/packages/playwright-core/src/server/firefox/ffPage.ts +++ b/packages/playwright-core/src/server/firefox/ffPage.ts @@ -35,7 +35,7 @@ import { splitErrorMessage } from '../../utils/stackTrace'; import { debugLogger } from '../../common/debugLogger'; import { ManualPromise } from '../../utils/manualPromise'; import { BrowserContext } from '../browserContext'; -import { TargetClosedError } from '../../common/errors'; +import { TargetClosedError } from '../errors'; export const UTILITY_WORLD_NAME = '__playwright_utility_world__'; diff --git a/packages/playwright-core/src/server/frames.ts b/packages/playwright-core/src/server/frames.ts index f367957502..488a30fbab 100644 --- a/packages/playwright-core/src/server/frames.ts +++ b/packages/playwright-core/src/server/frames.ts @@ -41,7 +41,7 @@ import type { ScreenshotOptions } from './screenshotter'; import type { InputFilesItems } from './dom'; import { asLocator } from '../utils/isomorphic/locatorGenerators'; import { FrameSelectors } from './frameSelectors'; -import { TimeoutError } from '../common/errors'; +import { TimeoutError } from './errors'; type ContextData = { contextPromise: ManualPromise; diff --git a/packages/playwright-core/src/server/page.ts b/packages/playwright-core/src/server/page.ts index 9f29478318..da84d32385 100644 --- a/packages/playwright-core/src/server/page.ts +++ b/packages/playwright-core/src/server/page.ts @@ -43,7 +43,7 @@ import type { TimeoutOptions } from '../common/types'; import { isInvalidSelectorError } from '../utils/isomorphic/selectorParser'; import { parseEvaluationResultValue, source } from './isomorphic/utilityScriptSerializers'; import type { SerializedValue } from './isomorphic/utilityScriptSerializers'; -import { TargetClosedError } from '../common/errors'; +import { TargetClosedError } from './errors'; export interface PageDelegate { readonly rawMouse: input.RawMouse; diff --git a/packages/playwright-core/src/server/progress.ts b/packages/playwright-core/src/server/progress.ts index 94e7cdf1ff..094230a7c0 100644 --- a/packages/playwright-core/src/server/progress.ts +++ b/packages/playwright-core/src/server/progress.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { TimeoutError } from '../common/errors'; +import { TimeoutError } from './errors'; import { assert, monotonicTime } from '../utils'; import type { LogName } from '../common/debugLogger'; import type { CallMetadata, Instrumentation, SdkObject } from './instrumentation'; diff --git a/packages/playwright-core/src/server/webkit/wkBrowser.ts b/packages/playwright-core/src/server/webkit/wkBrowser.ts index db452a21dc..f195a73196 100644 --- a/packages/playwright-core/src/server/webkit/wkBrowser.ts +++ b/packages/playwright-core/src/server/webkit/wkBrowser.ts @@ -30,7 +30,7 @@ import type { Protocol } from './protocol'; import type { PageProxyMessageReceivedPayload } from './wkConnection'; import { kPageProxyMessageReceived, WKConnection, WKSession } from './wkConnection'; import { WKPage } from './wkPage'; -import { TargetClosedError } from '../../common/errors'; +import { TargetClosedError } from '../errors'; import type { SdkObject } from '../instrumentation'; const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15'; diff --git a/packages/playwright-core/src/server/webkit/wkPage.ts b/packages/playwright-core/src/server/webkit/wkPage.ts index d1197d7caf..1ae8d23082 100644 --- a/packages/playwright-core/src/server/webkit/wkPage.ts +++ b/packages/playwright-core/src/server/webkit/wkPage.ts @@ -45,7 +45,7 @@ import { WKWorkers } from './wkWorkers'; import { debugLogger } from '../../common/debugLogger'; import { ManualPromise } from '../../utils/manualPromise'; import { BrowserContext } from '../browserContext'; -import { TargetClosedError } from '../../common/errors'; +import { TargetClosedError } from '../errors'; const UTILITY_WORLD_NAME = '__playwright_utility_world__';