Navigation Menu

Skip to content

Commit

Permalink
feat(rpc): ensure feature-detection works as before (#2898)
Browse files Browse the repository at this point in the history
For this, some tests are migrated from skip() to feature detection,
like our users would do.
  • Loading branch information
dgozman committed Jul 13, 2020
1 parent 2151757 commit 9fd30e5
Show file tree
Hide file tree
Showing 18 changed files with 235 additions and 148 deletions.
7 changes: 1 addition & 6 deletions src/rpc/channels.ts
Expand Up @@ -98,11 +98,7 @@ export interface BrowserContextChannel extends Channel {
on(event: 'crServiceWorker', callback: (params: WorkerChannel) => void): this;
crNewCDPSession(params: { page: PageChannel }): Promise<CDPSessionChannel>;
}
export type BrowserContextInitializer = {
pages: PageChannel[],
crBackgroundPages: PageChannel[],
crServiceWorkers: WorkerChannel[],
};
export type BrowserContextInitializer = {};


export interface PageChannel extends Channel {
Expand All @@ -117,7 +113,6 @@ export interface PageChannel extends Channel {
on(event: 'frameAttached', callback: (params: FrameChannel) => void): this;
on(event: 'frameDetached', callback: (params: FrameChannel) => void): this;
on(event: 'frameNavigated', callback: (params: { frame: FrameChannel, url: string, name: string }) => void): this;
on(event: 'frameNavigated', callback: (params: { frame: FrameChannel, url: string, name: string }) => void): this;
on(event: 'load', callback: () => void): this;
on(event: 'pageError', callback: (params: { error: types.Error }) => void): this;
on(event: 'popup', callback: (params: PageChannel) => void): this;
Expand Down
17 changes: 3 additions & 14 deletions src/rpc/client/browser.ts
Expand Up @@ -20,14 +20,15 @@ import { BrowserContext } from './browserContext';
import { Page } from './page';
import { ChannelOwner } from './channelOwner';
import { Events } from '../../events';
import { CDPSession } from './cdpSession';
import { LoggerSink } from '../../loggerSink';
import { BrowserType } from './browserType';

export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
readonly _contexts = new Set<BrowserContext>();
private _isConnected = true;
private _isClosedOrClosing = false;
private _closedPromise: Promise<void>;
readonly _browserType: BrowserType;

static from(browser: BrowserChannel): Browser {
return (browser as any)._object;
Expand All @@ -39,6 +40,7 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {

constructor(parent: ChannelOwner, type: string, guid: string, initializer: BrowserInitializer) {
super(parent, type, guid, initializer, true);
this._browserType = parent as BrowserType;
this._channel.on('close', () => {
this._isConnected = false;
this.emit(Events.Browser.Disconnected);
Expand All @@ -54,7 +56,6 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
const context = BrowserContext.from(await this._channel.newContext(options));
this._contexts.add(context);
context._logger = logger || this._logger;
context._browser = this;
return context;
}

Expand All @@ -81,16 +82,4 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
}
await this._closedPromise;
}

async newBrowserCDPSession(): Promise<CDPSession> {
return CDPSession.from(await this._channel.crNewBrowserCDPSession());
}

async startTracing(page?: Page, options: { path?: string; screenshots?: boolean; categories?: string[]; } = {}) {
await this._channel.crStartTracing({ ...options, page: page ? page._channel : undefined });
}

async stopTracing(): Promise<Buffer> {
return Buffer.from(await this._channel.crStopTracing(), 'base64');
}
}
58 changes: 11 additions & 47 deletions src/rpc/client/browserContext.ts
Expand Up @@ -25,16 +25,13 @@ import { helper } from '../../helper';
import { Browser } from './browser';
import { Events } from '../../events';
import { TimeoutSettings } from '../../timeoutSettings';
import { CDPSession } from './cdpSession';
import { Events as ChromiumEvents } from '../../chromium/events';
import { Worker } from './worker';
import { BrowserType } from './browserType';

export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserContextInitializer> {
_pages = new Set<Page>();
_crBackgroundPages = new Set<Page>();
_crServiceWorkers = new Set<Worker>();
private _routes: { url: types.URLMatch, handler: network.RouteHandler }[] = [];
_browser: Browser | undefined;
readonly _browser: Browser | undefined;
readonly _browserType: BrowserType;
readonly _bindings = new Map<string, frames.FunctionWithSource>();
private _pendingWaitForEvents = new Map<(error: Error) => void, string>();
_timeoutSettings = new TimeoutSettings();
Expand All @@ -52,43 +49,22 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC

constructor(parent: ChannelOwner, type: string, guid: string, initializer: BrowserContextInitializer) {
super(parent, type, guid, initializer, true);
initializer.pages.forEach(p => {
const page = Page.from(p);
this._pages.add(page);
page._setBrowserContext(this);
});
if (parent instanceof Browser) {
this._browser = parent;
this._browserType = this._browser._browserType;
} else {
// Launching persistent context does not produce a browser at all.
this._browserType = parent as BrowserType;
}

this._channel.on('bindingCall', bindingCall => this._onBinding(BindingCall.from(bindingCall)));
this._channel.on('close', () => this._onClose());
this._channel.on('page', page => this._onPage(Page.from(page)));
this._channel.on('route', ({ route, request }) => this._onRoute(network.Route.from(route), network.Request.from(request)));
this._closedPromise = new Promise(f => this.once(Events.BrowserContext.Close, f));

initializer.crBackgroundPages.forEach(p => {
const page = Page.from(p);
this._crBackgroundPages.add(page);
page._setBrowserContext(this);
});
this._channel.on('crBackgroundPage', pageChannel => {
const page = Page.from(pageChannel);
page._setBrowserContext(this);
this._crBackgroundPages.add(page);
this.emit(ChromiumEvents.CRBrowserContext.BackgroundPage, page);
});
initializer.crServiceWorkers.forEach(w => {
const worker = Worker.from(w);
worker._context = this;
this._crServiceWorkers.add(worker);
});
this._channel.on('crServiceWorker', serviceWorkerChannel => {
const worker = Worker.from(serviceWorkerChannel);
worker._context = this;
this._crServiceWorkers.add(worker);
this.emit(ChromiumEvents.CRBrowserContext.ServiceWorker, worker);
});
}

private _onPage(page: Page): void {
page._setBrowserContext(this);
this._pages.add(page);
this.emit(Events.BrowserContext.Page, page);
}
Expand Down Expand Up @@ -234,16 +210,4 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
}
await this._closedPromise;
}

async newCDPSession(page: Page): Promise<CDPSession> {
return CDPSession.from(await this._channel.crNewCDPSession({ page: page._channel }));
}

backgroundPages(): Page[] {
return [...this._crBackgroundPages];
}

serviceWorkers(): Worker[] {
return [...this._crServiceWorkers];
}
}
2 changes: 1 addition & 1 deletion src/rpc/client/browserType.ts
Expand Up @@ -29,7 +29,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
}

constructor(parent: ChannelOwner, type: string, guid: string, initializer: BrowserTypeInitializer) {
super(parent, type, guid, initializer);
super(parent, type, guid, initializer, true);
}

executablePath(): string {
Expand Down
33 changes: 33 additions & 0 deletions src/rpc/client/chromiumBrowser.ts
@@ -0,0 +1,33 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Page } from './page';
import { CDPSession } from './cdpSession';
import { Browser } from './browser';

export class ChromiumBrowser extends Browser {
async newBrowserCDPSession(): Promise<CDPSession> {
return CDPSession.from(await this._channel.crNewBrowserCDPSession());
}

async startTracing(page?: Page, options: { path?: string; screenshots?: boolean; categories?: string[]; } = {}) {
await this._channel.crStartTracing({ ...options, page: page ? page._channel : undefined });
}

async stopTracing(): Promise<Buffer> {
return Buffer.from(await this._channel.crStopTracing(), 'base64');
}
}
56 changes: 56 additions & 0 deletions src/rpc/client/chromiumBrowserContext.ts
@@ -0,0 +1,56 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
* Modifications copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Page } from './page';
import { BrowserContextInitializer } from '../channels';
import { ChannelOwner } from './channelOwner';
import { CDPSession } from './cdpSession';
import { Events as ChromiumEvents } from '../../chromium/events';
import { Worker } from './worker';
import { BrowserContext } from './browserContext';

export class ChromiumBrowserContext extends BrowserContext {
_backgroundPages = new Set<Page>();
_serviceWorkers = new Set<Worker>();

constructor(parent: ChannelOwner, type: string, guid: string, initializer: BrowserContextInitializer) {
super(parent, type, guid, initializer);
this._channel.on('crBackgroundPage', pageChannel => {
const page = Page.from(pageChannel);
this._backgroundPages.add(page);
this.emit(ChromiumEvents.CRBrowserContext.BackgroundPage, page);
});
this._channel.on('crServiceWorker', serviceWorkerChannel => {
const worker = Worker.from(serviceWorkerChannel);
worker._context = this;
this._serviceWorkers.add(worker);
this.emit(ChromiumEvents.CRBrowserContext.ServiceWorker, worker);
});
}

backgroundPages(): Page[] {
return [...this._backgroundPages];
}

serviceWorkers(): Worker[] {
return [...this._serviceWorkers];
}

async newCDPSession(page: Page): Promise<CDPSession> {
return CDPSession.from(await this._channel.crNewCDPSession({ page: page._channel }));
}
}
14 changes: 12 additions & 2 deletions src/rpc/client/connection.ts
Expand Up @@ -33,6 +33,8 @@ import { BrowserServer } from './browserServer';
import { CDPSession } from './cdpSession';
import { Playwright } from './playwright';
import { Channel } from '../channels';
import { ChromiumBrowser } from './chromiumBrowser';
import { ChromiumBrowserContext } from './chromiumBrowserContext';

class Root extends ChannelOwner<Channel, {}> {
constructor(connection: Connection) {
Expand Down Expand Up @@ -133,7 +135,10 @@ export class Connection {
result = new BindingCall(parent, type, guid, initializer);
break;
case 'browser':
result = new Browser(parent, type, guid, initializer);
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);
Expand All @@ -145,7 +150,12 @@ export class Connection {
result = new CDPSession(parent, type, guid, initializer);
break;
case 'context':
result = new BrowserContext(parent, type, guid, initializer);
// Launching persistent context produces BrowserType parent directly for BrowserContext.
const browserType = parent instanceof Browser ? parent._browserType : parent as BrowserType;
if (browserType.name() === 'chromium')
result = new ChromiumBrowserContext(parent, type, guid, initializer);
else
result = new BrowserContext(parent, type, guid, initializer);
break;
case 'consoleMessage':
result = new ConsoleMessage(parent, type, guid, initializer);
Expand Down

0 comments on commit 9fd30e5

Please sign in to comment.