feat(rpc): merge ChannelOwner and ConnectionScope (#2911)
This commit is contained in:
parent
54f9a0dd7b
commit
b6fd4dc56c
|
|
@ -19,7 +19,6 @@ import { BrowserChannel, BrowserInitializer } from '../channels';
|
|||
import { BrowserContext } from './browserContext';
|
||||
import { Page } from './page';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { Events } from '../../events';
|
||||
import { CDPSession } from './cdpSession';
|
||||
|
||||
|
|
@ -37,13 +36,13 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
|||
return browser ? Browser.from(browser) : null;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: BrowserInitializer) {
|
||||
super(scope, guid, initializer, true);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: BrowserInitializer) {
|
||||
super(parent, guid, initializer, true);
|
||||
this._channel.on('close', () => {
|
||||
this._isConnected = false;
|
||||
this.emit(Events.Browser.Disconnected);
|
||||
this._isClosedOrClosing = true;
|
||||
this._scope.dispose();
|
||||
this._dispose();
|
||||
});
|
||||
this._closedPromise = new Promise(f => this.once(Events.Browser.Disconnected, f));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import { BrowserContextChannel, BrowserContextInitializer } from '../channels';
|
|||
import { ChannelOwner } from './channelOwner';
|
||||
import { helper } from '../../helper';
|
||||
import { Browser } from './browser';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { Events } from '../../events';
|
||||
import { TimeoutSettings } from '../../timeoutSettings';
|
||||
import { CDPSession } from './cdpSession';
|
||||
|
|
@ -51,8 +50,8 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
|||
return context ? BrowserContext.from(context) : null;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: BrowserContextInitializer) {
|
||||
super(scope, guid, initializer, true);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: BrowserContextInitializer) {
|
||||
super(parent, guid, initializer, true);
|
||||
initializer.pages.forEach(p => {
|
||||
const page = Page.from(p);
|
||||
this._pages.add(page);
|
||||
|
|
@ -225,7 +224,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
|||
}
|
||||
this._pendingWaitForEvents.clear();
|
||||
this.emit(Events.BrowserContext.Close);
|
||||
this._scope.dispose();
|
||||
this._dispose();
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
import { ChildProcess } from 'child_process';
|
||||
import { BrowserServerChannel, BrowserServerInitializer } from '../channels';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Events } from '../../events';
|
||||
|
||||
|
|
@ -25,8 +24,8 @@ export class BrowserServer extends ChannelOwner<BrowserServerChannel, BrowserSer
|
|||
return (server as any)._object;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: BrowserServerInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: BrowserServerInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
this._channel.on('close', () => this.emit(Events.BrowserServer.Close));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import { BrowserTypeChannel, BrowserTypeInitializer } from '../channels';
|
|||
import { Browser } from './browser';
|
||||
import { BrowserContext } from './browserContext';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { BrowserServer } from './browserServer';
|
||||
|
||||
export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeInitializer> {
|
||||
|
|
@ -28,8 +27,8 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
|
|||
return (browserTyep as any)._object;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: BrowserTypeInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: BrowserTypeInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
}
|
||||
|
||||
executablePath(): string {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
|
||||
import { CDPSessionChannel, CDPSessionInitializer } from '../channels';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Protocol } from '../../chromium/protocol';
|
||||
|
||||
|
|
@ -30,11 +29,11 @@ export class CDPSession extends ChannelOwner<CDPSessionChannel, CDPSessionInitia
|
|||
removeListener: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
|
||||
once: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: CDPSessionInitializer) {
|
||||
super(scope, guid, initializer, true);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: CDPSessionInitializer) {
|
||||
super(parent, guid, initializer, true);
|
||||
|
||||
this._channel.on('event', ({ method, params }) => this.emit(method, params));
|
||||
this._channel.on('disconnected', () => this._scope.dispose());
|
||||
this._channel.on('disconnected', () => this._dispose());
|
||||
|
||||
this.on = super.on;
|
||||
this.addListener = super.addListener;
|
||||
|
|
|
|||
|
|
@ -16,18 +16,33 @@
|
|||
|
||||
import { EventEmitter } from 'events';
|
||||
import { Channel } from '../channels';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { Connection } from './connection';
|
||||
import { assert } from '../../helper';
|
||||
|
||||
export abstract class ChannelOwner<T extends Channel, Initializer> extends EventEmitter {
|
||||
export abstract class ChannelOwner<T extends Channel = Channel, Initializer = {}> extends EventEmitter {
|
||||
private _connection: Connection;
|
||||
private _isScope: boolean;
|
||||
// Parent is always "isScope".
|
||||
private _parent: ChannelOwner | undefined;
|
||||
// Only "isScope" channel owners have registered objects inside.
|
||||
private _objects = new Map<string, ChannelOwner>();
|
||||
|
||||
readonly _guid: string;
|
||||
readonly _channel: T;
|
||||
readonly _initializer: Initializer;
|
||||
readonly _scope: ConnectionScope;
|
||||
readonly guid: string;
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: Initializer, isScope?: boolean) {
|
||||
constructor(parent: ChannelOwner | Connection, guid: string, initializer: Initializer, isScope?: boolean) {
|
||||
super();
|
||||
this.guid = guid;
|
||||
this._scope = isScope ? scope.createChild(guid) : scope;
|
||||
|
||||
this._connection = parent instanceof Connection ? parent : parent._connection;
|
||||
this._guid = guid;
|
||||
this._isScope = !!isScope;
|
||||
this._parent = parent instanceof Connection ? undefined : parent;
|
||||
|
||||
this._connection._objects.set(guid, this);
|
||||
if (this._parent)
|
||||
this._parent._objects.set(guid, this);
|
||||
|
||||
const base = new EventEmitter();
|
||||
this._channel = new Proxy(base, {
|
||||
get: (obj: any, prop) => {
|
||||
|
|
@ -45,10 +60,35 @@ export abstract class ChannelOwner<T extends Channel, Initializer> extends Event
|
|||
return obj.addListener;
|
||||
if (prop === 'removeEventListener')
|
||||
return obj.removeListener;
|
||||
return (params: any) => scope.sendMessageToServer({ guid, method: String(prop), params });
|
||||
return (params: any) => this._connection.sendMessageToServer({ guid, method: String(prop), params });
|
||||
},
|
||||
});
|
||||
(this._channel as any)._object = this;
|
||||
this._initializer = initializer;
|
||||
}
|
||||
|
||||
_dispose() {
|
||||
assert(this._isScope);
|
||||
|
||||
// Clean up from parent and connection.
|
||||
if (this._parent)
|
||||
this._parent._objects.delete(this._guid);
|
||||
this._connection._objects.delete(this._guid);
|
||||
|
||||
// Dispose all children.
|
||||
for (const [guid, object] of [...this._objects]) {
|
||||
if (object._isScope)
|
||||
object._dispose();
|
||||
else
|
||||
this._connection._objects.delete(guid);
|
||||
}
|
||||
this._objects.clear();
|
||||
}
|
||||
|
||||
_debugScopeState(): any {
|
||||
return {
|
||||
_guid: this._guid,
|
||||
objects: this._isScope ? Array.from(this._objects.values()).map(o => o._debugScopeState()) : undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,18 +32,24 @@ import { parseError } from '../serializers';
|
|||
import { BrowserServer } from './browserServer';
|
||||
import { CDPSession } from './cdpSession';
|
||||
import { Playwright } from './playwright';
|
||||
import { Channel } from '../channels';
|
||||
|
||||
class Root extends ChannelOwner<Channel, {}> {
|
||||
constructor(connection: Connection) {
|
||||
super(connection, '', {}, true);
|
||||
}
|
||||
}
|
||||
|
||||
export class Connection {
|
||||
readonly _objects = new Map<string, ChannelOwner<any, any>>();
|
||||
readonly _waitingForObject = new Map<string, any>();
|
||||
readonly _objects = new Map<string, ChannelOwner>();
|
||||
private _waitingForObject = new Map<string, any>();
|
||||
onmessage = (message: string): void => {};
|
||||
private _lastId = 0;
|
||||
private _callbacks = new Map<number, { resolve: (a: any) => void, reject: (a: Error) => void }>();
|
||||
readonly _scopes = new Map<string, ConnectionScope>();
|
||||
private _rootScript: ConnectionScope;
|
||||
private _rootObject: ChannelOwner;
|
||||
|
||||
constructor() {
|
||||
this._rootScript = this.createScope('');
|
||||
this._rootObject = new Root(this);
|
||||
}
|
||||
|
||||
async waitForObjectWithKnownName(guid: string): Promise<any> {
|
||||
|
|
@ -61,13 +67,7 @@ export class Connection {
|
|||
}
|
||||
|
||||
_debugScopeState(): any {
|
||||
const scopeState: any = {};
|
||||
scopeState.objects = [...this._objects.keys()];
|
||||
scopeState.scopes = [...this._scopes.values()].map(scope => ({
|
||||
_guid: scope._guid,
|
||||
objects: [...scope._objects.keys()]
|
||||
}));
|
||||
return scopeState;
|
||||
return this._rootObject._debugScopeState();
|
||||
}
|
||||
|
||||
dispatch(message: string) {
|
||||
|
|
@ -86,22 +86,20 @@ export class Connection {
|
|||
|
||||
debug('pw:channel:event')(parsedMessage);
|
||||
if (method === '__create__') {
|
||||
const scope = this._scopes.get(guid)!;
|
||||
scope.createRemoteObject(params.type, params.guid, params.initializer);
|
||||
this._createRemoteObject(guid, params.type, params.guid, params.initializer);
|
||||
return;
|
||||
}
|
||||
const object = this._objects.get(guid)!;
|
||||
object._channel.emit(method, this._replaceGuidsWithChannels(params));
|
||||
}
|
||||
|
||||
|
||||
private _replaceChannelsWithGuids(payload: any): any {
|
||||
if (!payload)
|
||||
return payload;
|
||||
if (Array.isArray(payload))
|
||||
return payload.map(p => this._replaceChannelsWithGuids(p));
|
||||
if (payload._object instanceof ChannelOwner)
|
||||
return { guid: payload._object.guid };
|
||||
return { guid: payload._object._guid };
|
||||
if (typeof payload === 'object') {
|
||||
const result: any = {};
|
||||
for (const key of Object.keys(payload))
|
||||
|
|
@ -111,7 +109,7 @@ export class Connection {
|
|||
return payload;
|
||||
}
|
||||
|
||||
_replaceGuidsWithChannels(payload: any): any {
|
||||
private _replaceGuidsWithChannels(payload: any): any {
|
||||
if (!payload)
|
||||
return payload;
|
||||
if (Array.isArray(payload))
|
||||
|
|
@ -127,125 +125,73 @@ export class Connection {
|
|||
return payload;
|
||||
}
|
||||
|
||||
createScope(guid: string): ConnectionScope {
|
||||
const scope = new ConnectionScope(this, guid);
|
||||
this._scopes.set(guid, scope);
|
||||
return scope;
|
||||
}
|
||||
}
|
||||
|
||||
export class ConnectionScope {
|
||||
private _connection: Connection;
|
||||
readonly _objects = new Map<string, ChannelOwner<any, any>>();
|
||||
private _children = new Set<ConnectionScope>();
|
||||
private _parent: ConnectionScope | undefined;
|
||||
readonly _guid: string;
|
||||
|
||||
constructor(connection: Connection, guid: string) {
|
||||
this._connection = connection;
|
||||
this._guid = guid;
|
||||
}
|
||||
|
||||
createChild(guid: string): ConnectionScope {
|
||||
const scope = this._connection.createScope(guid);
|
||||
this._children.add(scope);
|
||||
scope._parent = this;
|
||||
return scope;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
// Take care of hierarchy.
|
||||
for (const child of [...this._children])
|
||||
child.dispose();
|
||||
this._children.clear();
|
||||
|
||||
// Delete self from scopes and objects.
|
||||
this._connection._scopes.delete(this._guid);
|
||||
this._connection._objects.delete(this._guid);
|
||||
|
||||
// Delete all of the objects from connection.
|
||||
for (const guid of this._objects.keys())
|
||||
this._connection._objects.delete(guid);
|
||||
|
||||
// Clean up from parent.
|
||||
if (this._parent) {
|
||||
this._parent._objects.delete(this._guid);
|
||||
this._parent._children.delete(this);
|
||||
}
|
||||
}
|
||||
|
||||
async sendMessageToServer(message: { guid: string, method: string, params: any }): Promise<any> {
|
||||
return this._connection.sendMessageToServer(message);
|
||||
}
|
||||
|
||||
createRemoteObject(type: string, guid: string, initializer: any): any {
|
||||
private _createRemoteObject(parentGuid: string, type: string, guid: string, initializer: any): any {
|
||||
const parent = this._objects.get(parentGuid)!;
|
||||
let result: ChannelOwner<any, any>;
|
||||
initializer = this._connection._replaceGuidsWithChannels(initializer);
|
||||
initializer = this._replaceGuidsWithChannels(initializer);
|
||||
switch (type) {
|
||||
case 'bindingCall':
|
||||
result = new BindingCall(this, guid, initializer);
|
||||
result = new BindingCall(parent, guid, initializer);
|
||||
break;
|
||||
case 'browser':
|
||||
result = new Browser(this, guid, initializer);
|
||||
result = new Browser(parent, guid, initializer);
|
||||
break;
|
||||
case 'browserServer':
|
||||
result = new BrowserServer(this, guid, initializer);
|
||||
result = new BrowserServer(parent, guid, initializer);
|
||||
break;
|
||||
case 'browserType':
|
||||
result = new BrowserType(this, guid, initializer);
|
||||
result = new BrowserType(parent, guid, initializer);
|
||||
break;
|
||||
case 'cdpSession':
|
||||
// Chromium-specific.
|
||||
result = new CDPSession(this, guid, initializer);
|
||||
result = new CDPSession(parent, guid, initializer);
|
||||
break;
|
||||
case 'context':
|
||||
result = new BrowserContext(this, guid, initializer);
|
||||
result = new BrowserContext(parent, guid, initializer);
|
||||
break;
|
||||
case 'consoleMessage':
|
||||
result = new ConsoleMessage(this, guid, initializer);
|
||||
result = new ConsoleMessage(parent, guid, initializer);
|
||||
break;
|
||||
case 'dialog':
|
||||
result = new Dialog(this, guid, initializer);
|
||||
result = new Dialog(parent, guid, initializer);
|
||||
break;
|
||||
case 'download':
|
||||
result = new Download(this, guid, initializer);
|
||||
result = new Download(parent, guid, initializer);
|
||||
break;
|
||||
case 'elementHandle':
|
||||
result = new ElementHandle(this, guid, initializer);
|
||||
result = new ElementHandle(parent, guid, initializer);
|
||||
break;
|
||||
case 'frame':
|
||||
result = new Frame(this, guid, initializer);
|
||||
result = new Frame(parent, guid, initializer);
|
||||
break;
|
||||
case 'jsHandle':
|
||||
result = new JSHandle(this, guid, initializer);
|
||||
result = new JSHandle(parent, guid, initializer);
|
||||
break;
|
||||
case 'page':
|
||||
result = new Page(this, guid, initializer);
|
||||
result = new Page(parent, guid, initializer);
|
||||
break;
|
||||
case 'playwright':
|
||||
result = new Playwright(this, guid, initializer);
|
||||
result = new Playwright(parent, guid, initializer);
|
||||
break;
|
||||
case 'request':
|
||||
result = new Request(this, guid, initializer);
|
||||
result = new Request(parent, guid, initializer);
|
||||
break;
|
||||
case 'response':
|
||||
result = new Response(this, guid, initializer);
|
||||
result = new Response(parent, guid, initializer);
|
||||
break;
|
||||
case 'route':
|
||||
result = new Route(this, guid, initializer);
|
||||
result = new Route(parent, guid, initializer);
|
||||
break;
|
||||
case 'worker':
|
||||
result = new Worker(this, guid, initializer);
|
||||
result = new Worker(parent, guid, initializer);
|
||||
break;
|
||||
default:
|
||||
throw new Error('Missing type ' + type);
|
||||
}
|
||||
this._connection._objects.set(guid, result);
|
||||
this._objects.set(guid, result);
|
||||
const callback = this._connection._waitingForObject.get(guid);
|
||||
const callback = this._waitingForObject.get(guid);
|
||||
if (callback) {
|
||||
callback(result);
|
||||
this._connection._waitingForObject.delete(guid);
|
||||
this._waitingForObject.delete(guid);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,15 +19,14 @@ import { ConsoleMessageLocation } from '../../types';
|
|||
import { JSHandle } from './jsHandle';
|
||||
import { ConsoleMessageChannel, ConsoleMessageInitializer } from '../channels';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { ConnectionScope } from './connection';
|
||||
|
||||
export class ConsoleMessage extends ChannelOwner<ConsoleMessageChannel, ConsoleMessageInitializer> {
|
||||
static from(message: ConsoleMessageChannel): ConsoleMessage {
|
||||
return (message as any)._object;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: ConsoleMessageInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: ConsoleMessageInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
}
|
||||
|
||||
type(): string {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
|
||||
import { DialogChannel, DialogInitializer } from '../channels';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
|
||||
export class Dialog extends ChannelOwner<DialogChannel, DialogInitializer> {
|
||||
|
|
@ -23,8 +22,8 @@ export class Dialog extends ChannelOwner<DialogChannel, DialogInitializer> {
|
|||
return (dialog as any)._object;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: DialogInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: DialogInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
}
|
||||
|
||||
type(): string {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
import * as fs from 'fs';
|
||||
import { DownloadChannel, DownloadInitializer } from '../channels';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Readable } from 'stream';
|
||||
|
||||
|
|
@ -25,8 +24,8 @@ export class Download extends ChannelOwner<DownloadChannel, DownloadInitializer>
|
|||
return (download as any)._object;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: DownloadInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: DownloadInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
}
|
||||
|
||||
url(): string {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import * as types from '../../types';
|
|||
import { ElementHandleChannel, JSHandleInitializer } from '../channels';
|
||||
import { Frame } from './frame';
|
||||
import { FuncOn, JSHandle, serializeArgument, parseResult } from './jsHandle';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
|
||||
export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
||||
readonly _elementChannel: ElementHandleChannel;
|
||||
|
|
@ -31,8 +31,8 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
|||
return handle ? ElementHandle.from(handle) : null;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: JSHandleInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: JSHandleInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
this._elementChannel = this._channel as ElementHandleChannel;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import { JSHandle, Func1, FuncOn, SmartHandle, serializeArgument, parseResult }
|
|||
import * as network from './network';
|
||||
import { Response } from './network';
|
||||
import { Page } from './page';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { normalizeFilePayloads } from '../serializers';
|
||||
|
||||
export type GotoOptions = types.NavigateOptions & {
|
||||
|
|
@ -50,8 +49,8 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
return frame ? Frame.from(frame) : null;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: FrameInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: FrameInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
this._parentFrame = Frame.fromNullable(initializer.parentFrame);
|
||||
if (this._parentFrame)
|
||||
this._parentFrame._childFrames.add(this);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
import { JSHandleChannel, JSHandleInitializer } from '../channels';
|
||||
import { ElementHandle } from './elementHandle';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { serializeAsCallArgument, parseEvaluationResultValue } from '../../common/utilityScriptSerializers';
|
||||
|
||||
type NoHandles<Arg> = Arg extends JSHandle ? never : (Arg extends object ? { [Key in keyof Arg]: NoHandles<Arg[Key]> } : Arg);
|
||||
|
|
@ -47,8 +46,8 @@ export class JSHandle<T = any> extends ChannelOwner<JSHandleChannel, JSHandleIni
|
|||
return handle ? JSHandle.from(handle) : null;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: JSHandleInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: JSHandleInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
this._preview = this._initializer.preview;
|
||||
this._channel.on('previewUpdated', preview => this._preview = preview);
|
||||
}
|
||||
|
|
@ -103,7 +102,7 @@ export function serializeArgument(arg: any): any {
|
|||
};
|
||||
const value = serializeAsCallArgument(arg, value => {
|
||||
if (value instanceof ChannelOwner)
|
||||
return { h: pushHandle(value.guid) };
|
||||
return { h: pushHandle(value._guid) };
|
||||
return { fallThrough: value };
|
||||
});
|
||||
return { value, guids };
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import * as types from '../../types';
|
|||
import { RequestChannel, ResponseChannel, RouteChannel, RequestInitializer, ResponseInitializer, RouteInitializer } from '../channels';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Frame } from './frame';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { normalizeFulfillParameters } from '../serializers';
|
||||
|
||||
export type NetworkCookie = {
|
||||
|
|
@ -58,8 +57,8 @@ export class Request extends ChannelOwner<RequestChannel, RequestInitializer> {
|
|||
return request ? Request.from(request) : null;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: RequestInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: RequestInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
this._redirectedFrom = Request.fromNullable(initializer.redirectedFrom);
|
||||
if (this._redirectedFrom)
|
||||
this._redirectedFrom._redirectedTo = this;
|
||||
|
|
@ -138,8 +137,8 @@ export class Route extends ChannelOwner<RouteChannel, RouteInitializer> {
|
|||
return (route as any)._object;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: RouteInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: RouteInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
}
|
||||
|
||||
request(): Request {
|
||||
|
|
@ -171,8 +170,8 @@ export class Response extends ChannelOwner<ResponseChannel, ResponseInitializer>
|
|||
return response ? Response.from(response) : null;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: ResponseInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: ResponseInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
}
|
||||
|
||||
url(): string {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import { assert, assertMaxArguments, helper, Listener } from '../../helper';
|
|||
import { TimeoutSettings } from '../../timeoutSettings';
|
||||
import * as types from '../../types';
|
||||
import { BindingCallChannel, BindingCallInitializer, PageChannel, PageInitializer } from '../channels';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { parseError, serializeError } from '../serializers';
|
||||
import { Accessibility } from './accessibility';
|
||||
import { BrowserContext } from './browserContext';
|
||||
|
|
@ -69,8 +68,8 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
return page ? Page.from(page) : null;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: PageInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: PageInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
this.accessibility = new Accessibility(this._channel);
|
||||
this.keyboard = new Keyboard(this._channel);
|
||||
this.mouse = new Mouse(this._channel);
|
||||
|
|
@ -511,8 +510,8 @@ export class BindingCall extends ChannelOwner<BindingCallChannel, BindingCallIni
|
|||
return (channel as any)._object;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: BindingCallInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: BindingCallInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
}
|
||||
|
||||
async call(func: FunctionWithSource) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import { PlaywrightChannel, PlaywrightInitializer } from '../channels';
|
|||
import * as types from '../../types';
|
||||
import { BrowserType } from './browserType';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { ConnectionScope } from './connection';
|
||||
|
||||
export class Playwright extends ChannelOwner<PlaywrightChannel, PlaywrightInitializer> {
|
||||
chromium: BrowserType;
|
||||
|
|
@ -26,8 +25,8 @@ export class Playwright extends ChannelOwner<PlaywrightChannel, PlaywrightInitia
|
|||
webkit: BrowserType;
|
||||
devices: types.Devices;
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: PlaywrightInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: PlaywrightInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
this.chromium = BrowserType.from(initializer.chromium);
|
||||
this.firefox = BrowserType.from(initializer.firefox);
|
||||
this.webkit = BrowserType.from(initializer.webkit);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
import { Events } from '../../events';
|
||||
import { assertMaxArguments } from '../../helper';
|
||||
import { WorkerChannel, WorkerInitializer } from '../channels';
|
||||
import { ConnectionScope } from './connection';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Func1, JSHandle, parseResult, serializeArgument, SmartHandle } from './jsHandle';
|
||||
import { Page } from './page';
|
||||
|
|
@ -31,8 +30,8 @@ export class Worker extends ChannelOwner<WorkerChannel, WorkerInitializer> {
|
|||
return (worker as any)._object;
|
||||
}
|
||||
|
||||
constructor(scope: ConnectionScope, guid: string, initializer: WorkerInitializer) {
|
||||
super(scope, guid, initializer);
|
||||
constructor(parent: ChannelOwner, guid: string, initializer: WorkerInitializer) {
|
||||
super(parent, guid, initializer);
|
||||
this._channel.on('close', () => {
|
||||
if (this._page)
|
||||
this._page._workers.delete(this);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const { FFOX, CHROMIUM, WEBKIT, WIN, CHANNEL } = require('./utils').testOptions(
|
|||
|
||||
describe.skip(!CHANNEL)('Channels', function() {
|
||||
it('should work', async({browser}) => {
|
||||
expect(!!browser._channel).toBeTruthy();
|
||||
expect(!!browser._connection).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should scope context handles', async({browser, server}) => {
|
||||
|
|
@ -101,8 +101,8 @@ describe.skip(!CHANNEL)('Channels', function() {
|
|||
|
||||
async function expectScopeState(object, golden) {
|
||||
const remoteState = trimGuids(await object._channel.debugScopeState());
|
||||
const localState = trimGuids(object._scope._connection._debugScopeState());
|
||||
expect(localState).toEqual(golden);
|
||||
const localState = trimGuids(object._connection._debugScopeState());
|
||||
expect(processLocalState(localState)).toEqual(golden);
|
||||
expect(remoteState).toEqual(golden);
|
||||
}
|
||||
|
||||
|
|
@ -119,3 +119,21 @@ function trimGuids(object) {
|
|||
return object ? object.match(/[^@]+/)[0] : '';
|
||||
return object;
|
||||
}
|
||||
|
||||
function processLocalState(root) {
|
||||
const objects = [];
|
||||
const scopes = [];
|
||||
const visit = (object, scope) => {
|
||||
if (object._guid !== '')
|
||||
objects.push(object._guid);
|
||||
scope.push(object._guid);
|
||||
if (object.objects) {
|
||||
scope = [];
|
||||
scopes.push({ _guid: object._guid, objects: scope });
|
||||
for (const child of object.objects)
|
||||
visit(child, scope);
|
||||
}
|
||||
};
|
||||
visit(root, []);
|
||||
return { objects, scopes };
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue