diff --git a/src/chromium/ExecutionContext.ts b/src/chromium/ExecutionContext.ts index fd8833a892..89d69a952d 100644 --- a/src/chromium/ExecutionContext.ts +++ b/src/chromium/ExecutionContext.ts @@ -20,7 +20,6 @@ import { helper } from '../helper'; import { valueFromRemoteObject, getExceptionMessage, releaseObject } from './protocolHelper'; import { Protocol } from './protocol'; import * as js from '../javascript'; -import * as dom from '../dom'; export const EVALUATION_SCRIPT_URL = '__playwright_evaluation_script__'; const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m; @@ -50,7 +49,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { }).catch(rewriteError); if (exceptionDetails) throw new Error('Evaluation failed: ' + getExceptionMessage(exceptionDetails)); - return returnByValue ? valueFromRemoteObject(remoteObject) : toHandle(context, remoteObject); + return returnByValue ? valueFromRemoteObject(remoteObject) : context._createHandle(remoteObject); } if (typeof pageFunction !== 'function') @@ -91,7 +90,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { const { exceptionDetails, result: remoteObject } = await callFunctionOnPromise.catch(rewriteError); if (exceptionDetails) throw new Error('Evaluation failed: ' + getExceptionMessage(exceptionDetails)); - return returnByValue ? valueFromRemoteObject(remoteObject) : toHandle(context, remoteObject); + return returnByValue ? valueFromRemoteObject(remoteObject) : context._createHandle(remoteObject); function convertArgument(arg: any): any { if (typeof arg === 'bigint') // eslint-disable-line valid-typeof @@ -141,7 +140,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { for (const property of response.result) { if (!property.enumerable) continue; - result.set(property.name, toHandle(handle.executionContext(), property.value)); + result.set(property.name, handle.executionContext()._createHandle(property.value)); } return result; } @@ -174,19 +173,6 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { } } -const remoteObjectSymbol = Symbol('RemoteObject'); - -export function toRemoteObject(handle: js.JSHandle): Protocol.Runtime.RemoteObject { - return (handle as any)[remoteObjectSymbol]; -} - -export function toHandle(context: js.ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject): js.JSHandle { - if (remoteObject.subtype === 'node' && context.frame()) { - const handle = new dom.ElementHandle(context); - (handle as any)[remoteObjectSymbol] = remoteObject; - return handle; - } - const handle = new js.JSHandle(context); - (handle as any)[remoteObjectSymbol] = remoteObject; - return handle; +function toRemoteObject(handle: js.JSHandle): Protocol.Runtime.RemoteObject { + return handle._remoteObject as Protocol.Runtime.RemoteObject; } diff --git a/src/chromium/JSHandle.ts b/src/chromium/JSHandle.ts index 722e250945..0c0d2ddf89 100644 --- a/src/chromium/JSHandle.ts +++ b/src/chromium/JSHandle.ts @@ -23,8 +23,8 @@ import * as frames from '../frames'; import { CDPSession } from './Connection'; import { FrameManager } from './FrameManager'; import { Protocol } from './protocol'; -import { toRemoteObject, toHandle, ExecutionContextDelegate } from './ExecutionContext'; import { ScreenshotOptions } from './Screenshotter'; +import { ExecutionContextDelegate } from './ExecutionContext'; export class DOMWorldDelegate implements dom.DOMWorldDelegate { readonly keyboard: input.Keyboard; @@ -54,6 +54,10 @@ export class DOMWorldDelegate implements dom.DOMWorldDelegate { return this._frameManager.page()._javascriptEnabled; } + isElement(remoteObject: any): boolean { + return (remoteObject as Protocol.Runtime.RemoteObject).subtype === 'node'; + } + private _getBoxModel(handle: dom.ElementHandle): Promise { return this._client.send('DOM.getBoxModel', { objectId: toRemoteObject(handle).objectId @@ -202,6 +206,10 @@ export class DOMWorldDelegate implements dom.DOMWorldDelegate { backendNodeId, executionContextId: (to.context._delegate as ExecutionContextDelegate)._contextId, }); - return toHandle(to.context, object).asElement()!; + return to.context._createHandle(object).asElement()!; } } + +function toRemoteObject(handle: dom.ElementHandle): Protocol.Runtime.RemoteObject { + return handle._remoteObject as Protocol.Runtime.RemoteObject; +} diff --git a/src/chromium/Page.ts b/src/chromium/Page.ts index 7b98beaab4..86f8ca697d 100644 --- a/src/chromium/Page.ts +++ b/src/chromium/Page.ts @@ -32,16 +32,15 @@ import { PDF } from './features/pdf'; import { Workers } from './features/workers'; import { FrameManager, FrameManagerEvents } from './FrameManager'; import { RawMouseImpl, RawKeyboardImpl } from './Input'; -import { toHandle } from './ExecutionContext'; import { NetworkManagerEvents } from './NetworkManager'; import { Protocol } from './protocol'; import { getExceptionMessage, releaseObject } from './protocolHelper'; import { Target } from './Target'; import * as input from '../input'; import * as types from '../types'; -import * as dom from '../dom'; import * as frames from '../frames'; import * as js from '../javascript'; +import * as dom from '../dom'; import * as network from '../network'; import * as dialog from '../dialog'; import * as console from '../console'; @@ -317,7 +316,7 @@ export class Page extends EventEmitter { return; } const context = this._frameManager.executionContextById(event.executionContextId); - const values = event.args.map(arg => toHandle(context, arg)); + const values = event.args.map(arg => context._createHandle(arg)); this._addConsoleMessage(event.type, values, event.stackTrace); } diff --git a/src/chromium/features/accessibility.ts b/src/chromium/features/accessibility.ts index 7a787c5f15..e823e3bb5a 100644 --- a/src/chromium/features/accessibility.ts +++ b/src/chromium/features/accessibility.ts @@ -17,7 +17,6 @@ import { CDPSession } from '../Connection'; import { Protocol } from '../protocol'; -import { toRemoteObject } from '../ExecutionContext'; import * as dom from '../../dom'; type SerializedAXNode = { @@ -73,7 +72,8 @@ export class Accessibility { const {nodes} = await this._client.send('Accessibility.getFullAXTree'); let backendNodeId = null; if (root) { - const {node} = await this._client.send('DOM.describeNode', {objectId: toRemoteObject(root).objectId}); + const remoteObject = root._remoteObject as Protocol.Runtime.RemoteObject; + const {node} = await this._client.send('DOM.describeNode', {objectId: remoteObject.objectId}); backendNodeId = node.backendNodeId; } const defaultRoot = AXNode.createTree(nodes); diff --git a/src/chromium/features/workers.ts b/src/chromium/features/workers.ts index ecdf1ba046..1d7a74cbcf 100644 --- a/src/chromium/features/workers.ts +++ b/src/chromium/features/workers.ts @@ -21,7 +21,7 @@ import { Protocol } from '../protocol'; import { Events } from '../events'; import * as types from '../../types'; import * as js from '../../javascript'; -import { toHandle, ExecutionContextDelegate } from '../ExecutionContext'; +import { ExecutionContextDelegate } from '../ExecutionContext'; type AddToConsoleCallback = (type: string, args: js.JSHandle[], stackTrace: Protocol.Runtime.StackTrace | undefined) => void; type HandleExceptionCallback = (exceptionDetails: Protocol.Runtime.ExceptionDetails) => void; @@ -67,7 +67,7 @@ export class Worker extends EventEmitter { this._executionContextPromise = new Promise(x => this._executionContextCallback = x); let jsHandleFactory: (o: Protocol.Runtime.RemoteObject) => js.JSHandle; this._client.once('Runtime.executionContextCreated', async event => { - jsHandleFactory = remoteObject => toHandle(executionContext, remoteObject); + jsHandleFactory = remoteObject => executionContext._createHandle(remoteObject); const executionContext = new js.ExecutionContext(new ExecutionContextDelegate(client, event.context)); this._executionContextCallback(executionContext); }); diff --git a/src/dom.ts b/src/dom.ts index a140bd8e77..f88a35e25b 100644 --- a/src/dom.ts +++ b/src/dom.ts @@ -2,22 +2,21 @@ // Licensed under the MIT license. import * as frames from './frames'; -import { assert, helper } from './helper'; -import Injected from './injected/injected'; import * as input from './input'; import * as js from './javascript'; import * as types from './types'; import * as injectedSource from './generated/injectedSource'; import * as cssSelectorEngineSource from './generated/cssSelectorEngineSource'; import * as xpathSelectorEngineSource from './generated/xpathSelectorEngineSource'; - -type SelectorRoot = Element | ShadowRoot | Document; +import { assert, helper } from './helper'; +import Injected from './injected/injected'; export interface DOMWorldDelegate { keyboard: input.Keyboard; mouse: input.Mouse; frame: frames.Frame; isJavascriptEnabled(): boolean; + isElement(remoteObject: any): boolean; contentFrame(handle: ElementHandle): Promise; boundingBox(handle: ElementHandle): Promise; screenshot(handle: ElementHandle, options?: any): Promise; @@ -38,6 +37,12 @@ export class DOMWorld { this.delegate = delegate; } + _createHandle(remoteObject: any): ElementHandle | null { + if (this.delegate.isElement(remoteObject)) + return new ElementHandle(this.context, remoteObject); + return null; + } + injected(): Promise { if (!this._injectedPromise) { const engineSources = [cssSelectorEngineSource.source, xpathSelectorEngineSource.source]; @@ -67,11 +72,13 @@ export class DOMWorld { } } +type SelectorRoot = Element | ShadowRoot | Document; + export class ElementHandle extends js.JSHandle { private readonly _world: DOMWorld; - constructor(context: js.ExecutionContext) { - super(context); + constructor(context: js.ExecutionContext, remoteObject: any) { + super(context, remoteObject); assert(context._domWorld, 'Element handle should have a dom world'); this._world = context._domWorld; } diff --git a/src/firefox/ExecutionContext.ts b/src/firefox/ExecutionContext.ts index 1241790818..502964a11c 100644 --- a/src/firefox/ExecutionContext.ts +++ b/src/firefox/ExecutionContext.ts @@ -17,7 +17,6 @@ import {helper, debugError} from '../helper'; import * as js from '../javascript'; -import * as dom from '../dom'; import { JugglerSession } from './Connection'; export class ExecutionContextDelegate implements js.ExecutionContextDelegate { @@ -48,7 +47,8 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { expression: pageFunction.trim(), executionContextId: this._executionContextId, }).catch(rewriteError); - return toHandle(context, payload.result, payload.exceptionDetails); + checkException(payload.exceptionDetails); + return context._createHandle(payload.result); } if (typeof pageFunction !== 'function') throw new Error(`Expected to get |string| or |function| as the first argument, but got "${pageFunction}" instead.`); @@ -76,7 +76,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { throw new Error('JSHandles can be evaluated only in the context they were created!'); if (arg._disposed) throw new Error('JSHandle is disposed!'); - return this._toProtocolValue(toPayload(arg)); + return this._toCallArgument(arg._remoteObject); } if (Object.is(arg, Infinity)) return {unserializableValue: 'Infinity'}; @@ -101,7 +101,8 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { throw err; } const payload = await callFunctionPromise.catch(rewriteError); - return toHandle(context, payload.result, payload.exceptionDetails); + checkException(payload.exceptionDetails); + return context._createHandle(payload.result); function rewriteError(error) { if (error.message.includes('Failed to find execution context with id')) @@ -113,18 +114,18 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { async getProperties(handle: js.JSHandle): Promise> { const response = await this._session.send('Runtime.getObjectProperties', { executionContextId: this._executionContextId, - objectId: toPayload(handle).objectId, + objectId: handle._remoteObject.objectId, }); const result = new Map(); for (const property of response.properties) - result.set(property.name, toHandle(handle.executionContext(), property.value, null)); + result.set(property.name, handle.executionContext()._createHandle(property.value)); return result; } async releaseHandle(handle: js.JSHandle): Promise { await this._session.send('Runtime.disposeObject', { executionContextId: this._executionContextId, - objectId: toPayload(handle).objectId, + objectId: handle._remoteObject.objectId, }).catch(error => { // Exceptions might happen in case of a page been navigated or closed. // Swallow these since they are harmless and we don't leak anything in this case. @@ -133,51 +134,37 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { } async handleJSONValue(handle: js.JSHandle): Promise { - const payload = toPayload(handle); + const payload = handle._remoteObject; if (!payload.objectId) return deserializeValue(payload); const simpleValue = await this._session.send('Runtime.callFunction', { executionContextId: this._executionContextId, returnByValue: true, functionDeclaration: (e => e).toString(), - args: [this._toProtocolValue(payload)], + args: [this._toCallArgument(payload)], }); return deserializeValue(simpleValue.result); } handleToString(handle: js.JSHandle, includeType: boolean): string { - const payload = toPayload(handle); + const payload = handle._remoteObject; if (payload.objectId) return 'JSHandle@' + (payload.subtype || payload.type); return (includeType ? 'JSHandle:' : '') + deserializeValue(payload); } - private _toProtocolValue(payload: any): any { + private _toCallArgument(payload: any): any { return { value: payload.value, unserializableValue: payload.unserializableValue, objectId: payload.objectId }; } } -const payloadSymbol = Symbol('payload'); - -export function toPayload(handle: js.JSHandle): any { - return (handle as any)[payloadSymbol]; -} - -export function toHandle(context: js.ExecutionContext, result: any, exceptionDetails?: any) { +function checkException(exceptionDetails?: any) { if (exceptionDetails) { if (exceptionDetails.value) throw new Error('Evaluation failed: ' + JSON.stringify(exceptionDetails.value)); else throw new Error('Evaluation failed: ' + exceptionDetails.text + '\n' + exceptionDetails.stack); } - if (result.subtype === 'node') { - const handle = new dom.ElementHandle(context); - (handle as any)[payloadSymbol] = result; - return handle; - } - const handle = new js.JSHandle(context); - (handle as any)[payloadSymbol] = result; - return handle; } export function deserializeValue({unserializableValue, value}) { diff --git a/src/firefox/JSHandle.ts b/src/firefox/JSHandle.ts index 7fc9adc47f..2f54d6564a 100644 --- a/src/firefox/JSHandle.ts +++ b/src/firefox/JSHandle.ts @@ -22,7 +22,6 @@ import * as types from '../types'; import * as frames from '../frames'; import { JugglerSession } from './Connection'; import { FrameManager } from './FrameManager'; -import { toPayload } from './ExecutionContext'; export class DOMWorldDelegate implements dom.DOMWorldDelegate { readonly keyboard: input.Keyboard; @@ -44,7 +43,7 @@ export class DOMWorldDelegate implements dom.DOMWorldDelegate { async contentFrame(handle: dom.ElementHandle): Promise { const {frameId} = await this._session.send('Page.contentFrame', { frameId: this._frameId, - objectId: toPayload(handle).objectId, + objectId: toRemoteObject(handle).objectId, }); if (!frameId) return null; @@ -56,17 +55,21 @@ export class DOMWorldDelegate implements dom.DOMWorldDelegate { return this._frameManager._page._javascriptEnabled; } + isElement(remoteObject: any): boolean { + return remoteObject.subtype === 'node'; + } + async boundingBox(handle: dom.ElementHandle): Promise { return await this._session.send('Page.getBoundingBox', { frameId: this._frameId, - objectId: toPayload(handle).objectId, + objectId: toRemoteObject(handle).objectId, }); } async screenshot(handle: dom.ElementHandle, options: any = {}): Promise { const clip = await this._session.send('Page.getBoundingBox', { frameId: this._frameId, - objectId: toPayload(handle).objectId, + objectId: toRemoteObject(handle).objectId, }); if (!clip) throw new Error('Node is either not visible or not an HTMLElement'); @@ -119,7 +122,7 @@ export class DOMWorldDelegate implements dom.DOMWorldDelegate { const result = await this._session.send('Page.getContentQuads', { frameId: this._frameId, - objectId: toPayload(handle).objectId, + objectId: toRemoteObject(handle).objectId, }).catch(debugError); if (!result || !result.quads.length) throw new Error('Node is either not visible or not an HTMLElement'); @@ -140,3 +143,8 @@ export class DOMWorldDelegate implements dom.DOMWorldDelegate { return handle; } } + +function toRemoteObject(handle: dom.ElementHandle): any { + return handle._remoteObject; +} + diff --git a/src/firefox/Page.ts b/src/firefox/Page.ts index 79fbb0eb34..f76bab0024 100644 --- a/src/firefox/Page.ts +++ b/src/firefox/Page.ts @@ -32,12 +32,11 @@ import { NavigationWatchdog } from './NavigationWatchdog'; import { NetworkManager, NetworkManagerEvents } from './NetworkManager'; import * as input from '../input'; import * as types from '../types'; -import * as dom from '../dom'; import * as js from '../javascript'; +import * as dom from '../dom'; import * as network from '../network'; import * as frames from '../frames'; import * as dialog from '../dialog'; -import { toHandle } from './ExecutionContext'; import * as console from '../console'; const writeFileAsync = helper.promisify(fs.writeFile); @@ -553,7 +552,7 @@ export class Page extends EventEmitter { _onConsole({type, args, executionContextId, location}) { const context = this._frameManager.executionContextById(executionContextId); - this.emit(Events.Page.Console, new console.ConsoleMessage(type, undefined, args.map(arg => toHandle(context, arg)), location)); + this.emit(Events.Page.Console, new console.ConsoleMessage(type, undefined, args.map(arg => context._createHandle(arg)), location)); } isClosed(): boolean { @@ -577,7 +576,7 @@ export class Page extends EventEmitter { if (!this._fileChooserInterceptors.size) return; const context = this._frameManager.executionContextById(executionContextId); - const handle = toHandle(context, element) as dom.ElementHandle; + const handle = context._createHandle(element).asElement()!; const interceptors = Array.from(this._fileChooserInterceptors); this._fileChooserInterceptors.clear(); const multiple = await handle.evaluate((element: HTMLInputElement) => !!element.multiple); diff --git a/src/firefox/api.ts b/src/firefox/api.ts index 7501196264..d3ee2bc180 100644 --- a/src/firefox/api.ts +++ b/src/firefox/api.ts @@ -7,11 +7,11 @@ export { Browser, BrowserContext, Target } from './Browser'; export { BrowserFetcher } from './BrowserFetcher'; export { Dialog } from '../dialog'; export { ExecutionContext, JSHandle } from '../javascript'; +export { ElementHandle } from '../dom'; export { Accessibility } from './features/accessibility'; export { Interception } from './features/interception'; export { Permissions } from './features/permissions'; export { Frame } from '../frames'; -export { ElementHandle } from '../dom'; export { Request, Response } from '../network'; export { Page } from './Page'; export { Playwright } from './Playwright'; diff --git a/src/javascript.ts b/src/javascript.ts index 7321470def..f33aaafe7e 100644 --- a/src/javascript.ts +++ b/src/javascript.ts @@ -32,14 +32,20 @@ export class ExecutionContext { evaluateHandle: types.EvaluateHandle = (pageFunction, ...args) => { return this._delegate.evaluate(this, false /* returnByValue */, pageFunction, ...args); } + + _createHandle(remoteObject: any): JSHandle { + return (this._domWorld && this._domWorld._createHandle(remoteObject)) || new JSHandle(this, remoteObject); + } } export class JSHandle { readonly _context: ExecutionContext; + readonly _remoteObject: any; _disposed = false; - constructor(context: ExecutionContext) { + constructor(context: ExecutionContext, remoteObject: any) { this._context = context; + this._remoteObject = remoteObject; } executionContext(): ExecutionContext { diff --git a/src/webkit/ExecutionContext.ts b/src/webkit/ExecutionContext.ts index ab3307587e..7b26f69d0d 100644 --- a/src/webkit/ExecutionContext.ts +++ b/src/webkit/ExecutionContext.ts @@ -20,7 +20,6 @@ import { helper } from '../helper'; import { valueFromRemoteObject, releaseObject } from './protocolHelper'; import { Protocol } from './protocol'; import * as js from '../javascript'; -import * as dom from '../dom'; export const EVALUATION_SCRIPT_URL = '__playwright_evaluation_script__'; const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m; @@ -78,7 +77,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { if (response.wasThrown) throw new Error('Evaluation failed: ' + response.result.description); if (!returnByValue) - return toHandle(context, response.result); + return context._createHandle(response.result); if (response.result.objectId) { const serializeFunction = function() { try { @@ -184,7 +183,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { if (response.wasThrown) throw new Error('Evaluation failed: ' + response.result.description); if (!returnByValue) - return toHandle(context, response.result); + return context._createHandle(response.result); if (response.result.objectId) { const serializeFunction = function() { try { @@ -281,7 +280,7 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { for (const property of response.properties) { if (!property.enumerable) continue; - result.set(property.name, toHandle(handle.executionContext(), property.value)); + result.set(property.name, handle.executionContext()._createHandle(property.value)); } return result; } @@ -332,19 +331,6 @@ export class ExecutionContextDelegate implements js.ExecutionContextDelegate { } -const remoteObjectSymbol = Symbol('RemoteObject'); - -export function toRemoteObject(handle: js.JSHandle): Protocol.Runtime.RemoteObject { - return (handle as any)[remoteObjectSymbol]; -} - -export function toHandle(context: js.ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject) { - if (remoteObject.subtype === 'node' && context.frame()) { - const handle = new dom.ElementHandle(context); - (handle as any)[remoteObjectSymbol] = remoteObject; - return handle; - } - const handle = new js.JSHandle(context); - (handle as any)[remoteObjectSymbol] = remoteObject; - return handle; +function toRemoteObject(handle: js.JSHandle): Protocol.Runtime.RemoteObject { + return handle._remoteObject as Protocol.Runtime.RemoteObject; } diff --git a/src/webkit/JSHandle.ts b/src/webkit/JSHandle.ts index 1b54585753..30adda47ad 100644 --- a/src/webkit/JSHandle.ts +++ b/src/webkit/JSHandle.ts @@ -22,8 +22,8 @@ import * as dom from '../dom'; import * as frames from '../frames'; import * as types from '../types'; import { TargetSession } from './Connection'; -import { toRemoteObject } from './ExecutionContext'; import { FrameManager } from './FrameManager'; +import { Protocol } from './protocol'; const writeFileAsync = helper.promisify(fs.writeFile); @@ -50,6 +50,10 @@ export class DOMWorldDelegate implements dom.DOMWorldDelegate { return this._frameManager.page()._javascriptEnabled; } + isElement(remoteObject: any): boolean { + return (remoteObject as Protocol.Runtime.RemoteObject).subtype === 'node'; + } + async boundingBox(handle: dom.ElementHandle): Promise { throw new Error('boundingBox() is not implemented'); } @@ -142,3 +146,7 @@ export class DOMWorldDelegate implements dom.DOMWorldDelegate { return handle; } } + +function toRemoteObject(handle: dom.ElementHandle): Protocol.Runtime.RemoteObject { + return handle._remoteObject as Protocol.Runtime.RemoteObject; +} diff --git a/src/webkit/Page.ts b/src/webkit/Page.ts index 4447d00d00..bf7272ed2f 100644 --- a/src/webkit/Page.ts +++ b/src/webkit/Page.ts @@ -26,16 +26,15 @@ import { TargetSession, TargetSessionEvents } from './Connection'; import { Events } from './events'; import { FrameManager, FrameManagerEvents } from './FrameManager'; import { RawKeyboardImpl, RawMouseImpl } from './Input'; -import { toHandle } from './ExecutionContext'; import { NetworkManagerEvents } from './NetworkManager'; import { Protocol } from './protocol'; import { Target } from './Target'; import { TaskQueue } from './TaskQueue'; import * as input from '../input'; import * as types from '../types'; -import * as dom from '../dom'; import * as frames from '../frames'; import * as js from '../javascript'; +import * as dom from '../dom'; import * as network from '../network'; import * as dialog from '../dialog'; import * as console from '../console'; @@ -170,14 +169,14 @@ export class Page extends EventEmitter { derivedType = 'timeEnd'; const mainFrameContext = await this.mainFrame().executionContext(); const handles = (parameters || []).map(p => { - let context = null; + let context: js.ExecutionContext | null = null; if (p.objectId) { const objectId = JSON.parse(p.objectId); context = this._frameManager._contextIdToContext.get(objectId.injectedScriptId); } else { context = mainFrameContext; } - return toHandle(context, p); + return context._createHandle(p); }); this.emit(Events.Page.Console, new console.ConsoleMessage(derivedType, handles.length ? undefined : text, handles, { url, lineNumber, columnNumber })); } @@ -446,7 +445,7 @@ export class Page extends EventEmitter { if (!this._fileChooserInterceptors.size) return; const context = await this._frameManager.frame(event.frameId)._utilityContext(); - const handle = toHandle(context, event.element) as dom.ElementHandle; + const handle = context._createHandle(event.element).asElement()!; const interceptors = Array.from(this._fileChooserInterceptors); this._fileChooserInterceptors.clear(); const multiple = await handle.evaluate((element: HTMLInputElement) => !!element.multiple); diff --git a/src/webkit/api.ts b/src/webkit/api.ts index 972e7d388a..7efebaffb0 100644 --- a/src/webkit/api.ts +++ b/src/webkit/api.ts @@ -5,9 +5,9 @@ export { TimeoutError } from '../Errors'; export { Browser, BrowserContext } from './Browser'; export { BrowserFetcher } from './BrowserFetcher'; export { ExecutionContext, JSHandle } from '../javascript'; +export { ElementHandle } from '../dom'; export { Frame } from '../frames'; export { Mouse, Keyboard } from '../input'; -export { ElementHandle } from '../dom'; export { Request, Response } from '../network'; export { Page } from './Page'; export { Playwright } from './Playwright';