chore: put remoteObject directly on JSHandle (#113)
This commit is contained in:
parent
113ffd6808
commit
ffaf7326ab
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<void | Protocol.DOM.getBoxModelReturnValue> {
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
19
src/dom.ts
19
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<frames.Frame | null>;
|
||||
boundingBox(handle: ElementHandle): Promise<types.Rect | null>;
|
||||
screenshot(handle: ElementHandle, options?: any): Promise<string | Buffer>;
|
||||
|
|
@ -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<js.JSHandle> {
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Map<string, js.JSHandle>> {
|
||||
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<void> {
|
||||
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<any> {
|
||||
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}) {
|
||||
|
|
|
|||
|
|
@ -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<frames.Frame | null> {
|
||||
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<types.Rect | null> {
|
||||
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<string | Buffer> {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<types.Rect | null> {
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
Loading…
Reference in a new issue