chore(rpc): strongly-type the initializer, remove __init__ phase (#2729)

This commit is contained in:
Pavel Feldman 2020-06-26 12:28:27 -07:00 committed by GitHub
parent 18d6140d3e
commit 02f7501725
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 256 additions and 292 deletions

View file

@ -28,12 +28,17 @@ export interface BrowserTypeChannel extends Channel {
launch(params: { options?: types.LaunchOptions }): Promise<BrowserChannel>;
launchPersistentContext(params: { userDataDir: string, options?: types.LaunchOptions & types.BrowserContextOptions }): Promise<BrowserContextChannel>;
}
export type BrowserTypeInitializer = {
executablePath: string,
name: string
};
export interface BrowserChannel extends Channel {
close(): Promise<void>;
newContext(params: { options?: types.BrowserContextOptions }): Promise<BrowserContextChannel>;
newPage(params: { options?: types.BrowserContextOptions }): Promise<PageChannel>;
}
export type BrowserInitializer = {};
export interface BrowserContextChannel extends Channel {
addCookies(params: { cookies: types.SetNetworkCookieParam[] }): Promise<void>;
@ -54,6 +59,7 @@ export interface BrowserContextChannel extends Channel {
setOffline(params: { offline: boolean }): Promise<void>;
waitForEvent(params: { event: string }): Promise<any>;
}
export type BrowserContextInitializer = {};
export interface PageChannel extends Channel {
on(event: 'bindingCall', callback: (params: BindingCallChannel) => void): this;
@ -101,6 +107,10 @@ export interface PageChannel extends Channel {
// A11Y
accessibilitySnapshot(params: { options: { interestingOnly?: boolean, root?: ElementHandleChannel } }): Promise<types.SerializedAXNode | null>;
}
export type PageInitializer = {
mainFrame: FrameChannel,
viewportSize: types.Size | null
};
export interface FrameChannel extends Channel {
$$eval(params: { selector: string; expression: string, isFunction: boolean, arg: any }): Promise<any>;
@ -137,6 +147,11 @@ export interface FrameChannel extends Channel {
waitForNavigation(params: { options: types.WaitForNavigationOptions }): Promise<ResponseChannel | null>;
waitForSelector(params: { selector: string, options: types.WaitForElementOptions }): Promise<ElementHandleChannel | null>;
}
export type FrameInitializer = {
url: string,
name: string,
parentFrame: FrameChannel | null
};
export interface JSHandleChannel extends Channel {
dispose(): Promise<void>;
@ -145,6 +160,9 @@ export interface JSHandleChannel extends Channel {
getPropertyList(): Promise<{ name: string, value: JSHandleChannel}[]>;
jsonValue(): Promise<any>;
}
export type JSHandleInitializer = {
preview: string,
};
export interface ElementHandleChannel extends JSHandleChannel {
$$eval(params: { selector: string; expression: string, isFunction: boolean, arg: any }): Promise<any>;
@ -178,22 +196,53 @@ export interface ElementHandleChannel extends JSHandleChannel {
export interface RequestChannel extends Channel {
response(): Promise<ResponseChannel | null>;
}
export type RequestInitializer = {
frame: FrameChannel,
url: string,
resourceType: string,
method: string,
postData: string | null,
headers: types.Headers,
isNavigationRequest: boolean,
redirectedFrom: RequestChannel | null,
};
export interface RouteChannel extends Channel {
abort(params: { errorCode: string }): Promise<void>;
continue(params: { overrides: { method?: string, headers?: types.Headers, postData?: string } }): Promise<void>;
fulfill(params: { response: types.FulfillResponse & { path?: string } }): Promise<void>;
}
export type RouteInitializer = {
request: RequestChannel,
};
export interface ResponseChannel extends Channel {
body(): Promise<Buffer>;
finished(): Promise<Error | null>;
}
export type ResponseInitializer = {
request: RequestChannel,
url: string,
status: number,
statusText: string,
headers: types.Headers,
};
export interface ConsoleMessageChannel extends Channel {
}
export type ConsoleMessageInitializer = {
type: string,
text: string,
args: JSHandleChannel[],
location: types.ConsoleMessageLocation,
};
export interface BindingCallChannel extends Channel {
reject(params: { error: types.Error }): void;
resolve(params: { result: any }): void;
}
export type BindingCallInitializer = {
frame: FrameChannel,
name: string,
args: any[]
};

View file

@ -15,13 +15,13 @@
*/
import * as types from '../../types';
import { BrowserChannel } from '../channels';
import { BrowserChannel, BrowserInitializer } from '../channels';
import { BrowserContext } from './browserContext';
import { Page } from './page';
import { ChannelOwner } from './channelOwner';
import { Connection } from '../connection';
export class Browser extends ChannelOwner<BrowserChannel> {
export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
readonly _contexts = new Set<BrowserContext>();
private _isConnected = true;
@ -34,12 +34,10 @@ export class Browser extends ChannelOwner<BrowserChannel> {
return browser ? Browser.from(browser) : null;
}
constructor(connection: Connection, channel: BrowserChannel) {
super(connection, channel);
constructor(connection: Connection, channel: BrowserChannel, initializer: BrowserInitializer) {
super(connection, channel, initializer);
}
_initialize() {}
async newContext(options?: types.BrowserContextOptions): Promise<BrowserContext> {
const context = BrowserContext.from(await this._channel.newContext({ options }));
this._contexts.add(context);

View file

@ -19,13 +19,14 @@ import * as frames from './frame';
import { Page, BindingCall, waitForEvent } from './page';
import * as types from '../../types';
import * as network from './network';
import { BrowserContextChannel } from '../channels';
import { BrowserContextChannel, BrowserContextInitializer } from '../channels';
import { ChannelOwner } from './channelOwner';
import { helper } from '../../helper';
import { Browser } from './browser';
import { Connection } from '../connection';
import { Events } from '../../events';
export class BrowserContext extends ChannelOwner<BrowserContextChannel> {
export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserContextInitializer> {
_pages = new Set<Page>();
private _routes: { url: types.URLMatch, handler: network.RouteHandler }[] = [];
_browser: Browser | undefined;
@ -39,11 +40,16 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel> {
return context ? BrowserContext.from(context) : null;
}
constructor(connection: Connection, channel: BrowserContextChannel) {
super(connection, channel);
constructor(connection: Connection, channel: BrowserContextChannel, initializer: BrowserContextInitializer) {
super(connection, channel, initializer);
channel.on('page', page => this._onPage(Page.from(page)));
}
_initialize() {}
private _onPage(page: Page): void {
page._browserContext = this;
this._pages.add(page);
this.emit(Events.BrowserContext.Page, page);
}
_onRoute(route: network.Route, request: network.Request) {
for (const {url, handler} of this._routes) {
@ -56,7 +62,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel> {
}
async _onBinding(bindingCall: BindingCall) {
const func = this._bindings.get(bindingCall.name);
const func = this._bindings.get(bindingCall._initializer.name);
if (!func)
return;
bindingCall.call(func);
@ -157,5 +163,6 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel> {
async close(): Promise<void> {
await this._channel.close();
this._browser!._contexts.delete(this);
this.emit(Events.BrowserContext.Close);
}
}

View file

@ -15,31 +15,23 @@
*/
import * as types from '../../types';
import { BrowserTypeChannel } from '../channels';
import { BrowserTypeChannel, BrowserTypeInitializer } from '../channels';
import { Browser } from './browser';
import { BrowserContext } from './browserContext';
import { ChannelOwner } from './channelOwner';
import { Connection } from '../connection';
export class BrowserType extends ChannelOwner<BrowserTypeChannel> {
private _executablePath: string = '';
private _name: string = '';
constructor(connection: Connection, channel: BrowserTypeChannel) {
super(connection, channel);
}
_initialize(payload: { executablePath: string, name: string }) {
this._executablePath = payload.executablePath;
this._name = payload.name;
export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeInitializer> {
constructor(connection: Connection, channel: BrowserTypeChannel, initializer: BrowserTypeInitializer) {
super(connection, channel, initializer);
}
executablePath(): string {
return this._executablePath;
return this._initializer.executablePath;
}
name(): string {
return this._name;
return this._initializer.name;
}
async launch(options?: types.LaunchOptions): Promise<Browser> {

View file

@ -18,17 +18,17 @@ import { EventEmitter } from 'events';
import { Channel } from '../channels';
import { Connection } from '../connection';
export abstract class ChannelOwner<T extends Channel> extends EventEmitter {
export abstract class ChannelOwner<T extends Channel, Initializer> extends EventEmitter {
readonly _channel: T;
readonly _initializer: Initializer;
readonly _connection: Connection;
static clientSymbol = Symbol('client');
constructor(connection: Connection, channel: T) {
constructor(connection: Connection, channel: T, initializer: Initializer) {
super();
this._connection = connection;
this._channel = channel;
this._initializer = initializer;
(channel as any)[ChannelOwner.clientSymbol] = this;
}
abstract _initialize(payload: any): void;
}

View file

@ -17,45 +17,33 @@
import * as util from 'util';
import { ConsoleMessageLocation } from '../../types';
import { JSHandle } from './jsHandle';
import { ConsoleMessageChannel, JSHandleChannel } from '../channels';
import { ConsoleMessageChannel, ConsoleMessageInitializer } from '../channels';
import { ChannelOwner } from './channelOwner';
import { Connection } from '../connection';
export class ConsoleMessage extends ChannelOwner<ConsoleMessageChannel> {
private _type: string = '';
private _text: string = '';
private _args: JSHandle[] = [];
private _location: ConsoleMessageLocation = {};
export class ConsoleMessage extends ChannelOwner<ConsoleMessageChannel, ConsoleMessageInitializer> {
static from(request: ConsoleMessageChannel): ConsoleMessage {
return request._object;
}
constructor(connection: Connection, channel: ConsoleMessageChannel) {
super(connection, channel);
}
_initialize(params: { type: string, text: string, args: JSHandleChannel[], location: ConsoleMessageLocation }) {
this._type = params.type;
this._text = params.text;
this._args = params.args.map(JSHandle.from);
this._location = params.location;
constructor(connection: Connection, channel: ConsoleMessageChannel, initializer: ConsoleMessageInitializer) {
super(connection, channel, initializer);
}
type(): string {
return this._type;
return this._initializer.type;
}
text(): string {
return this._text;
return this._initializer.text;
}
args(): JSHandle[] {
return this._args;
return this._initializer.args.map(JSHandle.from);
}
location(): ConsoleMessageLocation {
return this._location;
return this._initializer.location;
}
[util.inspect.custom]() {

View file

@ -15,7 +15,7 @@
*/
import * as types from '../../types';
import { ElementHandleChannel } from '../channels';
import { ElementHandleChannel, JSHandleInitializer } from '../channels';
import { Frame } from './frame';
import { FuncOn, JSHandle, convertArg } from './jsHandle';
import { Connection } from '../connection';
@ -31,8 +31,8 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
return handle ? ElementHandle.from(handle) : null;
}
constructor(connection: Connection, channel: ElementHandleChannel) {
super(connection, channel);
constructor(connection: Connection, channel: ElementHandleChannel, initializer: JSHandleInitializer) {
super(connection, channel, initializer);
this._elementChannel = channel;
}

View file

@ -17,7 +17,7 @@
import { assertMaxArguments } from '../../helper';
import * as types from '../../types';
import { FrameChannel } from '../channels';
import { FrameChannel, FrameInitializer } from '../channels';
import { BrowserContext } from './browserContext';
import { ChannelOwner } from './channelOwner';
import { ElementHandle, convertSelectOptionValues } from './elementHandle';
@ -33,12 +33,13 @@ export type GotoOptions = types.NavigateOptions & {
export type FunctionWithSource = (source: { context: BrowserContext, page: Page, frame: Frame }, ...args: any) => any;
export class Frame extends ChannelOwner<FrameChannel> {
export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
_parentFrame: Frame | null = null;
_url = '';
_name = '';
private _detached = false;
_childFrames = new Set<Frame>();
_page: Page | undefined;
static from(frame: FrameChannel): Frame {
return frame._object;
@ -48,16 +49,13 @@ export class Frame extends ChannelOwner<FrameChannel> {
return frame ? Frame.from(frame) : null;
}
constructor(connection: Connection, channel: FrameChannel) {
super(connection, channel);
}
_initialize(params: { name: string, url: string, parentFrame: FrameChannel | null }) {
this._parentFrame = params.parentFrame ? params.parentFrame._object : null;
constructor(connection: Connection, channel: FrameChannel, initializer: FrameInitializer) {
super(connection, channel, initializer);
this._parentFrame = Frame.fromNullable(initializer.parentFrame);
if (this._parentFrame)
this._parentFrame._childFrames.add(this);
this._name = params.name;
this._url = params.url;
this._name = initializer.name;
this._url = initializer.url;
}
async goto(url: string, options: GotoOptions = {}): Promise<network.Response | null> {

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { JSHandleChannel } from '../channels';
import { JSHandleChannel, JSHandleInitializer } from '../channels';
import { ElementHandle } from './elementHandle';
import { ChannelOwner } from './channelOwner';
import { Connection } from '../connection';
@ -35,10 +35,7 @@ export type Func1<Arg, R> = string | ((arg: Unboxed<Arg>) => R | Promise<R>);
export type FuncOn<On, Arg2, R> = string | ((on: On, arg2: Unboxed<Arg2>) => R | Promise<R>);
export type SmartHandle<T> = T extends Node ? ElementHandle<T> : JSHandle<T>;
export class JSHandle<T = any> extends ChannelOwner<JSHandleChannel> {
protected _jsChannel: JSHandleChannel;
private _preview: string | undefined;
export class JSHandle<T = any> extends ChannelOwner<JSHandleChannel, JSHandleInitializer> {
static from(handle: JSHandleChannel): JSHandle {
return handle._object;
}
@ -47,25 +44,20 @@ export class JSHandle<T = any> extends ChannelOwner<JSHandleChannel> {
return handle ? JSHandle.from(handle) : null;
}
constructor(conection: Connection, channel: JSHandleChannel) {
super(conection, channel);
this._jsChannel = channel;
}
_initialize(params: { preview: string }) {
this._preview = params.preview;
constructor(conection: Connection, channel: JSHandleChannel, initializer: JSHandleInitializer) {
super(conection, channel, initializer);
}
async evaluate<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<R>;
async evaluate<R>(pageFunction: FuncOn<T, void, R>, arg?: any): Promise<R>;
async evaluate<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<R> {
return await this._jsChannel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: convertArg(arg) });
return await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: convertArg(arg) });
}
async evaluateHandle<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<SmartHandle<R>>;
async evaluateHandle<R>(pageFunction: FuncOn<T, void, R>, arg?: any): Promise<SmartHandle<R>>;
async evaluateHandle<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<SmartHandle<R>> {
const handleChannel = await this._jsChannel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: convertArg(arg) });
const handleChannel = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: convertArg(arg) });
return JSHandle.from(handleChannel) as SmartHandle<R>;
}
@ -83,13 +75,13 @@ export class JSHandle<T = any> extends ChannelOwner<JSHandleChannel> {
async getProperties(): Promise<Map<string, JSHandle>> {
const map = new Map<string, JSHandle>();
for (const { name, value } of await this._jsChannel.getPropertyList())
for (const { name, value } of await this._channel.getPropertyList())
map.set(name, JSHandle.from(value));
return map;
}
async jsonValue(): Promise<T> {
return await this._jsChannel.jsonValue();
return await this._channel.jsonValue();
}
asElement(): ElementHandle | null {
@ -97,11 +89,11 @@ export class JSHandle<T = any> extends ChannelOwner<JSHandleChannel> {
}
async dispose() {
return await this._jsChannel.dispose();
return await this._channel.dispose();
}
toString(): string {
return this._preview!;
return this._initializer.preview;
}
}

View file

@ -16,7 +16,7 @@
import { URLSearchParams } from 'url';
import * as types from '../../types';
import { RequestChannel, ResponseChannel, FrameChannel, RouteChannel } from '../channels';
import { RequestChannel, ResponseChannel, RouteChannel, RequestInitializer, ResponseInitializer, RouteInitializer } from '../channels';
import { ChannelOwner } from './channelOwner';
import { Frame } from './frame';
import { Connection } from '../connection';
@ -44,17 +44,10 @@ export type SetNetworkCookieParam = {
sameSite?: 'Strict' | 'Lax' | 'None'
};
export class Request extends ChannelOwner<RequestChannel> {
export class Request extends ChannelOwner<RequestChannel, RequestInitializer> {
private _redirectedFrom: Request | null = null;
private _redirectedTo: Request | null = null;
private _isNavigationRequest = false;
_failureText: string | null = null;
private _url: string = '';
private _resourceType = '';
private _method = '';
private _postData: string | null = null;
private _headers: types.Headers = {};
private _frame: Frame | undefined;
static from(request: RequestChannel): Request {
return request._object;
@ -64,42 +57,31 @@ export class Request extends ChannelOwner<RequestChannel> {
return request ? Request.from(request) : null;
}
constructor(connection: Connection, channel: RequestChannel) {
super(connection, channel);
}
_initialize(payload: { frame: FrameChannel, redirectedFrom: RequestChannel | null, isNavigationRequest: boolean,
url: string, resourceType: string, method: string, postData: string | null, headers: types.Headers }) {
this._frame = payload.frame._object as Frame;
this._isNavigationRequest = payload.isNavigationRequest;
this._redirectedFrom = Request.fromNullable(payload.redirectedFrom);
constructor(connection: Connection, channel: RequestChannel, initializer: RequestInitializer) {
super(connection, channel, initializer);
this._redirectedFrom = Request.fromNullable(initializer.redirectedFrom);
if (this._redirectedFrom)
this._redirectedFrom._redirectedTo = this;
this._url = payload.url;
this._resourceType = payload.resourceType;
this._method = payload.method;
this._postData = payload.postData;
this._headers = payload.headers;
}
url(): string {
return this._url;
return this._initializer.url;
}
resourceType(): string {
return this._resourceType;
return this._initializer.resourceType;
}
method(): string {
return this._method;
return this._initializer.method;
}
postData(): string | null {
return this._postData;
return this._initializer.postData;
}
postDataJSON(): Object | null {
if (!this._postData)
if (!this._initializer.postData)
return null;
const contentType = this.headers()['content-type'];
@ -108,17 +90,17 @@ export class Request extends ChannelOwner<RequestChannel> {
if (contentType === 'application/x-www-form-urlencoded') {
const entries: Record<string, string> = {};
const parsed = new URLSearchParams(this._postData);
const parsed = new URLSearchParams(this._initializer.postData);
for (const [k, v] of parsed.entries())
entries[k] = v;
return entries;
}
return JSON.parse(this._postData);
return JSON.parse(this._initializer.postData);
}
headers(): {[key: string]: string} {
return { ...this._headers };
return { ...this._initializer.headers };
}
async response(): Promise<Response | null> {
@ -126,11 +108,11 @@ export class Request extends ChannelOwner<RequestChannel> {
}
frame(): Frame {
return this._frame!;
return Frame.from(this._initializer.frame);
}
isNavigationRequest(): boolean {
return this._isNavigationRequest;
return this._initializer.isNavigationRequest;
}
redirectedFrom(): Request | null {
@ -150,23 +132,17 @@ export class Request extends ChannelOwner<RequestChannel> {
}
}
export class Route extends ChannelOwner<RouteChannel> {
private _request: Request | undefined;
export class Route extends ChannelOwner<RouteChannel, RouteInitializer> {
static from(route: RouteChannel): Route {
return route._object;
}
constructor(connection: Connection, channel: RouteChannel) {
super(connection, channel);
}
_initialize(params: { request: RequestChannel }) {
this._request = Request.from(params.request);
constructor(connection: Connection, channel: RouteChannel, initializer: RouteInitializer) {
super(connection, channel, initializer);
}
request(): Request {
return this._request!;
return Request.from(this._initializer.request);
}
async abort(errorCode: string = 'failed') {
@ -184,13 +160,7 @@ export class Route extends ChannelOwner<RouteChannel> {
export type RouteHandler = (route: Route, request: Request) => void;
export class Response extends ChannelOwner<ResponseChannel> {
private _request: Request | undefined;
private _status: number = 0;
private _statusText: string = '';
private _url: string = '';
private _headers: types.Headers = {};
export class Response extends ChannelOwner<ResponseChannel, ResponseInitializer> {
static from(response: ResponseChannel): Response {
return response._object;
}
@ -199,36 +169,28 @@ export class Response extends ChannelOwner<ResponseChannel> {
return response ? Response.from(response) : null;
}
constructor(connection: Connection, channel: ResponseChannel) {
super(connection, channel);
}
_initialize(payload: { request: RequestChannel, url: string, status: number, statusText: string, headers: types.Headers }) {
this._request = Request.from(payload.request);
this._status = payload.status;
this._statusText = payload.statusText;
this._url = payload.url;
this._headers = payload.headers;
constructor(connection: Connection, channel: ResponseChannel, initializer: ResponseInitializer) {
super(connection, channel, initializer);
}
url(): string {
return this._url;
return this._initializer.url;
}
ok(): boolean {
return this._status === 0 || (this._status >= 200 && this._status <= 299);
return this._initializer.status === 0 || (this._initializer.status >= 200 && this._initializer.status <= 299);
}
status(): number {
return this._status;
return this._initializer.status;
}
statusText(): string {
return this._statusText;
return this._initializer.statusText;
}
headers(): object {
return { ...this._headers };
return { ...this._initializer.headers };
}
async finished(): Promise<Error | null> {
@ -250,10 +212,10 @@ export class Response extends ChannelOwner<ResponseChannel> {
}
request(): Request {
return this._request!;
return Request.from(this._initializer.request);
}
frame(): Frame {
return this._request!.frame();
return Request.from(this._initializer.request).frame();
}
}

View file

@ -19,7 +19,7 @@ import { EventEmitter } from 'events';
import { Events } from '../../events';
import { assert, assertMaxArguments, helper, Listener, serializeError, parseError } from '../../helper';
import * as types from '../../types';
import { BrowserContextChannel, FrameChannel, PageChannel, BindingCallChannel, Channel } from '../channels';
import { PageChannel, BindingCallChannel, Channel, PageInitializer, BindingCallInitializer } from '../channels';
import { BrowserContext } from './browserContext';
import { ChannelOwner } from './channelOwner';
import { ElementHandle } from './elementHandle';
@ -29,17 +29,17 @@ import { Request, Response, RouteHandler, Route } from './network';
import { Connection } from '../connection';
import { Keyboard, Mouse } from './input';
import { Accessibility } from './accessibility';
import { ConsoleMessage } from './console';
import { ConsoleMessage } from './consoleMessage';
export class Page extends ChannelOwner<PageChannel> {
export class Page extends ChannelOwner<PageChannel, PageInitializer> {
readonly pdf: ((options?: types.PDFOptions) => Promise<Buffer>) | undefined;
private _browserContext: BrowserContext | undefined;
private _mainFrame: Frame | undefined;
_browserContext: BrowserContext | undefined;
private _mainFrame: Frame;
private _frames = new Set<Frame>();
private _workers: Worker[] = [];
private _closed = false;
private _viewportSize: types.Size | null = null;
private _viewportSize: types.Size | null;
private _routes: { url: types.URLMatch, handler: RouteHandler }[] = [];
readonly accessibility: Accessibility;
@ -55,18 +55,16 @@ export class Page extends ChannelOwner<PageChannel> {
return page ? Page.from(page) : null;
}
constructor(connection: Connection, channel: PageChannel) {
super(connection, channel);
constructor(connection: Connection, channel: PageChannel, initializer: PageInitializer) {
super(connection, channel, initializer);
this.accessibility = new Accessibility(channel);
this.keyboard = new Keyboard(channel);
this.mouse = new Mouse(channel);
}
_initialize(payload: { browserContext: BrowserContextChannel, mainFrame: FrameChannel, viewportSize: types.Size }) {
this._browserContext = BrowserContext.from(payload.browserContext);
this._mainFrame = Frame.from(payload.mainFrame);
this._mainFrame = Frame.from(initializer.mainFrame);
this._mainFrame._page = this;
this._frames.add(this._mainFrame);
this._viewportSize = payload.viewportSize;
this._viewportSize = initializer.viewportSize;
this._channel.on('bindingCall', bindingCall => this._onBinding(BindingCall.from(bindingCall)));
this._channel.on('close', () => this._onClose());
@ -88,6 +86,7 @@ export class Page extends ChannelOwner<PageChannel> {
}
private _onFrameAttached(frame: Frame) {
frame._page = this;
this._frames.add(frame);
if (frame._parentFrame)
frame._parentFrame._childFrames.add(frame);
@ -118,7 +117,7 @@ export class Page extends ChannelOwner<PageChannel> {
}
async _onBinding(bindingCall: BindingCall) {
const func = this._bindings.get(bindingCall.name);
const func = this._bindings.get(bindingCall._initializer.name);
if (func)
bindingCall.call(func);
this._browserContext!._onBinding(bindingCall);
@ -138,7 +137,7 @@ export class Page extends ChannelOwner<PageChannel> {
}
mainFrame(): Frame {
return this._mainFrame!;
return this._mainFrame;
}
frame(options: string | { name?: string, url?: types.URLMatch }): Frame | null {
@ -165,48 +164,48 @@ export class Page extends ChannelOwner<PageChannel> {
}
async $(selector: string): Promise<ElementHandle<Element> | null> {
return await this._mainFrame!.$(selector);
return await this._mainFrame.$(selector);
}
async waitForSelector(selector: string, options?: types.WaitForElementOptions): Promise<ElementHandle<Element> | null> {
return await this._mainFrame!.waitForSelector(selector, options);
return await this._mainFrame.waitForSelector(selector, options);
}
async dispatchEvent(selector: string, type: string, eventInit?: Object, options?: types.TimeoutOptions): Promise<void> {
return await this._mainFrame!.dispatchEvent(selector, type, eventInit, options);
return await this._mainFrame.dispatchEvent(selector, type, eventInit, options);
}
async evaluateHandle<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<SmartHandle<R>>;
async evaluateHandle<R>(pageFunction: Func1<void, R>, arg?: any): Promise<SmartHandle<R>>;
async evaluateHandle<R, Arg>(pageFunction: Func1<Arg, R>, arg: Arg): Promise<SmartHandle<R>> {
assertMaxArguments(arguments.length, 2);
return await this._mainFrame!.evaluateHandle(pageFunction, arg);
return await this._mainFrame.evaluateHandle(pageFunction, arg);
}
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R>;
async $eval<R>(selector: string, pageFunction: FuncOn<Element, void, R>, arg?: any): Promise<R>;
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R> {
assertMaxArguments(arguments.length, 3);
return await this._mainFrame!.$eval(selector, pageFunction, arg);
return await this._mainFrame.$eval(selector, pageFunction, arg);
}
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R>;
async $$eval<R>(selector: string, pageFunction: FuncOn<Element[], void, R>, arg?: any): Promise<R>;
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R> {
assertMaxArguments(arguments.length, 3);
return await this._mainFrame!.$$eval(selector, pageFunction, arg);
return await this._mainFrame.$$eval(selector, pageFunction, arg);
}
async $$(selector: string): Promise<ElementHandle<Element>[]> {
return await this._mainFrame!.$$(selector);
return await this._mainFrame.$$(selector);
}
async addScriptTag(options: { url?: string; path?: string; content?: string; type?: string; }): Promise<ElementHandle> {
return await this._mainFrame!.addScriptTag(options);
return await this._mainFrame.addScriptTag(options);
}
async addStyleTag(options: { url?: string; path?: string; content?: string; }): Promise<ElementHandle> {
return await this._mainFrame!.addStyleTag(options);
return await this._mainFrame.addStyleTag(options);
}
async exposeFunction(name: string, playwrightFunction: Function) {
@ -247,11 +246,11 @@ export class Page extends ChannelOwner<PageChannel> {
}
async waitForLoadState(state?: types.LifecycleEvent, options?: types.TimeoutOptions): Promise<void> {
return this._mainFrame!.waitForLoadState(state, options);
return this._mainFrame.waitForLoadState(state, options);
}
async waitForNavigation(options?: types.WaitForNavigationOptions): Promise<Response | null> {
return this._mainFrame!.waitForNavigation(options);
return this._mainFrame.waitForNavigation(options);
}
async waitForRequest(urlOrPredicate: string | RegExp | ((r: Request) => boolean), options: types.TimeoutOptions = {}): Promise<Request> {
@ -455,31 +454,24 @@ export class Worker extends EventEmitter {
}
}
export class BindingCall extends ChannelOwner<BindingCallChannel> {
name: string = '';
source: { context: BrowserContext, page: Page, frame: Frame } | undefined;
args: any[] = [];
export class BindingCall extends ChannelOwner<BindingCallChannel, BindingCallInitializer> {
static from(channel: BindingCallChannel): BindingCall {
return channel._object;
}
constructor(connection: Connection, channel: BindingCallChannel) {
super(connection, channel);
}
_initialize(params: { name: string, context: BrowserContextChannel, page: PageChannel, frame: FrameChannel, args: any[] }) {
this.name = params.name;
this.source = {
context: BrowserContext.from(params.context),
page: Page.from(params.page),
frame: Frame.from(params.frame)
};
this.args = params.args;
constructor(connection: Connection, channel: BindingCallChannel, initializer: BindingCallInitializer) {
super(connection, channel, initializer);
}
async call(func: FunctionWithSource) {
try {
this._channel.resolve({ result: await func(this.source!, ...this.args) });
const frame = Frame.from(this._initializer.frame);
const source = {
context: frame._page!._browserContext!,
page: frame._page!,
frame
};
this._channel.resolve({ result: await func(source, ...this._initializer.args) });
} catch (e) {
this._channel.reject({ error: serializeError(e) });
}

View file

@ -26,62 +26,75 @@ import { Request, Response, Route } from './client/network';
import { Page, BindingCall } from './client/page';
import debug = require('debug');
import { Channel } from './channels';
import { ConsoleMessage } from './client/console';
import { ConsoleMessage } from './client/consoleMessage';
export class Connection {
private _channels = new Map<string, Channel>();
private _waitingForObject = new Map<string, any>();
sendMessageToServerTransport = (message: any): Promise<any> => Promise.resolve();
constructor() {}
createRemoteObject(type: string, guid: string): any {
private _createRemoteObject(type: string, guid: string, initializer: any): any {
const channel = this._createChannel(guid) as any;
this._channels.set(guid, channel);
let result: ChannelOwner<any>;
let result: ChannelOwner<any, any>;
initializer = this._replaceGuidsWithChannels(initializer);
switch (type) {
case 'browserType':
result = new BrowserType(this, channel);
result = new BrowserType(this, channel, initializer);
break;
case 'browser':
result = new Browser(this, channel);
result = new Browser(this, channel, initializer);
break;
case 'context':
result = new BrowserContext(this, channel);
result = new BrowserContext(this, channel, initializer);
break;
case 'page':
result = new Page(this, channel);
result = new Page(this, channel, initializer);
break;
case 'frame':
result = new Frame(this, channel);
result = new Frame(this, channel, initializer);
break;
case 'request':
result = new Request(this, channel);
result = new Request(this, channel, initializer);
break;
case 'response':
result = new Response(this, channel);
result = new Response(this, channel, initializer);
break;
case 'route':
result = new Route(this, channel);
result = new Route(this, channel, initializer);
break;
case 'bindingCall':
result = new BindingCall(this, channel);
result = new BindingCall(this, channel, initializer);
break;
case 'jsHandle':
result = new JSHandle(this, channel);
result = new JSHandle(this, channel, initializer);
break;
case 'elementHandle':
result = new ElementHandle(this, channel);
result = new ElementHandle(this, channel, initializer);
break;
case 'consoleMessage':
result = new ConsoleMessage(this, channel);
result = new ConsoleMessage(this, channel, initializer);
break;
default:
throw new Error('Missing type ' + type);
}
channel._object = result;
const callback = this._waitingForObject.get(guid);
if (callback) {
callback(result);
this._waitingForObject.delete(guid);
}
return result;
}
waitForObjectWithKnownName(guid: string): Promise<any> {
if (this._channels.has(guid))
return this._channels.get(guid)!._object;
return new Promise(f => this._waitingForObject.set(guid, f));
}
async sendMessageToServer(message: { guid: string, method: string, params: any }) {
const converted = {...message, params: this._replaceChannelsWithGuids(message.params)};
debug('pw:channel:command')(converted);
@ -95,15 +108,11 @@ export class Connection {
const { guid, method, params } = message;
if (method === '__create__') {
this.createRemoteObject(params.type, guid);
this._createRemoteObject(params.type, guid, params.initializer);
return;
}
const channel = this._channels.get(guid)!;
if (message.method === '__init__') {
channel._object._initialize(this._replaceGuidsWithChannels(params));
return;
}
channel.emit(method, this._replaceGuidsWithChannels(params));
}

View file

@ -18,13 +18,13 @@ import { EventEmitter } from 'events';
import { helper } from '../helper';
import { Channel } from './channels';
export class Dispatcher extends EventEmitter implements Channel {
export class Dispatcher<Initializer> extends EventEmitter implements Channel {
readonly _guid: string;
readonly _type: string;
protected _scope: DispatcherScope;
_object: any;
constructor(scope: DispatcherScope, object: any, type: string, guid = type + '@' + helper.guid()) {
constructor(scope: DispatcherScope, object: any, type: string, initializer: Initializer, guid = type + '@' + helper.guid()) {
super();
this._type = type;
this._guid = guid;
@ -32,20 +32,16 @@ export class Dispatcher extends EventEmitter implements Channel {
this._scope = scope;
scope.dispatchers.set(this._guid, this);
object[scope.dispatcherSymbol] = this;
this._scope.sendMessageToClient(this._guid, '__create__', { type });
this._scope.sendMessageToClient(this._guid, '__create__', { type, initializer });
}
_initialize(payload: any) {
this._scope.sendMessageToClient(this._guid, '__init__', payload);
}
_dispatchEvent(method: string, params: Dispatcher | any = {}) {
_dispatchEvent(method: string, params: Dispatcher<any> | any = {}) {
this._scope.sendMessageToClient(this._guid, method, params);
}
}
export class DispatcherScope {
readonly dispatchers = new Map<string, Dispatcher>();
readonly dispatchers = new Map<string, Dispatcher<any>>();
readonly dispatcherSymbol = Symbol('dispatcher');
sendMessageToClientTransport = (message: any) => {};

View file

@ -17,14 +17,13 @@
import * as types from '../../types';
import { BrowserContextBase, BrowserContext } from '../../browserContext';
import { Events } from '../../events';
import { BrowserDispatcher } from './browserDispatcher';
import { Dispatcher, DispatcherScope } from '../dispatcher';
import { PageDispatcher, BindingCallDispatcher } from './pageDispatcher';
import { PageChannel, BrowserContextChannel } from '../channels';
import { PageChannel, BrowserContextChannel, BrowserContextInitializer } from '../channels';
import { RouteDispatcher, RequestDispatcher } from './networkDispatchers';
import { Page } from '../../page';
export class BrowserContextDispatcher extends Dispatcher implements BrowserContextChannel {
export class BrowserContextDispatcher extends Dispatcher<BrowserContextInitializer> implements BrowserContextChannel {
private _context: BrowserContextBase;
static from(scope: DispatcherScope, browserContext: BrowserContext): BrowserContextDispatcher {
@ -34,10 +33,7 @@ export class BrowserContextDispatcher extends Dispatcher implements BrowserConte
}
constructor(scope: DispatcherScope, context: BrowserContextBase) {
super(scope, context, 'context');
this._initialize({
browser: BrowserDispatcher.from(scope, context._browserBase)
});
super(scope, context, 'context', {});
this._context = context;
context.on(Events.BrowserContext.Page, page => this._dispatchEvent('page', PageDispatcher.from(this._scope, page)));
context.on(Events.BrowserContext.Close, () => {

View file

@ -18,11 +18,11 @@ import { BrowserBase } from '../../browser';
import { BrowserContextBase } from '../../browserContext';
import * as types from '../../types';
import { BrowserContextDispatcher } from './browserContextDispatcher';
import { BrowserChannel, BrowserContextChannel, PageChannel } from '../channels';
import { BrowserChannel, BrowserContextChannel, PageChannel, BrowserInitializer } from '../channels';
import { Dispatcher, DispatcherScope } from '../dispatcher';
import { PageDispatcher } from './pageDispatcher';
export class BrowserDispatcher extends Dispatcher implements BrowserChannel {
export class BrowserDispatcher extends Dispatcher<BrowserInitializer> implements BrowserChannel {
private _browser: BrowserBase;
static from(scope: DispatcherScope, browser: BrowserBase): BrowserDispatcher {
@ -38,8 +38,7 @@ export class BrowserDispatcher extends Dispatcher implements BrowserChannel {
}
constructor(scope: DispatcherScope, browser: BrowserBase) {
super(scope, browser, 'browser');
this._initialize({});
super(scope, browser, 'browser', {});
this._browser = browser;
}

View file

@ -18,12 +18,12 @@ import { BrowserBase } from '../../browser';
import { BrowserTypeBase } from '../../server/browserType';
import * as types from '../../types';
import { BrowserDispatcher } from './browserDispatcher';
import { BrowserChannel, BrowserTypeChannel, BrowserContextChannel } from '../channels';
import { BrowserChannel, BrowserTypeChannel, BrowserContextChannel, BrowserTypeInitializer } from '../channels';
import { Dispatcher, DispatcherScope } from '../dispatcher';
import { BrowserContextBase } from '../../browserContext';
import { BrowserContextDispatcher } from './browserContextDispatcher';
export class BrowserTypeDispatcher extends Dispatcher implements BrowserTypeChannel {
export class BrowserTypeDispatcher extends Dispatcher<BrowserTypeInitializer> implements BrowserTypeChannel {
private _browserType: BrowserTypeBase;
static from(scope: DispatcherScope, browserType: BrowserTypeBase): BrowserTypeDispatcher {
@ -33,8 +33,10 @@ export class BrowserTypeDispatcher extends Dispatcher implements BrowserTypeChan
}
constructor(scope: DispatcherScope, browserType: BrowserTypeBase) {
super(scope, browserType, 'browserType', browserType.name());
this._initialize({ executablePath: browserType.executablePath(), name: browserType.name() });
super(scope, browserType, 'browserType', {
executablePath: browserType.executablePath(),
name: browserType.name()
}, browserType.name());
this._browserType = browserType;
}

View file

@ -15,11 +15,11 @@
*/
import { ConsoleMessage } from '../../console';
import { ConsoleMessageChannel } from '../channels';
import { ConsoleMessageChannel, ConsoleMessageInitializer } from '../channels';
import { Dispatcher, DispatcherScope } from '../dispatcher';
import { ElementHandleDispatcher } from './elementHandlerDispatcher';
export class ConsoleMessageDispatcher extends Dispatcher implements ConsoleMessageChannel {
export class ConsoleMessageDispatcher extends Dispatcher<ConsoleMessageInitializer> implements ConsoleMessageChannel {
static from(scope: DispatcherScope, message: ConsoleMessage): ConsoleMessageDispatcher {
if ((message as any)[scope.dispatcherSymbol])
return (message as any)[scope.dispatcherSymbol];
@ -27,11 +27,10 @@ export class ConsoleMessageDispatcher extends Dispatcher implements ConsoleMessa
}
constructor(scope: DispatcherScope, message: ConsoleMessage) {
super(scope, message, 'consoleMessage');
this._initialize({
super(scope, message, 'consoleMessage', {
type: message.type(),
text: message.text(),
args: message.args().map(a => ElementHandleDispatcher.from(this._scope, a)),
args: message.args().map(a => ElementHandleDispatcher.from(scope, a)),
location: message.location(),
});
}

View file

@ -51,9 +51,8 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements Eleme
constructor(scope: DispatcherScope, elementHandle: ElementHandle) {
super(scope, elementHandle, true);
super(scope, elementHandle);
this._elementHandle = elementHandle;
this._initialize({ preview: elementHandle.toString(), frame: FrameDispatcher.from(scope, elementHandle._context.frame) });
this._elementHandle = elementHandle;
}

View file

@ -16,13 +16,13 @@
import { Frame } from '../../frames';
import * as types from '../../types';
import { ElementHandleChannel, FrameChannel, JSHandleChannel, ResponseChannel } from '../channels';
import { ElementHandleChannel, FrameChannel, JSHandleChannel, ResponseChannel, FrameInitializer } from '../channels';
import { Dispatcher, DispatcherScope } from '../dispatcher';
import { ElementHandleDispatcher, convertSelectOptionValues } from './elementHandlerDispatcher';
import { JSHandleDispatcher } from './jsHandleDispatcher';
import { ResponseDispatcher } from './networkDispatchers';
export class FrameDispatcher extends Dispatcher implements FrameChannel {
export class FrameDispatcher extends Dispatcher<FrameInitializer> implements FrameChannel {
private _frame: Frame;
static from(scope: DispatcherScope, frame: Frame): FrameDispatcher {
@ -38,14 +38,12 @@ export class FrameDispatcher extends Dispatcher implements FrameChannel {
}
constructor(scope: DispatcherScope, frame: Frame) {
super(scope, frame, 'frame');
this._frame = frame;
const parentFrame = frame.parentFrame();
this._initialize({
super(scope, frame, 'frame', {
url: frame.url(),
name: frame.name(),
parentFrame: FrameDispatcher.fromNullable(this._scope, parentFrame)
parentFrame: FrameDispatcher.fromNullable(scope, frame.parentFrame())
});
this._frame = frame;
}
async goto(params: { url: string, options: types.GotoOptions }): Promise<ResponseChannel | null> {

View file

@ -15,17 +15,17 @@
*/
import * as js from '../../javascript';
import { JSHandleChannel } from '../channels';
import { JSHandleChannel, JSHandleInitializer } from '../channels';
import { Dispatcher, DispatcherScope } from '../dispatcher';
import { convertArg } from './frameDispatcher';
export class JSHandleDispatcher extends Dispatcher implements JSHandleChannel {
export class JSHandleDispatcher extends Dispatcher<JSHandleInitializer> implements JSHandleChannel {
readonly _jsHandle: js.JSHandle<any>;
constructor(scope: DispatcherScope, jsHandle: js.JSHandle, omitInit?: boolean) {
super(scope, jsHandle, jsHandle.asElement() ? 'elementHandle' : 'jsHandle');
if (!omitInit)
this._initialize({ preview: jsHandle.toString() });
constructor(scope: DispatcherScope, jsHandle: js.JSHandle) {
super(scope, jsHandle, jsHandle.asElement() ? 'elementHandle' : 'jsHandle', {
preview: jsHandle.toString(),
});
this._jsHandle = jsHandle;
}

View file

@ -16,11 +16,11 @@
import { Request, Response, Route } from '../../network';
import * as types from '../../types';
import { RequestChannel, ResponseChannel, RouteChannel } from '../channels';
import { RequestChannel, ResponseChannel, RouteChannel, ResponseInitializer, RequestInitializer, RouteInitializer } from '../channels';
import { Dispatcher, DispatcherScope } from '../dispatcher';
import { FrameDispatcher } from './frameDispatcher';
export class RequestDispatcher extends Dispatcher implements RequestChannel {
export class RequestDispatcher extends Dispatcher<RequestInitializer> implements RequestChannel {
private _request: Request;
static from(scope: DispatcherScope, request: Request): RequestDispatcher {
@ -34,18 +34,15 @@ export class RequestDispatcher extends Dispatcher implements RequestChannel {
}
constructor(scope: DispatcherScope, request: Request) {
super(scope, request, 'request');
this._initialize({
super(scope, request, 'request', {
frame: FrameDispatcher.from(scope, request.frame()),
url: request.url(),
resourceType: request.resourceType(),
method: request.method(),
postData: request.postData(),
headers: request.headers(),
isNavigationRequest: request.isNavigationRequest(),
failure: request.failure(),
frame: FrameDispatcher.from(this._scope, request.frame()),
redirectedFrom: RequestDispatcher.fromNullable(this._scope, request.redirectedFrom()),
redirectedTo: RequestDispatcher.fromNullable(this._scope, request.redirectedTo()),
redirectedFrom: RequestDispatcher.fromNullable(scope, request.redirectedFrom()),
});
this._request = request;
}
@ -55,7 +52,7 @@ export class RequestDispatcher extends Dispatcher implements RequestChannel {
}
}
export class ResponseDispatcher extends Dispatcher implements ResponseChannel {
export class ResponseDispatcher extends Dispatcher<ResponseInitializer> implements ResponseChannel {
private _response: Response;
static from(scope: DispatcherScope, response: Response): ResponseDispatcher {
@ -69,12 +66,9 @@ export class ResponseDispatcher extends Dispatcher implements ResponseChannel {
}
constructor(scope: DispatcherScope, response: Response) {
super(scope, response, 'response');
this._initialize({
frame: FrameDispatcher.from(this._scope, response.frame()),
request: RequestDispatcher.from(this._scope, response.request())!,
super(scope, response, 'response', {
request: RequestDispatcher.from(scope, response.request())!,
url: response.url(),
ok: response.ok(),
status: response.status(),
statusText: response.statusText(),
headers: response.headers(),
@ -91,7 +85,7 @@ export class ResponseDispatcher extends Dispatcher implements ResponseChannel {
}
}
export class RouteDispatcher extends Dispatcher implements RouteChannel {
export class RouteDispatcher extends Dispatcher<RouteInitializer> implements RouteChannel {
private _route: Route;
static from(scope: DispatcherScope, route: Route): RouteDispatcher {
@ -105,8 +99,9 @@ export class RouteDispatcher extends Dispatcher implements RouteChannel {
}
constructor(scope: DispatcherScope, route: Route) {
super(scope, route, 'route');
this._initialize({ request: RequestDispatcher.from(this._scope, route.request()) });
super(scope, route, 'route', {
request: RequestDispatcher.from(scope, route.request())
});
this._route = route;
}

View file

@ -19,16 +19,15 @@ import { Request } from '../../network';
import { Frame } from '../../frames';
import { Page } from '../../page';
import * as types from '../../types';
import { ElementHandleChannel, PageChannel, ResponseChannel, BindingCallChannel } from '../channels';
import { ElementHandleChannel, PageChannel, ResponseChannel, BindingCallChannel, PageInitializer, BindingCallInitializer } from '../channels';
import { Dispatcher, DispatcherScope } from '../dispatcher';
import { BrowserContextDispatcher } from './browserContextDispatcher';
import { FrameDispatcher } from './frameDispatcher';
import { RequestDispatcher, ResponseDispatcher, RouteDispatcher } from './networkDispatchers';
import { ConsoleMessageDispatcher } from './consoleMessageDispatcher';
import { BrowserContext } from '../../browserContext';
import { serializeError, parseError } from '../../helper';
export class PageDispatcher extends Dispatcher implements PageChannel {
export class PageDispatcher extends Dispatcher<PageInitializer> implements PageChannel {
private _page: Page;
static from(scope: DispatcherScope, page: Page): PageDispatcher {
@ -44,11 +43,9 @@ export class PageDispatcher extends Dispatcher implements PageChannel {
}
constructor(scope: DispatcherScope, page: Page) {
super(scope, page, 'page');
this._initialize({
browserContext: BrowserContextDispatcher.from(scope, page._browserContext),
super(scope, page, 'page', {
mainFrame: FrameDispatcher.from(scope, page.mainFrame()),
frames: page.frames().map(f => FrameDispatcher.from(this._scope, f)),
viewportSize: page.viewportSize()
});
this._page = page;
page.on(Events.Page.Close, () => this._dispatchEvent('close'));
@ -196,18 +193,15 @@ export class PageDispatcher extends Dispatcher implements PageChannel {
}
export class BindingCallDispatcher extends Dispatcher implements BindingCallChannel {
export class BindingCallDispatcher extends Dispatcher<BindingCallInitializer> implements BindingCallChannel {
private _resolve: ((arg: any) => void) | undefined;
private _reject: ((error: any) => void) | undefined;
private _promise: Promise<any>;
constructor(scope: DispatcherScope, name: string, source: { context: BrowserContext, page: Page, frame: Frame }, args: any[]) {
super(scope, {}, 'bindingCall');
this._initialize({
name,
context: BrowserContextDispatcher.from(scope, source.context),
page: PageDispatcher.from(scope, source.page),
super(scope, {}, 'bindingCall', {
frame: FrameDispatcher.from(scope, source.frame),
name,
args
});
this._promise = new Promise((resolve, reject) => {

View file

@ -113,16 +113,15 @@ function collect(browserNames) {
for (const browserName of browserNames) {
const browserType = playwright[browserName];
let overridenBrowserType = browserType;
// Channel substitute
if (process.env.PWCHANNEL) {
BrowserTypeDispatcher.from(dispatcherScope, browserType);
overridenBrowserType = connection.createRemoteObject('browserType', browserType.name());
}
const browserTypeEnvironment = new Environment('BrowserType');
browserTypeEnvironment.beforeAll(async state => {
// Channel substitute
let overridenBrowserType = browserType;
if (process.env.PWCHANNEL) {
BrowserTypeDispatcher.from(dispatcherScope, browserType);
overridenBrowserType = await connection.waitForObjectWithKnownName(browserType.name());
}
state.browserType = overridenBrowserType;
});
browserTypeEnvironment.afterAll(async state => {