Skip to content

Commit

Permalink
feat(rpc): do not use server types and events in rpc/client (#3219)
Browse files Browse the repository at this point in the history
This change removes almost all dependencies from rpc/client
to the rest of the project. The last ones would be utilities
like helper, converters, etc.
  • Loading branch information
dgozman authored Jul 30, 2020
1 parent 7dd9f2c commit 3bd9777
Show file tree
Hide file tree
Showing 24 changed files with 1,031 additions and 204 deletions.
659 changes: 659 additions & 0 deletions src/rpc/channels.ts

Large diffs are not rendered by default.

26 changes: 22 additions & 4 deletions src/rpc/client/accessibility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,28 @@
* limitations under the License.
*/

import { PageChannel } from '../channels';
import { PageChannel, AXNode } from '../channels';
import { ElementHandle } from './elementHandle';
import * as types from '../../types';
import { axNodeFromProtocol } from '../serializers';

type SerializedAXNode = Omit<AXNode, 'valueString' | 'valueNumber' | 'children' | 'checked' | 'pressed'> & {
value?: string|number,
checked?: boolean | 'mixed',
pressed?: boolean | 'mixed',
children?: SerializedAXNode[]
};

function axNodeFromProtocol(axNode: AXNode): SerializedAXNode {
const result: SerializedAXNode = {
...axNode,
value: axNode.valueNumber !== undefined ? axNode.valueNumber : axNode.valueString,
checked: axNode.checked === 'checked' ? true : axNode.checked === 'unchecked' ? false : axNode.checked,
pressed: axNode.pressed === 'pressed' ? true : axNode.pressed === 'released' ? false : axNode.pressed,
children: axNode.children ? axNode.children.map(axNodeFromProtocol) : undefined,
};
delete (result as any).valueNumber;
delete (result as any).valueString;
return result;
}

export class Accessibility {
private _channel: PageChannel;
Expand All @@ -27,7 +45,7 @@ export class Accessibility {
this._channel = channel;
}

async snapshot(options: { interestingOnly?: boolean; root?: ElementHandle } = {}): Promise<types.SerializedAXNode | null> {
async snapshot(options: { interestingOnly?: boolean; root?: ElementHandle } = {}): Promise<SerializedAXNode | null> {
const root = options.root ? options.root._elementChannel : undefined;
const result = await this._channel.accessibilitySnapshot({ interestingOnly: options.interestingOnly, root });
return result.rootAXNode ? axNodeFromProtocol(result.rootAXNode) : null;
Expand Down
9 changes: 4 additions & 5 deletions src/rpc/client/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@
* limitations under the License.
*/

import * as types from '../../types';
import { BrowserChannel, BrowserInitializer, BrowserNewContextParams } from '../channels';
import { BrowserContext } from './browserContext';
import { Page } from './page';
import { ChannelOwner } from './channelOwner';
import { Events } from '../../events';
import { LoggerSink } from '../../loggerSink';
import { Events } from './events';
import { BrowserType } from './browserType';
import { headersObjectToArray } from '../../converters';
import { BrowserContextOptions } from './types';

export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
readonly _contexts = new Set<BrowserContext>();
Expand Down Expand Up @@ -50,7 +49,7 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
this._closedPromise = new Promise(f => this.once(Events.Browser.Disconnected, f));
}

async newContext(options: types.BrowserContextOptions & { logger?: LoggerSink } = {}): Promise<BrowserContext> {
async newContext(options: BrowserContextOptions = {}): Promise<BrowserContext> {
const logger = options.logger;
options = { ...options, logger: undefined };
return this._wrapApiCall('browser.newContext', async () => {
Expand All @@ -75,7 +74,7 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
return this._initializer.version;
}

async newPage(options: types.BrowserContextOptions & { logger?: LoggerSink } = {}): Promise<Page> {
async newPage(options: BrowserContextOptions = {}): Promise<Page> {
const context = await this.newContext(options);
const page = await context.newPage();
page._ownedContext = context;
Expand Down
18 changes: 9 additions & 9 deletions src/rpc/client/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@

import * as frames from './frame';
import { Page, BindingCall } from './page';
import * as types from '../../types';
import * as network from './network';
import { BrowserContextChannel, BrowserContextInitializer } from '../channels';
import { ChannelOwner } from './channelOwner';
import { helper } from '../../helper';
import { Browser } from './browser';
import { Events } from '../../events';
import { Events } from './events';
import { TimeoutSettings } from '../../timeoutSettings';
import { Waiter } from './waiter';
import { headersObjectToArray } from '../../converters';
import { URLMatch, Headers, WaitForEventOptions } from './types';

export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserContextInitializer> {
_pages = new Set<Page>();
private _routes: { url: types.URLMatch, handler: network.RouteHandler }[] = [];
private _routes: { url: URLMatch, handler: network.RouteHandler }[] = [];
readonly _browser: Browser | undefined;
readonly _browserName: string;
readonly _bindings = new Map<string, frames.FunctionWithSource>();
Expand Down Expand Up @@ -138,13 +138,13 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
});
}

async setGeolocation(geolocation: types.Geolocation | null): Promise<void> {
async setGeolocation(geolocation: { longitude: number, latitude: number, accuracy?: number } | null): Promise<void> {
return this._wrapApiCall('browserContext.setGeolocation', async () => {
await this._channel.setGeolocation({ geolocation: geolocation || undefined });
});
}

async setExtraHTTPHeaders(headers: types.Headers): Promise<void> {
async setExtraHTTPHeaders(headers: Headers): Promise<void> {
return this._wrapApiCall('browserContext.setExtraHTTPHeaders', async () => {
await this._channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) });
});
Expand All @@ -156,7 +156,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
});
}

async setHTTPCredentials(httpCredentials: types.Credentials | null): Promise<void> {
async setHTTPCredentials(httpCredentials: { username: string, password: string } | null): Promise<void> {
return this._wrapApiCall('browserContext.setHTTPCredentials', async () => {
await this._channel.setHTTPCredentials({ httpCredentials: httpCredentials || undefined });
});
Expand Down Expand Up @@ -186,23 +186,23 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
await this.exposeBinding(name, (source, ...args) => playwrightFunction(...args));
}

async route(url: types.URLMatch, handler: network.RouteHandler): Promise<void> {
async route(url: URLMatch, handler: network.RouteHandler): Promise<void> {
return this._wrapApiCall('browserContext.route', async () => {
this._routes.push({ url, handler });
if (this._routes.length === 1)
await this._channel.setNetworkInterceptionEnabled({ enabled: true });
});
}

async unroute(url: types.URLMatch, handler?: network.RouteHandler): Promise<void> {
async unroute(url: URLMatch, handler?: network.RouteHandler): Promise<void> {
return this._wrapApiCall('browserContext.unroute', async () => {
this._routes = this._routes.filter(route => route.url !== url || (handler && route.handler !== handler));
if (this._routes.length === 0)
await this._channel.setNetworkInterceptionEnabled({ enabled: false });
});
}

async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
const waiter = new Waiter();
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/client/browserServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { ChildProcess } from 'child_process';
import { BrowserServerChannel, BrowserServerInitializer } from '../channels';
import { ChannelOwner } from './channelOwner';
import { Events } from '../../events';
import { Events } from './events';

export class BrowserServer extends ChannelOwner<BrowserServerChannel, BrowserServerInitializer> {
static from(server: BrowserServerChannel): BrowserServer {
Expand Down
13 changes: 5 additions & 8 deletions src/rpc/client/browserType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,15 @@
* limitations under the License.
*/

import * as types from '../../types';
import { BrowserTypeChannel, BrowserTypeInitializer, BrowserTypeLaunchParams, BrowserTypeLaunchServerParams, BrowserTypeLaunchPersistentContextParams } from '../channels';
import { Browser } from './browser';
import { BrowserContext } from './browserContext';
import { ChannelOwner } from './channelOwner';
import { BrowserServer } from './browserServer';
import { LoggerSink } from '../../loggerSink';
import { headersObjectToArray, envObjectToArray } from '../../converters';
import { serializeArgument } from './jsHandle';
import { assert } from '../../helper';

type FirefoxPrefsOptions = { firefoxUserPrefs?: { [key: string]: string | number | boolean } };
import { LaunchOptions, LaunchServerOptions, BrowserContextOptions, ConnectOptions } from './types';

export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeInitializer> {

Expand All @@ -45,7 +42,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
return this._initializer.name;
}

async launch(options: types.LaunchOptions & FirefoxPrefsOptions & { logger?: LoggerSink } = {}): Promise<Browser> {
async launch(options: LaunchOptions = {}): Promise<Browser> {
const logger = options.logger;
options = { ...options, logger: undefined };
return this._wrapApiCall('browserType.launch', async () => {
Expand All @@ -64,7 +61,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
}, logger);
}

async launchServer(options: types.LaunchServerOptions & FirefoxPrefsOptions & { logger?: LoggerSink } = {}): Promise<BrowserServer> {
async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServer> {
const logger = options.logger;
options = { ...options, logger: undefined };
return this._wrapApiCall('browserType.launchServer', async () => {
Expand All @@ -79,7 +76,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
}, logger);
}

async launchPersistentContext(userDataDir: string, options: types.LaunchOptions & types.BrowserContextOptions & { logger?: LoggerSink } = {}): Promise<BrowserContext> {
async launchPersistentContext(userDataDir: string, options: LaunchOptions & BrowserContextOptions = {}): Promise<BrowserContext> {
const logger = options.logger;
options = { ...options, logger: undefined };
return this._wrapApiCall('browserType.launchPersistentContext', async () => {
Expand All @@ -100,7 +97,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
}, logger);
}

async connect(options: types.ConnectOptions & { logger?: LoggerSink }): Promise<Browser> {
async connect(options: ConnectOptions): Promise<Browser> {
const logger = options.logger;
options = { ...options, logger: undefined };
return this._wrapApiCall('browserType.connect', async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/client/channelOwner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { EventEmitter } from 'events';
import type { Channel } from '../channels';
import type { Connection } from './connection';
import type { LoggerSink } from '../../loggerSink';
import type { LoggerSink } from './types';
import { DebugLoggerSink } from '../../logger';

export abstract class ChannelOwner<T extends Channel = Channel, Initializer = {}> extends EventEmitter {
Expand Down
6 changes: 3 additions & 3 deletions src/rpc/client/chromiumBrowserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { Page } from './page';
import { BrowserContextInitializer } from '../channels';
import { ChannelOwner } from './channelOwner';
import { CDPSession } from './cdpSession';
import { Events as ChromiumEvents } from '../../chromium/events';
import { Events } from './events';
import { Worker } from './worker';
import { BrowserContext } from './browserContext';

Expand All @@ -32,13 +32,13 @@ export class ChromiumBrowserContext extends BrowserContext {
this._channel.on('crBackgroundPage', ({ page }) => {
const backgroundPage = Page.from(page);
this._backgroundPages.add(backgroundPage);
this.emit(ChromiumEvents.ChromiumBrowserContext.BackgroundPage, backgroundPage);
this.emit(Events.ChromiumBrowserContext.BackgroundPage, backgroundPage);
});
this._channel.on('crServiceWorker', ({worker}) => {
const serviceWorker = Worker.from(worker);
serviceWorker._context = this;
this._serviceWorkers.add(serviceWorker);
this.emit(ChromiumEvents.ChromiumBrowserContext.ServiceWorker, serviceWorker);
this.emit(Events.ChromiumBrowserContext.ServiceWorker, serviceWorker);
});
}

Expand Down
16 changes: 10 additions & 6 deletions src/rpc/client/chromiumCoverage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@
* limitations under the License.
*/

import * as types from '../../types';
import { PageChannel } from '../channels';
import { PageChannel, PageCrStartJSCoverageOptions, PageCrStopJSCoverageResult, PageCrStartCSSCoverageOptions, PageCrStopCSSCoverageResult } from '../channels';

let __dummyJSResult: PageCrStopJSCoverageResult;
type PageCrStopJSCoverageResultEntries = typeof __dummyJSResult.entries;
let __dummyCSSResult: PageCrStopCSSCoverageResult;
type PageCrStopCSSCoverageResultEntries = typeof __dummyCSSResult.entries;

export class ChromiumCoverage {
private _channel: PageChannel;
Expand All @@ -24,19 +28,19 @@ export class ChromiumCoverage {
this._channel = channel;
}

async startJSCoverage(options: types.JSCoverageOptions = {}) {
async startJSCoverage(options: PageCrStartJSCoverageOptions = {}) {
await this._channel.crStartJSCoverage(options);
}

async stopJSCoverage(): Promise<types.JSCoverageEntry[]> {
async stopJSCoverage(): Promise<PageCrStopJSCoverageResultEntries> {
return (await this._channel.crStopJSCoverage()).entries;
}

async startCSSCoverage(options: types.CSSCoverageOptions = {}) {
async startCSSCoverage(options: PageCrStartCSSCoverageOptions = {}) {
await this._channel.crStartCSSCoverage(options);
}

async stopCSSCoverage(): Promise<types.CSSCoverageEntry[]> {
async stopCSSCoverage(): Promise<PageCrStopCSSCoverageResultEntries> {
return (await this._channel.crStopCSSCoverage()).entries;
}
}
4 changes: 3 additions & 1 deletion src/rpc/client/consoleMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
*/

import * as util from 'util';
import { ConsoleMessageLocation } from '../../types';
import { JSHandle } from './jsHandle';
import { ConsoleMessageChannel, ConsoleMessageInitializer } from '../channels';
import { ChannelOwner } from './channelOwner';

let __dummyInitializer: ConsoleMessageInitializer;
type ConsoleMessageLocation = typeof __dummyInitializer.location;

export class ConsoleMessage extends ChannelOwner<ConsoleMessageChannel, ConsoleMessageInitializer> {
static from(message: ConsoleMessageChannel): ConsoleMessage {
return (message as any)._object;
Expand Down
20 changes: 9 additions & 11 deletions src/rpc/client/electron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,16 @@
* limitations under the License.
*/

import * as types from '../../types';
import { ElectronChannel, ElectronInitializer, ElectronApplicationChannel, ElectronApplicationInitializer, ElectronLaunchParams } from '../channels';
import { ElectronChannel, ElectronInitializer, ElectronApplicationChannel, ElectronApplicationInitializer, ElectronLaunchParams, ElectronLaunchOptions } from '../channels';
import { BrowserContext } from './browserContext';
import { ChannelOwner } from './channelOwner';
import { Page } from './page';
import { serializeArgument, FuncOn, parseResult, SmartHandle, JSHandle } from './jsHandle';
import { ElectronEvents, ElectronLaunchOptionsBase } from '../../server/electron';
import { TimeoutSettings } from '../../timeoutSettings';
import { Waiter } from './waiter';
import { Events } from '../../events';
import { LoggerSink } from '../../loggerSink';
import { Events } from './events';
import { envObjectToArray } from '../../converters';
import { WaitForEventOptions, Env, LoggerSink } from './types';

export class Electron extends ChannelOwner<ElectronChannel, ElectronInitializer> {
static from(electron: ElectronChannel): Electron {
Expand All @@ -36,7 +34,7 @@ export class Electron extends ChannelOwner<ElectronChannel, ElectronInitializer>
super(parent, type, guid, initializer);
}

async launch(executablePath: string, options: ElectronLaunchOptionsBase & { logger?: LoggerSink } = {}): Promise<ElectronApplication> {
async launch(executablePath: string, options: ElectronLaunchOptions & { env?: Env, logger?: LoggerSink } = {}): Promise<ElectronApplication> {
const logger = options.logger;
options = { ...options, logger: undefined };
return this._wrapApiCall('electron.launch', async () => {
Expand Down Expand Up @@ -66,10 +64,10 @@ export class ElectronApplication extends ChannelOwner<ElectronApplicationChannel
const window = Page.from(page);
(window as any).browserWindow = JSHandle.from(browserWindow);
this._windows.add(window);
this.emit(ElectronEvents.ElectronApplication.Window, window);
this.emit(Events.ElectronApplication.Window, window);
window.once(Events.Page.Close, () => this._windows.delete(window));
});
this._channel.on('close', () => this.emit(ElectronEvents.ElectronApplication.Close));
this._channel.on('close', () => this.emit(Events.ElectronApplication.Close));
}

windows(): Page[] {
Expand All @@ -95,13 +93,13 @@ export class ElectronApplication extends ChannelOwner<ElectronApplicationChannel
await this._channel.close();
}

async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
const waiter = new Waiter();
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
if (event !== ElectronEvents.ElectronApplication.Close)
waiter.rejectOnEvent(this, ElectronEvents.ElectronApplication.Close, new Error('Electron application closed'));
if (event !== Events.ElectronApplication.Close)
waiter.rejectOnEvent(this, Events.ElectronApplication.Close, new Error('Electron application closed'));
const result = await waiter.waitForEvent(this, event, predicate as any);
waiter.dispose();
return result;
Expand Down
Loading

0 comments on commit 3bd9777

Please sign in to comment.