From aba2d31c649a4d5c7e00771d02a92a6b268b8c6d Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Fri, 21 Feb 2025 14:53:27 -0800 Subject: [PATCH] inline factory --- .../src/server/bidi/bidiExecutionContext.ts | 28 +++++++++---------- .../src/server/bidi/bidiPage.ts | 6 ++-- .../src/server/chromium/crExecutionContext.ts | 25 ++++++++--------- .../src/server/chromium/crPage.ts | 12 +++----- packages/playwright-core/src/server/dom.ts | 4 --- .../src/server/electron/electron.ts | 8 ++---- .../src/server/firefox/ffExecutionContext.ts | 25 +++++++---------- .../src/server/firefox/ffPage.ts | 12 ++++---- .../playwright-core/src/server/javascript.ts | 21 ++------------ .../src/server/webkit/wkExecutionContext.ts | 27 ++++++++---------- .../src/server/webkit/wkPage.ts | 10 +++---- .../src/server/webkit/wkWorkers.ts | 4 +-- 12 files changed, 71 insertions(+), 111 deletions(-) diff --git a/packages/playwright-core/src/server/bidi/bidiExecutionContext.ts b/packages/playwright-core/src/server/bidi/bidiExecutionContext.ts index a0ea401ace..20c00dc74f 100644 --- a/packages/playwright-core/src/server/bidi/bidiExecutionContext.ts +++ b/packages/playwright-core/src/server/bidi/bidiExecutionContext.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { assert } from '../../utils'; import { parseEvaluationResultValue } from '../isomorphic/utilityScriptSerializers'; import * as js from '../javascript'; import * as dom from '../dom'; @@ -26,7 +27,6 @@ import type { BidiSession } from './bidiConnection'; export class BidiExecutionContext implements js.ExecutionContextDelegate { private readonly _session: BidiSession; readonly _target: bidi.Script.Target; - private _handleFactory!: js.HandleFactory; constructor(session: BidiSession, realmInfo: bidi.Script.RealmInfo) { this._session = session; @@ -43,10 +43,6 @@ export class BidiExecutionContext implements js.ExecutionContextDelegate { } } - setHandleFactory(handleFactory: js.HandleFactory) { - this._handleFactory = handleFactory; - } - async rawEvaluateJSON(expression: string): Promise { const response = await this._session.send('script.evaluate', { expression, @@ -103,7 +99,7 @@ export class BidiExecutionContext implements js.ExecutionContextDelegate { if (response.type === 'success') { if (returnByValue) return parseEvaluationResultValue(BidiDeserializer.deserialize(response.result)); - return this._createHandle(response.result); + return createHandle(utilityScript._context, response.result); } throw new js.JavaScriptErrorInEvaluate('Unexpected response type: ' + JSON.stringify(response)); } @@ -143,11 +139,11 @@ export class BidiExecutionContext implements js.ExecutionContextDelegate { }; } - async remoteObjectForNodeId(nodeId: bidi.Script.SharedReference): Promise { + async remoteObjectForNodeId(context: dom.FrameExecutionContext, nodeId: bidi.Script.SharedReference): Promise { const result = await this._remoteValueForReference(nodeId); if (!('handle' in result)) throw new Error('Can\'t get remote object for nodeId'); - return this._createHandle(result); + return createHandle(context, result); } async contentFrameIdForFrame(handle: dom.ElementHandle) { @@ -186,13 +182,6 @@ export class BidiExecutionContext implements js.ExecutionContextDelegate { return response.result; throw new js.JavaScriptErrorInEvaluate('Unexpected response type: ' + JSON.stringify(response)); } - - _createHandle(remoteObject: bidi.Script.RemoteValue): js.JSHandle { - if (remoteObject.type === 'node') - return this._handleFactory.createElementHandle(remoteObject.handle!); - const objectId = 'handle' in remoteObject ? remoteObject.handle : undefined; - return this._handleFactory.createJSHandle(remoteObject.type, renderPreview(remoteObject), objectId, remoteObjectValue(remoteObject)); - } } function renderPreview(remoteObject: bidi.Script.RemoteValue): string | undefined { @@ -216,3 +205,12 @@ function remoteObjectValue(remoteObject: bidi.Script.RemoteValue): any { return remoteObject.value; return undefined; } + +export function createHandle(context: js.ExecutionContext, remoteObject: bidi.Script.RemoteValue): js.JSHandle { + if (remoteObject.type === 'node') { + assert(context instanceof dom.FrameExecutionContext); + return new dom.ElementHandle(context, remoteObject.handle!); + } + const objectId = 'handle' in remoteObject ? remoteObject.handle : undefined; + return new js.JSHandle(context, remoteObject.type, renderPreview(remoteObject), objectId, remoteObjectValue(remoteObject)); +} diff --git a/packages/playwright-core/src/server/bidi/bidiPage.ts b/packages/playwright-core/src/server/bidi/bidiPage.ts index f356cb0d2a..33e3f58931 100644 --- a/packages/playwright-core/src/server/bidi/bidiPage.ts +++ b/packages/playwright-core/src/server/bidi/bidiPage.ts @@ -20,7 +20,7 @@ import { BrowserContext } from '../browserContext'; import * as dialog from '../dialog'; import * as dom from '../dom'; import { Page } from '../page'; -import { BidiExecutionContext } from './bidiExecutionContext'; +import { BidiExecutionContext, createHandle } from './bidiExecutionContext'; import { RawKeyboardImpl, RawMouseImpl, RawTouchscreenImpl } from './bidiInput'; import { BidiNetworkManager } from './bidiNetworkManager'; import { BidiPDF } from './bidiPdf'; @@ -242,7 +242,7 @@ export class BidiPage implements PageDelegate { return; const callFrame = params.stackTrace?.callFrames[0]; const location = callFrame ?? { url: '', lineNumber: 1, columnNumber: 1 }; - this._page._addConsoleMessage(entry.method, entry.args.map(arg => toBidiExecutionContext(context)._createHandle(arg)), location, params.text || undefined); + this._page._addConsoleMessage(entry.method, entry.args.map(arg => createHandle(context, arg)), location, params.text || undefined); } async navigateFrame(frame: frames.Frame, url: string, referrer: string | undefined): Promise { @@ -528,7 +528,7 @@ export class BidiPage implements PageDelegate { const fromContext = toBidiExecutionContext(handle._context); const nodeId = await fromContext.nodeIdForElementHandle(handle); const executionContext = toBidiExecutionContext(to); - return await executionContext.remoteObjectForNodeId(nodeId) as dom.ElementHandle; + return await executionContext.remoteObjectForNodeId(to, nodeId) as dom.ElementHandle; } async getAccessibilityTree(needle?: dom.ElementHandle): Promise<{tree: accessibility.AXNode, needle: accessibility.AXNode | null}> { diff --git a/packages/playwright-core/src/server/chromium/crExecutionContext.ts b/packages/playwright-core/src/server/chromium/crExecutionContext.ts index b5a3a3d3a0..117d53ed53 100644 --- a/packages/playwright-core/src/server/chromium/crExecutionContext.ts +++ b/packages/playwright-core/src/server/chromium/crExecutionContext.ts @@ -15,10 +15,12 @@ * limitations under the License. */ +import { assert } from '../../utils/isomorphic/assert'; import { getExceptionMessage, releaseObject } from './crProtocolHelper'; import { rewriteErrorMessage } from '../../utils/isomorphic/stackTrace'; import { parseEvaluationResultValue } from '../isomorphic/utilityScriptSerializers'; import * as js from '../javascript'; +import * as dom from '../dom'; import { isSessionClosedError } from '../protocolError'; import type { CRSession } from './crConnection'; @@ -27,17 +29,12 @@ import type { Protocol } from './protocol'; export class CRExecutionContext implements js.ExecutionContextDelegate { _client: CRSession; _contextId: number; - private _handleFactory!: js.HandleFactory; constructor(client: CRSession, contextPayload: Protocol.Runtime.ExecutionContextDescription) { this._client = client; this._contextId = contextPayload.id; } - setHandleFactory(handleFactory: js.HandleFactory) { - this._handleFactory = handleFactory; - } - async rawEvaluateJSON(expression: string): Promise { const { exceptionDetails, result: remoteObject } = await this._client.send('Runtime.evaluate', { expression, @@ -74,7 +71,7 @@ export class CRExecutionContext implements js.ExecutionContextDelegate { }).catch(rewriteError); if (exceptionDetails) throw new js.JavaScriptErrorInEvaluate(getExceptionMessage(exceptionDetails)); - return returnByValue ? parseEvaluationResultValue(remoteObject.value) : this._createHandle(remoteObject); + return returnByValue ? parseEvaluationResultValue(remoteObject.value) : createHandle(utilityScript._context, remoteObject); } async getProperties(context: js.ExecutionContext, object: js.JSHandle): Promise> { @@ -86,17 +83,11 @@ export class CRExecutionContext implements js.ExecutionContextDelegate { for (const property of response.result) { if (!property.enumerable || !property.value) continue; - result.set(property.name, this._createHandle(property.value)); + result.set(property.name, createHandle(object._context, property.value)); } return result; } - _createHandle(remoteObject: Protocol.Runtime.RemoteObject): js.JSHandle { - if (remoteObject.subtype === 'node') - return this._handleFactory.createElementHandle(remoteObject.objectId!); - return this._handleFactory.createJSHandle(remoteObject.subtype || remoteObject.type, renderPreview(remoteObject), remoteObject.objectId, potentiallyUnserializableValue(remoteObject)); - } - async releaseHandle(objectId: js.ObjectId): Promise { await releaseObject(this._client, objectId); } @@ -139,3 +130,11 @@ function renderPreview(object: Protocol.Runtime.RemoteObject): string | undefine return js.sparseArrayToString(object.preview.properties); return object.description; } + +export function createHandle(context: js.ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject): js.JSHandle { + if (remoteObject.subtype === 'node') { + assert(context instanceof dom.FrameExecutionContext); + return new dom.ElementHandle(context, remoteObject.objectId!); + } + return new js.JSHandle(context, remoteObject.subtype || remoteObject.type, renderPreview(remoteObject), remoteObject.objectId, potentiallyUnserializableValue(remoteObject)); +} diff --git a/packages/playwright-core/src/server/chromium/crPage.ts b/packages/playwright-core/src/server/chromium/crPage.ts index ec36bcfdc9..5097bdaf03 100644 --- a/packages/playwright-core/src/server/chromium/crPage.ts +++ b/packages/playwright-core/src/server/chromium/crPage.ts @@ -33,7 +33,7 @@ import { getAccessibilityTree } from './crAccessibility'; import { CRBrowserContext } from './crBrowser'; import { CRCoverage } from './crCoverage'; import { DragManager } from './crDragDrop'; -import { CRExecutionContext } from './crExecutionContext'; +import { createHandle, CRExecutionContext } from './crExecutionContext'; import { RawKeyboardImpl, RawMouseImpl, RawTouchscreenImpl } from './crInput'; import { CRNetworkManager } from './crNetworkManager'; import { CRPDF } from './crPdf'; @@ -736,7 +736,7 @@ class FrameSession { session.on('Target.attachedToTarget', event => this._onAttachedToTarget(event)); session.on('Target.detachedFromTarget', event => this._onDetachedFromTarget(event)); session.on('Runtime.consoleAPICalled', event => { - const args = event.args.map(o => toCRExecutionContext(worker._existingExecutionContext!)._createHandle(o)); + const args = event.args.map(o => createHandle(worker._existingExecutionContext!, o)); this._page._addConsoleMessage(event.type, args, toConsoleMessageLocation(event.stackTrace)); }); session.on('Runtime.exceptionThrown', exception => this._page.emitOnContextOnceInitialized(BrowserContext.Events.PageError, exceptionToError(exception.exceptionDetails), this._page)); @@ -799,7 +799,7 @@ class FrameSession { const context = this._contextIdToContext.get(event.executionContextId); if (!context) return; - const values = event.args.map(arg => toCRExecutionContext(context)._createHandle(arg)); + const values = event.args.map(arg => createHandle(context, arg)); this._page._addConsoleMessage(event.type, values, toConsoleMessageLocation(event.stackTrace)); } @@ -1168,7 +1168,7 @@ class FrameSession { }); if (!result || result.object.subtype === 'null') throw new Error(dom.kUnableToAdoptErrorMessage); - return toCRExecutionContext(to)._createHandle(result.object).asElement()!; + return createHandle(to, result.object).asElement()!; } } @@ -1243,7 +1243,3 @@ function calculateUserAgentMetadata(options: types.BrowserContextOptions) { metadata.architecture = 'arm'; return metadata; } - -function toCRExecutionContext(executionContext: js.ExecutionContext): CRExecutionContext { - return executionContext._delegate as CRExecutionContext; -} diff --git a/packages/playwright-core/src/server/dom.ts b/packages/playwright-core/src/server/dom.ts index 2ad561f042..3366a1a50d 100644 --- a/packages/playwright-core/src/server/dom.ts +++ b/packages/playwright-core/src/server/dom.ts @@ -109,10 +109,6 @@ export class FrameExecutionContext extends js.ExecutionContext { } return this._injectedScriptPromise; } - - override createElementHandle(objectId: js.ObjectId): ElementHandle { - return new ElementHandle(this, objectId); - } } export class ElementHandle extends js.JSHandle { diff --git a/packages/playwright-core/src/server/electron/electron.ts b/packages/playwright-core/src/server/electron/electron.ts index ecff4853ce..c780808c88 100644 --- a/packages/playwright-core/src/server/electron/electron.ts +++ b/packages/playwright-core/src/server/electron/electron.ts @@ -27,7 +27,7 @@ import { eventsHelper } from '../utils/eventsHelper'; import { validateBrowserContextOptions } from '../browserContext'; import { CRBrowser } from '../chromium/crBrowser'; import { CRConnection } from '../chromium/crConnection'; -import { CRExecutionContext } from '../chromium/crExecutionContext'; +import { createHandle, CRExecutionContext } from '../chromium/crExecutionContext'; import { toConsoleMessageLocation } from '../chromium/crProtocolHelper'; import { ConsoleMessage } from '../console'; import { helper } from '../helper'; @@ -116,7 +116,7 @@ export class ElectronApplication extends SdkObject { } if (!this._nodeExecutionContext) return; - const args = event.args.map(arg => toCRExecutionContext(this._nodeExecutionContext!)._createHandle(arg)); + const args = event.args.map(arg => createHandle(this._nodeExecutionContext!, arg)); const message = new ConsoleMessage(null, event.type, undefined, args, toConsoleMessageLocation(event.stackTrace)); this.emit(ElectronApplication.Events.Console, message); } @@ -151,10 +151,6 @@ export class ElectronApplication extends SdkObject { } } -function toCRExecutionContext(executionContext: js.ExecutionContext): CRExecutionContext { - return executionContext._delegate as CRExecutionContext; -} - export class Electron extends SdkObject { constructor(playwright: Playwright) { super(playwright, 'electron'); diff --git a/packages/playwright-core/src/server/firefox/ffExecutionContext.ts b/packages/playwright-core/src/server/firefox/ffExecutionContext.ts index 75a0e6e652..356ff11f24 100644 --- a/packages/playwright-core/src/server/firefox/ffExecutionContext.ts +++ b/packages/playwright-core/src/server/firefox/ffExecutionContext.ts @@ -15,9 +15,11 @@ * limitations under the License. */ +import { assert } from '../../utils/isomorphic/assert'; import { rewriteErrorMessage } from '../../utils/isomorphic/stackTrace'; import { parseEvaluationResultValue } from '../isomorphic/utilityScriptSerializers'; import * as js from '../javascript'; +import * as dom from '../dom'; import { isSessionClosedError } from '../protocolError'; import type { FFSession } from './ffConnection'; @@ -26,17 +28,12 @@ import type { Protocol } from './protocol'; export class FFExecutionContext implements js.ExecutionContextDelegate { _session: FFSession; _executionContextId: string; - private _handleFactory!: js.HandleFactory; constructor(session: FFSession, executionContextId: string) { this._session = session; this._executionContextId = executionContextId; } - setHandleFactory(handleFactory: js.HandleFactory) { - this._handleFactory = handleFactory; - } - async rawEvaluateJSON(expression: string): Promise { const payload = await this._session.send('Runtime.evaluate', { expression, @@ -71,7 +68,7 @@ export class FFExecutionContext implements js.ExecutionContextDelegate { checkException(payload.exceptionDetails); if (returnByValue) return parseEvaluationResultValue(payload.result!.value); - return toFFExecutionContext(utilityScript._context)._createHandle(payload.result!); + return createHandle(utilityScript._context, payload.result!); } async getProperties(context: js.ExecutionContext, object: js.JSHandle): Promise> { @@ -81,16 +78,10 @@ export class FFExecutionContext implements js.ExecutionContextDelegate { }); const result = new Map(); for (const property of response.properties) - result.set(property.name, toFFExecutionContext(context)._createHandle(property.value)); + result.set(property.name, createHandle(context, property.value)); return result; } - _createHandle(remoteObject: Protocol.Runtime.RemoteObject): js.JSHandle { - if (remoteObject.subtype === 'node') - return this._handleFactory.createElementHandle(remoteObject.objectId!); - return this._handleFactory.createJSHandle(remoteObject.subtype || remoteObject.type || '', renderPreview(remoteObject), remoteObject.objectId, potentiallyUnserializableValue(remoteObject)); - } - async releaseHandle(objectId: js.ObjectId): Promise { await this._session.send('Runtime.disposeObject', { executionContextId: this._executionContextId, @@ -143,6 +134,10 @@ function renderPreview(object: Protocol.Runtime.RemoteObject): string | undefine return String(object.value); } -export function toFFExecutionContext(executionContext: js.ExecutionContext): FFExecutionContext { - return executionContext._delegate as FFExecutionContext; +export function createHandle(context: js.ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject): js.JSHandle { + if (remoteObject.subtype === 'node') { + assert(context instanceof dom.FrameExecutionContext); + return new dom.ElementHandle(context, remoteObject.objectId!); + } + return new js.JSHandle(context, remoteObject.subtype || remoteObject.type || '', renderPreview(remoteObject), remoteObject.objectId, potentiallyUnserializableValue(remoteObject)); } diff --git a/packages/playwright-core/src/server/firefox/ffPage.ts b/packages/playwright-core/src/server/firefox/ffPage.ts index e5f7198ef3..16a0562f84 100644 --- a/packages/playwright-core/src/server/firefox/ffPage.ts +++ b/packages/playwright-core/src/server/firefox/ffPage.ts @@ -22,7 +22,7 @@ import { InitScript } from '../page'; import { Page, Worker } from '../page'; import { getAccessibilityTree } from './ffAccessibility'; import { FFSession } from './ffConnection'; -import { FFExecutionContext, toFFExecutionContext } from './ffExecutionContext'; +import { createHandle, FFExecutionContext } from './ffExecutionContext'; import { RawKeyboardImpl, RawMouseImpl, RawTouchscreenImpl } from './ffInput'; import { FFNetworkManager } from './ffNetworkManager'; import { debugLogger } from '../utils/debugLogger'; @@ -234,7 +234,7 @@ export class FFPage implements PageDelegate { if (!context) return; // Juggler reports 'warn' for some internal messages generated by the browser. - this._page._addConsoleMessage(type === 'warn' ? 'warning' : type, args.map(arg => toFFExecutionContext(context)._createHandle(arg)), location); + this._page._addConsoleMessage(type === 'warn' ? 'warning' : type, args.map(arg => createHandle(context, arg)), location); } _onDialogOpened(params: Protocol.Page.dialogOpenedPayload) { @@ -262,7 +262,7 @@ export class FFPage implements PageDelegate { const context = this._contextIdToContext.get(executionContextId); if (!context) return; - const handle = toFFExecutionContext(context)._createHandle(element).asElement()!; + const handle = createHandle(context, element).asElement()!; await this._page._onFileChooserOpened(handle); } @@ -286,7 +286,7 @@ export class FFPage implements PageDelegate { workerSession.on('Runtime.console', event => { const { type, args, location } = event; const context = worker._existingExecutionContext!; - this._page._addConsoleMessage(type, args.map(arg => toFFExecutionContext(context)._createHandle(arg)), location); + this._page._addConsoleMessage(type, args.map(arg => createHandle(context, arg)), location); }); // Note: we receive worker exceptions directly from the page. } @@ -531,7 +531,7 @@ export class FFPage implements PageDelegate { }); if (!result.remoteObject) throw new Error(dom.kUnableToAdoptErrorMessage); - return toFFExecutionContext(to)._createHandle(result.remoteObject) as dom.ElementHandle; + return createHandle(to, result.remoteObject) as dom.ElementHandle; } async getAccessibilityTree(needle?: dom.ElementHandle) { @@ -560,7 +560,7 @@ export class FFPage implements PageDelegate { }); if (!result.remoteObject) throw new Error('Frame has been detached.'); - return toFFExecutionContext(context)._createHandle(result.remoteObject) as dom.ElementHandle; + return createHandle(context, result.remoteObject) as dom.ElementHandle; } shouldToggleStyleSheetToSyncAnimations(): boolean { diff --git a/packages/playwright-core/src/server/javascript.ts b/packages/playwright-core/src/server/javascript.ts index 2019d424a6..7cbadd5bd5 100644 --- a/packages/playwright-core/src/server/javascript.ts +++ b/packages/playwright-core/src/server/javascript.ts @@ -53,25 +53,18 @@ export interface ExecutionContextDelegate { evaluateWithArguments(expression: string, returnByValue: boolean, utilityScript: JSHandle, values: any[], objectIds: ObjectId[]): Promise; getProperties(context: ExecutionContext, object: JSHandle): Promise>; releaseHandle(objectId: ObjectId): Promise; - setHandleFactory(factory: HandleFactory): void; } -export interface HandleFactory { - createElementHandle(objectId: ObjectId): dom.ElementHandle; - createJSHandle(type: string, preview: string | undefined, objectId?: ObjectId, value?: any): JSHandle; -} - -export class ExecutionContext extends SdkObject implements HandleFactory { - _delegate: ExecutionContextDelegate; +export class ExecutionContext extends SdkObject { + private _delegate: ExecutionContextDelegate; private _utilityScriptPromise: Promise | undefined; private _contextDestroyedScope = new LongStandingScope(); readonly worldNameForTest: string; - constructor(parent: SdkObject, delegate: ExecutionContextDelegate, worldNameForTest: string, handleFactory?: HandleFactory) { + constructor(parent: SdkObject, delegate: ExecutionContextDelegate, worldNameForTest: string) { super(parent, 'execution-context'); this.worldNameForTest = worldNameForTest; this._delegate = delegate; - delegate.setHandleFactory(this); } contextDestroyed(reason: string) { @@ -123,14 +116,6 @@ export class ExecutionContext extends SdkObject implements HandleFactory { async doSlowMo() { // overridden in FrameExecutionContext } - - createElementHandle(objectId: string): dom.ElementHandle { - throw new Error('Not supported'); - } - - createJSHandle(type: string, preview: string | undefined, objectId?: ObjectId, value?: any): JSHandle { - return new JSHandle(this, type, preview, objectId, value); - } } export class JSHandle extends SdkObject { diff --git a/packages/playwright-core/src/server/webkit/wkExecutionContext.ts b/packages/playwright-core/src/server/webkit/wkExecutionContext.ts index 06ea3f523d..366d227035 100644 --- a/packages/playwright-core/src/server/webkit/wkExecutionContext.ts +++ b/packages/playwright-core/src/server/webkit/wkExecutionContext.ts @@ -17,7 +17,9 @@ import { parseEvaluationResultValue } from '../isomorphic/utilityScriptSerializers'; import * as js from '../javascript'; +import * as dom from '../dom'; import { isSessionClosedError } from '../protocolError'; +import { assert } from '../../utils/isomorphic/assert'; import type { Protocol } from './protocol'; import type { WKSession } from './wkConnection'; @@ -25,17 +27,12 @@ import type { WKSession } from './wkConnection'; export class WKExecutionContext implements js.ExecutionContextDelegate { private readonly _session: WKSession; readonly _contextId: number | undefined; - private _handleFactory!: js.HandleFactory; constructor(session: WKSession, contextId: number | undefined) { this._session = session; this._contextId = contextId; } - setHandleFactory(handleFactory: js.HandleFactory) { - this._handleFactory = handleFactory; - } - async rawEvaluateJSON(expression: string): Promise { try { const response = await this._session.send('Runtime.evaluate', { @@ -84,7 +81,7 @@ export class WKExecutionContext implements js.ExecutionContextDelegate { throw new js.JavaScriptErrorInEvaluate(response.result.description); if (returnByValue) return parseEvaluationResultValue(response.result.value); - return toWKExecutionContext(utilityScript._context)._createHandle(response.result); + return createHandle(utilityScript._context, response.result); } catch (error) { throw rewriteError(error); } @@ -99,18 +96,11 @@ export class WKExecutionContext implements js.ExecutionContextDelegate { for (const property of response.properties) { if (!property.enumerable || !property.value) continue; - result.set(property.name, toWKExecutionContext(context)._createHandle(property.value)); + result.set(property.name, createHandle(context, property.value)); } return result; } - _createHandle(remoteObject: Protocol.Runtime.RemoteObject): js.JSHandle { - if (remoteObject.subtype === 'node') - return this._handleFactory.createElementHandle(remoteObject.objectId!); - const isPromise = remoteObject.className === 'Promise'; - return this._handleFactory.createJSHandle(isPromise ? 'promise' : remoteObject.subtype || remoteObject.type, renderPreview(remoteObject), remoteObject.objectId, potentiallyUnserializableValue(remoteObject)); - } - async releaseHandle(objectId: js.ObjectId): Promise { await this._session.send('Runtime.releaseObject', { objectId }); } @@ -147,6 +137,11 @@ function renderPreview(object: Protocol.Runtime.RemoteObject): string | undefine return object.description; } -export function toWKExecutionContext(executionContext: js.ExecutionContext): WKExecutionContext { - return executionContext._delegate as WKExecutionContext; +export function createHandle(context: js.ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject): js.JSHandle { + if (remoteObject.subtype === 'node') { + assert(context instanceof dom.FrameExecutionContext); + return new dom.ElementHandle(context as dom.FrameExecutionContext, remoteObject.objectId!); + } + const isPromise = remoteObject.className === 'Promise'; + return new js.JSHandle(context, isPromise ? 'promise' : remoteObject.subtype || remoteObject.type, renderPreview(remoteObject), remoteObject.objectId, potentiallyUnserializableValue(remoteObject)); } diff --git a/packages/playwright-core/src/server/webkit/wkPage.ts b/packages/playwright-core/src/server/webkit/wkPage.ts index 0b7fb80b49..0e57b0f6a9 100644 --- a/packages/playwright-core/src/server/webkit/wkPage.ts +++ b/packages/playwright-core/src/server/webkit/wkPage.ts @@ -34,7 +34,7 @@ import { PageBinding } from '../page'; import { Page } from '../page'; import { getAccessibilityTree } from './wkAccessibility'; import { WKSession } from './wkConnection'; -import { toWKExecutionContext, WKExecutionContext } from './wkExecutionContext'; +import { createHandle, WKExecutionContext } from './wkExecutionContext'; import { RawKeyboardImpl, RawMouseImpl, RawTouchscreenImpl } from './wkInput'; import { WKInterceptableRequest, WKRouteImpl } from './wkInterceptableRequest'; import { WKProvisionalPage } from './wkProvisionalPage'; @@ -562,7 +562,7 @@ export class WKPage implements PageDelegate { } if (!context) return; - handles.push(toWKExecutionContext(context)._createHandle(p)); + handles.push(createHandle(context, p)); } this._lastConsoleMessage = { derivedType, @@ -611,7 +611,7 @@ export class WKPage implements PageDelegate { let handle; try { const context = await this._page._frameManager.frame(event.frameId)!._mainContext(); - handle = toWKExecutionContext(context)._createHandle(event.element).asElement()!; + handle = createHandle(context, event.element).asElement()!; } catch (e) { // During async processing, frame/context may go away. We should not throw. return; @@ -958,7 +958,7 @@ export class WKPage implements PageDelegate { }); if (!result || result.object.subtype === 'null') throw new Error(dom.kUnableToAdoptErrorMessage); - return toWKExecutionContext(to)._createHandle(result.object) as dom.ElementHandle; + return createHandle(to, result.object) as dom.ElementHandle; } async getAccessibilityTree(needle?: dom.ElementHandle): Promise<{tree: accessibility.AXNode, needle: accessibility.AXNode | null}> { @@ -982,7 +982,7 @@ export class WKPage implements PageDelegate { }); if (!result || result.object.subtype === 'null') throw new Error('Frame has been detached.'); - return toWKExecutionContext(context)._createHandle(result.object) as dom.ElementHandle; + return createHandle(context, result.object) as dom.ElementHandle; } private _maybeCancelCoopNavigationRequest(provisionalPage: WKProvisionalPage) { diff --git a/packages/playwright-core/src/server/webkit/wkWorkers.ts b/packages/playwright-core/src/server/webkit/wkWorkers.ts index 8a094f34e6..dc7c633433 100644 --- a/packages/playwright-core/src/server/webkit/wkWorkers.ts +++ b/packages/playwright-core/src/server/webkit/wkWorkers.ts @@ -17,7 +17,7 @@ import { eventsHelper } from '../utils/eventsHelper'; import { Worker } from '../page'; import { WKSession } from './wkConnection'; -import { toWKExecutionContext, WKExecutionContext } from './wkExecutionContext'; +import { createHandle, WKExecutionContext } from './wkExecutionContext'; import type { Protocol } from './protocol'; import type { RegisteredListener } from '../utils/eventsHelper'; @@ -95,7 +95,7 @@ export class WKWorkers { derivedType = 'timeEnd'; const handles = (parameters || []).map(p => { - return toWKExecutionContext(worker._existingExecutionContext!)._createHandle(p); + return createHandle(worker._existingExecutionContext!, p); }); const location: types.ConsoleMessageLocation = { url: url || '',