feat(rpc): align types/guids in the protocol with their pdl definition (#3079)

This makes the protocol self-explanatory, and avoids silly conversions
in codegenerators, e.g. cdpSession <-> CDPSession.
This commit is contained in:
Dmitry Gozman 2020-07-22 10:37:21 -07:00 committed by GitHub
parent f50f228a1f
commit 1aee8dfc7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 108 additions and 110 deletions

View file

@ -27,7 +27,7 @@ import { Transport } from './transport';
connection.onmessage = message => transport.send(JSON.stringify(message));
transport.onmessage = message => connection.dispatch(JSON.parse(message));
const playwright = await connection.waitForObjectWithKnownName('playwright');
const playwright = await connection.waitForObjectWithKnownName('Playwright');
const browser = await playwright.chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com');

View file

@ -134,25 +134,16 @@ export class Connection {
let result: ChannelOwner<any, any>;
initializer = this._replaceGuidsWithChannels(initializer);
switch (type) {
case 'bindingCall':
case 'BindingCall':
result = new BindingCall(parent, type, guid, initializer);
break;
case 'browser':
case 'Browser':
if ((parent as BrowserType).name() === 'chromium')
result = new ChromiumBrowser(parent, type, guid, initializer);
else
result = new Browser(parent, type, guid, initializer);
break;
case 'browserServer':
result = new BrowserServer(parent, type, guid, initializer);
break;
case 'browserType':
result = new BrowserType(parent, type, guid, initializer);
break;
case 'cdpSession':
result = new CDPSession(parent, type, guid, initializer);
break;
case 'context':
case 'BrowserContext':
let browserName = '';
if (parent instanceof Electron) {
// Launching electron produces Electron parent for BrowserContext.
@ -169,52 +160,61 @@ export class Connection {
else
result = new BrowserContext(parent, type, guid, initializer, browserName);
break;
case 'consoleMessage':
case 'BrowserServer':
result = new BrowserServer(parent, type, guid, initializer);
break;
case 'BrowserType':
result = new BrowserType(parent, type, guid, initializer);
break;
case 'CDPSession':
result = new CDPSession(parent, type, guid, initializer);
break;
case 'ConsoleMessage':
result = new ConsoleMessage(parent, type, guid, initializer);
break;
case 'dialog':
case 'Dialog':
result = new Dialog(parent, type, guid, initializer);
break;
case 'download':
case 'Download':
result = new Download(parent, type, guid, initializer);
break;
case 'electron':
case 'Electron':
result = new Electron(parent, type, guid, initializer);
break;
case 'electronApplication':
case 'ElectronApplication':
result = new ElectronApplication(parent, type, guid, initializer);
break;
case 'elementHandle':
case 'ElementHandle':
result = new ElementHandle(parent, type, guid, initializer);
break;
case 'frame':
case 'Frame':
result = new Frame(parent, type, guid, initializer);
break;
case 'jsHandle':
case 'JSHandle':
result = new JSHandle(parent, type, guid, initializer);
break;
case 'page':
case 'Page':
result = new Page(parent, type, guid, initializer);
break;
case 'playwright':
case 'Playwright':
result = new Playwright(parent, type, guid, initializer);
break;
case 'request':
case 'Request':
result = new Request(parent, type, guid, initializer);
break;
case 'stream':
case 'Stream':
result = new Stream(parent, type, guid, initializer);
break;
case 'response':
case 'Response':
result = new Response(parent, type, guid, initializer);
break;
case 'route':
case 'Route':
result = new Route(parent, type, guid, initializer);
break;
case 'selectors':
case 'Selectors':
result = new Selectors(parent, type, guid, initializer);
break;
case 'worker':
case 'Worker':
result = new Worker(parent, type, guid, initializer);
break;
default:

View file

@ -30,7 +30,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, Browser
private _context: BrowserContextBase;
constructor(scope: DispatcherScope, context: BrowserContextBase) {
super(scope, context, 'context', {}, true);
super(scope, context, 'BrowserContext', {}, true);
this._context = context;
for (const page of context.pages())

View file

@ -27,7 +27,7 @@ import { headersArrayToObject } from '../serializers';
export class BrowserDispatcher extends Dispatcher<Browser, BrowserInitializer> implements BrowserChannel {
constructor(scope: DispatcherScope, browser: BrowserBase) {
super(scope, browser, 'browser', {}, true);
super(scope, browser, 'Browser', {}, true);
browser.on(Events.Browser.Disconnected, () => {
this._dispatchEvent('close');
this._dispose();

View file

@ -21,7 +21,7 @@ import { Events } from '../../events';
export class BrowserServerDispatcher extends Dispatcher<BrowserServer, BrowserServerInitializer> implements BrowserServerChannel {
constructor(scope: DispatcherScope, browserServer: BrowserServer) {
super(scope, browserServer, 'browserServer', {
super(scope, browserServer, 'BrowserServer', {
wsEndpoint: browserServer.wsEndpoint(),
pid: browserServer.process().pid
});

View file

@ -27,10 +27,10 @@ import { headersArrayToObject, envArrayToObject } from '../serializers';
export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeInitializer> implements BrowserTypeChannel {
constructor(scope: DispatcherScope, browserType: BrowserTypeBase) {
super(scope, browserType, 'browserType', {
super(scope, browserType, 'BrowserType', {
executablePath: browserType.executablePath(),
name: browserType.name()
}, true, browserType.name());
}, true);
}
async launch(params: BrowserTypeLaunchParams): Promise<{ browser: BrowserChannel }> {

View file

@ -21,7 +21,7 @@ import { serializeResult, parseArgument } from './jsHandleDispatcher';
export class CDPSessionDispatcher extends Dispatcher<CRSession, CDPSessionInitializer> implements CDPSessionChannel {
constructor(scope: DispatcherScope, crSession: CRSession) {
super(scope, crSession, 'cdpSession', {}, true);
super(scope, crSession, 'CDPSession', {}, true);
crSession._eventListener = (method, cdpParams) => {
const params = cdpParams ? serializeResult(cdpParams) : undefined;
this._dispatchEvent('event', { method, params });

View file

@ -21,7 +21,7 @@ import { createHandle } from './elementHandlerDispatcher';
export class ConsoleMessageDispatcher extends Dispatcher<ConsoleMessage, ConsoleMessageInitializer> implements ConsoleMessageChannel {
constructor(scope: DispatcherScope, message: ConsoleMessage) {
super(scope, message, 'consoleMessage', {
super(scope, message, 'ConsoleMessage', {
type: message.type(),
text: message.text(),
args: message.args().map(a => createHandle(scope, a)),

View file

@ -20,7 +20,7 @@ import { Dispatcher, DispatcherScope } from './dispatcher';
export class DialogDispatcher extends Dispatcher<Dialog, DialogInitializer> implements DialogChannel {
constructor(scope: DispatcherScope, dialog: Dialog) {
super(scope, dialog, 'dialog', {
super(scope, dialog, 'Dialog', {
type: dialog.type(),
message: dialog.message(),
defaultValue: dialog.defaultValue(),

View file

@ -21,7 +21,7 @@ import { StreamDispatcher } from './streamDispatcher';
export class DownloadDispatcher extends Dispatcher<Download, DownloadInitializer> implements DownloadChannel {
constructor(scope: DispatcherScope, download: Download) {
super(scope, download, 'download', {
super(scope, download, 'Download', {
url: download.url(),
suggestedFilename: download.suggestedFilename(),
});

View file

@ -26,7 +26,7 @@ import { envArrayToObject } from '../serializers';
export class ElectronDispatcher extends Dispatcher<Electron, ElectronInitializer> implements ElectronChannel {
constructor(scope: DispatcherScope, electron: Electron) {
super(scope, electron, 'electron', {}, true);
super(scope, electron, 'Electron', {}, true);
}
async launch(params: ElectronLaunchParams): Promise<{ electronApplication: ElectronApplicationChannel }> {
@ -41,7 +41,7 @@ export class ElectronDispatcher extends Dispatcher<Electron, ElectronInitializer
export class ElectronApplicationDispatcher extends Dispatcher<ElectronApplication, ElectronApplicationInitializer> implements ElectronApplicationChannel {
constructor(scope: DispatcherScope, electronApplication: ElectronApplication) {
super(scope, electronApplication, 'electronApplication', {
super(scope, electronApplication, 'ElectronApplication', {
context: new BrowserContextDispatcher(scope, electronApplication.context() as BrowserContextBase),
});

View file

@ -31,7 +31,7 @@ export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> impleme
}
private constructor(scope: DispatcherScope, frame: Frame) {
super(scope, frame, 'frame', {
super(scope, frame, 'Frame', {
url: frame.url(),
name: frame.name(),
parentFrame: lookupNullableDispatcher<FrameDispatcher>(frame.parentFrame()),

View file

@ -23,7 +23,7 @@ import { parseSerializedValue, serializeValue } from '../serializers';
export class JSHandleDispatcher extends Dispatcher<js.JSHandle, JSHandleInitializer> implements JSHandleChannel {
constructor(scope: DispatcherScope, jsHandle: js.JSHandle) {
super(scope, jsHandle, jsHandle.asElement() ? 'elementHandle' : 'jsHandle', {
super(scope, jsHandle, jsHandle.asElement() ? 'ElementHandle' : 'JSHandle', {
preview: jsHandle.toString(),
});
jsHandle._setPreviewCallback(preview => this._dispatchEvent('previewUpdated', { preview }));

View file

@ -34,7 +34,7 @@ export class RequestDispatcher extends Dispatcher<Request, RequestInitializer> i
private constructor(scope: DispatcherScope, request: Request) {
const postData = request.postData();
super(scope, request, 'request', {
super(scope, request, 'Request', {
frame: FrameDispatcher.from(scope, request.frame()),
url: request.url(),
resourceType: request.resourceType(),
@ -54,7 +54,7 @@ export class RequestDispatcher extends Dispatcher<Request, RequestInitializer> i
export class ResponseDispatcher extends Dispatcher<Response, ResponseInitializer> implements ResponseChannel {
constructor(scope: DispatcherScope, response: Response) {
super(scope, response, 'response', {
super(scope, response, 'Response', {
// TODO: responses in popups can point to non-reported requests.
request: RequestDispatcher.from(scope, response.request()),
url: response.url(),
@ -76,7 +76,7 @@ export class ResponseDispatcher extends Dispatcher<Response, ResponseInitializer
export class RouteDispatcher extends Dispatcher<Route, RouteInitializer> implements RouteChannel {
constructor(scope: DispatcherScope, route: Route) {
super(scope, route, 'route', {
super(scope, route, 'Route', {
// Context route can point to a non-reported request.
request: RequestDispatcher.from(scope, route.request())
});

View file

@ -39,7 +39,7 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
constructor(scope: DispatcherScope, page: Page) {
// TODO: theoretically, there could be more than one frame already.
// If we split pageCreated and pageReady, there should be no main frame during pageCreated.
super(scope, page, 'page', {
super(scope, page, 'Page', {
mainFrame: FrameDispatcher.from(scope, page.mainFrame()),
viewportSize: page.viewportSize() || undefined,
isClosed: page.isClosed()
@ -233,7 +233,7 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
export class WorkerDispatcher extends Dispatcher<Worker, WorkerInitializer> implements WorkerChannel {
constructor(scope: DispatcherScope, worker: Worker) {
super(scope, worker, 'worker', {
super(scope, worker, 'Worker', {
url: worker.url()
});
worker.on(Events.Worker.Close, () => this._dispatchEvent('close'));
@ -254,7 +254,7 @@ export class BindingCallDispatcher extends Dispatcher<{}, BindingCallInitializer
private _promise: Promise<any>;
constructor(scope: DispatcherScope, name: string, source: { context: BrowserContext, page: Page, frame: Frame }, args: any[]) {
super(scope, {}, 'bindingCall', {
super(scope, {}, 'BindingCall', {
frame: lookupDispatcher<FrameDispatcher>(source.frame),
name,
args: args.map(serializeResult),

View file

@ -27,13 +27,13 @@ export class PlaywrightDispatcher extends Dispatcher<Playwright, PlaywrightIniti
const electron = (playwright as any).electron as (Electron | undefined);
const deviceDescriptors = Object.entries(playwright.devices)
.map(([name, descriptor]) => ({ name, descriptor }));
super(scope, playwright, 'playwright', {
super(scope, playwright, 'Playwright', {
chromium: new BrowserTypeDispatcher(scope, playwright.chromium!),
firefox: new BrowserTypeDispatcher(scope, playwright.firefox!),
webkit: new BrowserTypeDispatcher(scope, playwright.webkit!),
electron: electron ? new ElectronDispatcher(scope, electron) : undefined,
deviceDescriptors,
selectors: new SelectorsDispatcher(scope, playwright.selectors),
}, false, 'playwright');
}, false, 'Playwright');
}
}

View file

@ -22,7 +22,7 @@ import * as dom from '../../dom';
export class SelectorsDispatcher extends Dispatcher<Selectors, SelectorsInitializer> implements SelectorsChannel {
constructor(scope: DispatcherScope, selectors: Selectors) {
super(scope, selectors, 'selectors', {});
super(scope, selectors, 'Selectors', {});
}
async register(params: { name: string, source: string, contentScript?: boolean }): Promise<void> {

View file

@ -20,7 +20,7 @@ import * as stream from 'stream';
export class StreamDispatcher extends Dispatcher<stream.Readable, StreamInitializer> implements StreamChannel {
constructor(scope: DispatcherScope, stream: stream.Readable) {
super(scope, stream, 'stream', {});
super(scope, stream, 'Stream', {});
}
async read(params: { size?: number }): Promise<{ binary: Binary }> {

View file

@ -26,14 +26,14 @@ describe.skip(!CHANNEL)('Channels', function() {
const GOLDEN_PRECONDITION = {
_guid: '',
objects: [
{ _guid: 'browserType', objects: [
{ _guid: 'browser', objects: [] }
{ _guid: 'BrowserType', objects: [
{ _guid: 'Browser', objects: [] }
] },
{ _guid: 'browserType', objects: [] },
{ _guid: 'browserType', objects: [] },
{ _guid: 'playwright' },
{ _guid: 'selectors' },
{ _guid: 'electron', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'Playwright' },
{ _guid: 'Selectors' },
{ _guid: 'Electron', objects: [] },
]
};
await expectScopeState(browser, GOLDEN_PRECONDITION);
@ -44,21 +44,21 @@ describe.skip(!CHANNEL)('Channels', function() {
await expectScopeState(browser, {
_guid: '',
objects: [
{ _guid: 'browserType', objects: [] },
{ _guid: 'browserType', objects: [] },
{ _guid: 'browserType', objects: [
{ _guid: 'browser', objects: [
{ _guid: 'context', objects: [
{ _guid: 'frame' },
{ _guid: 'page' },
{ _guid: 'request' },
{ _guid: 'response' },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'BrowserType', objects: [
{ _guid: 'Browser', objects: [
{ _guid: 'BrowserContext', objects: [
{ _guid: 'Frame' },
{ _guid: 'Page' },
{ _guid: 'Request' },
{ _guid: 'Response' },
]},
] },
] },
{ _guid: 'playwright' },
{ _guid: 'selectors' },
{ _guid: 'electron', objects: [] },
{ _guid: 'Playwright' },
{ _guid: 'Selectors' },
{ _guid: 'Electron', objects: [] },
]
});
@ -70,14 +70,14 @@ describe.skip(!CHANNEL)('Channels', function() {
const GOLDEN_PRECONDITION = {
_guid: '',
objects: [
{ _guid: 'browserType', objects: [
{ _guid: 'browser', objects: [] }
{ _guid: 'BrowserType', objects: [
{ _guid: 'Browser', objects: [] }
] },
{ _guid: 'browserType', objects: [] },
{ _guid: 'browserType', objects: [] },
{ _guid: 'playwright' },
{ _guid: 'selectors' },
{ _guid: 'electron', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'Playwright' },
{ _guid: 'Selectors' },
{ _guid: 'Electron', objects: [] },
]
};
await expectScopeState(browserType, GOLDEN_PRECONDITION);
@ -86,16 +86,16 @@ describe.skip(!CHANNEL)('Channels', function() {
await expectScopeState(browserType, {
_guid: '',
objects: [
{ _guid: 'browserType', objects: [
{ _guid: 'browser', objects: [
{ _guid: 'cdpSession', objects: [] },
{ _guid: 'BrowserType', objects: [
{ _guid: 'Browser', objects: [
{ _guid: 'CDPSession', objects: [] },
] },
] },
{ _guid: 'browserType', objects: [] },
{ _guid: 'browserType', objects: [] },
{ _guid: 'playwright' },
{ _guid: 'selectors' },
{ _guid: 'electron', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'Playwright' },
{ _guid: 'Selectors' },
{ _guid: 'Electron', objects: [] },
]
});
@ -107,14 +107,14 @@ describe.skip(!CHANNEL)('Channels', function() {
const GOLDEN_PRECONDITION = {
_guid: '',
objects: [
{ _guid: 'browserType', objects: [
{ _guid: 'browser', objects: [] }
{ _guid: 'BrowserType', objects: [
{ _guid: 'Browser', objects: [] }
] },
{ _guid: 'browserType', objects: [] },
{ _guid: 'browserType', objects: [] },
{ _guid: 'playwright' },
{ _guid: 'selectors' },
{ _guid: 'electron', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'Playwright' },
{ _guid: 'Selectors' },
{ _guid: 'Electron', objects: [] },
]
};
await expectScopeState(browserType, GOLDEN_PRECONDITION);
@ -124,17 +124,17 @@ describe.skip(!CHANNEL)('Channels', function() {
await expectScopeState(browserType, {
_guid: '',
objects: [
{ _guid: 'browserType', objects: [
{ _guid: 'browser', objects: [
{ _guid: 'context', objects: [] }
{ _guid: 'BrowserType', objects: [
{ _guid: 'Browser', objects: [
{ _guid: 'BrowserContext', objects: [] }
] },
{ _guid: 'browser', objects: [] },
{ _guid: 'Browser', objects: [] },
] },
{ _guid: 'browserType', objects: [] },
{ _guid: 'browserType', objects: [] },
{ _guid: 'playwright' },
{ _guid: 'selectors' },
{ _guid: 'electron', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'BrowserType', objects: [] },
{ _guid: 'Playwright' },
{ _guid: 'Selectors' },
{ _guid: 'Electron', objects: [] },
]
});
@ -170,8 +170,6 @@ function trimGuids(object) {
const result = {};
for (const key in object)
result[key] = trimGuids(object[key]);
if (result._guid === 'chromium' || result._guid === 'firefox' || result._guid === 'webkit')
result._guid = 'browserType';
return result;
}
if (typeof object === 'string')

View file

@ -196,7 +196,7 @@ class PlaywrightEnvironment {
new PlaywrightDispatcher(dispatcherConnection.rootDispatcher(), this._playwright);
state.toImpl = x => dispatcherConnection._dispatchers.get(x._guid)._object;
}
state.playwright = await connection.waitForObjectWithKnownName('playwright');
state.playwright = await connection.waitForObjectWithKnownName('Playwright');
} else {
state.toImpl = x => x;
state.playwright = this._playwright;

View file

@ -114,7 +114,7 @@ module.exports = function registerFixtures(global) {
toImpl = x => dispatcherConnection._dispatchers.get(x._guid)._object;
}
const playwrightObject = await connection.waitForObjectWithKnownName('playwright');
const playwrightObject = await connection.waitForObjectWithKnownName('Playwright');
playwrightObject.toImpl = toImpl;
await test(playwrightObject);
if (spawnedProcess) {

View file

@ -98,7 +98,7 @@ class PlaywrightEnvironment extends NodeEnvironment {
const describeSkip = this.global.describe.skip;
this.global.describe.skip = (...args) => {
if (args.length = 1)
if (args.length === 1)
return args[0] ? describeSkip : this.global.describe;
return describeSkip(...args);
};
@ -107,7 +107,7 @@ class PlaywrightEnvironment extends NodeEnvironment {
const itSkip = this.global.it.skip;
itSkip.slow = () => itSkip;
this.global.it.skip = (...args) => {
if (args.length = 1)
if (args.length === 1)
return args[0] ? itSkip : this.global.it;
return itSkip(...args);
};
@ -115,8 +115,8 @@ class PlaywrightEnvironment extends NodeEnvironment {
this.global.it.slow = () => {
return (name, fn) => {
return this.global.it(name, fn, 90000);
}
}
};
};
const testOptions = this.global.testOptions;
function toBeGolden(received, goldenName) {