chore: centralize playwright creation, bind context listeners to instance (#5217)

This commit is contained in:
Pavel Feldman 2021-01-29 16:00:56 -08:00 committed by GitHub
parent 7fe7d0ef32
commit 975519150e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 104 additions and 112 deletions

View File

@ -70,7 +70,7 @@ export class BrowserServerImpl extends EventEmitter implements BrowserServer {
this._browser = browser;
this._wsEndpoint = '';
this._process = browser._options.browserProcess.process!;
this._process = browser.options.browserProcess.process!;
let readyCallback = () => {};
this._ready = new Promise<void>(f => readyCallback = f);
@ -86,7 +86,7 @@ export class BrowserServerImpl extends EventEmitter implements BrowserServer {
this._clientAttached(socket);
});
browser._options.browserProcess.onclose = (exitCode, signal) => {
browser.options.browserProcess.onclose = (exitCode, signal) => {
this._server.close();
this.emit('close', exitCode, signal);
};
@ -101,11 +101,11 @@ export class BrowserServerImpl extends EventEmitter implements BrowserServer {
}
async close(): Promise<void> {
await this._browser._options.browserProcess.close();
await this._browser.options.browserProcess.close();
}
async kill(): Promise<void> {
await this._browser._options.browserProcess.kill();
await this._browser.options.browserProcess.kill();
}
private _clientAttached(socket: ws) {
@ -158,7 +158,7 @@ class ConnectedBrowser extends BrowserDispatcher {
async newContext(params: channels.BrowserNewContextParams): Promise<{ context: channels.BrowserContextChannel }> {
if (params.recordVideo) {
// TODO: we should create a separate temp directory or accept a launchServer parameter.
params.recordVideo.dir = this._object._options.downloadsPath!;
params.recordVideo.dir = this._object.options.downloadsPath!;
}
const result = await super.newContext(params);
const dispatcher = result.context as BrowserContextDispatcher;

View File

@ -18,15 +18,12 @@
import * as fs from 'fs';
import * as path from 'path';
import { installInspectorController } from '../server/supplements/inspectorController';
import { DispatcherConnection } from '../dispatchers/dispatcher';
import { PlaywrightDispatcher } from '../dispatchers/playwrightDispatcher';
import { installBrowsersWithProgressBar } from '../install/installer';
import { Transport } from '../protocol/transport';
import { Playwright } from '../server/playwright';
import { createPlaywright } from '../server/playwright';
import { gracefullyCloseAll } from '../server/processLauncher';
import { installHarTracer } from '../trace/harTracer';
import { installTracer } from '../trace/tracer';
import { BrowserName } from '../utils/browserPaths';
export function printApiJson() {
@ -38,10 +35,6 @@ export function printProtocol() {
}
export function runServer() {
installInspectorController();
installTracer();
installHarTracer();
const dispatcherConnection = new DispatcherConnection();
const transport = new Transport(process.stdout, process.stdin);
transport.onmessage = message => dispatcherConnection.dispatch(JSON.parse(message));
@ -56,7 +49,7 @@ export function runServer() {
process.exit(0);
};
const playwright = new Playwright(__dirname, require('../../browsers.json')['browsers']);
const playwright = createPlaywright();
new PlaywrightDispatcher(dispatcherConnection.rootDispatcher(), playwright);
}

View File

@ -28,7 +28,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
private _context: BrowserContext;
constructor(scope: DispatcherScope, context: BrowserContext) {
super(scope, context, 'BrowserContext', { isChromium: context._browser._options.isChromium }, true);
super(scope, context, 'BrowserContext', { isChromium: context._browser.options.isChromium }, true);
this._context = context;
for (const page of context.pages())
@ -41,7 +41,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
context.on(BrowserContext.Events.StdOut, data => this._dispatchEvent('stdout', { data: Buffer.from(data, 'utf8').toString('base64') }));
context.on(BrowserContext.Events.StdErr, data => this._dispatchEvent('stderr', { data: Buffer.from(data, 'utf8').toString('base64') }));
if (context._browser._options.name === 'chromium') {
if (context._browser.options.name === 'chromium') {
for (const page of (context as CRBrowserContext).backgroundPages())
this._dispatchEvent('crBackgroundPage', { page: new PageDispatcher(this._scope, page) });
context.on(CRBrowserContext.CREvents.BackgroundPage, page => this._dispatchEvent('crBackgroundPage', { page: new PageDispatcher(this._scope, page) }));
@ -139,7 +139,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
}
async pause() {
if (!this._context._browser._options.headful)
if (!this._context._browser.options.headful)
return;
const recorder = await RecorderSupplement.getOrCreate(this._context, 'pause', {
language: 'javascript',
@ -149,7 +149,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
}
async crNewCDPSession(params: channels.BrowserContextCrNewCDPSessionParams): Promise<channels.BrowserContextCrNewCDPSessionResult> {
if (!this._object._browser._options.isChromium)
if (!this._object._browser.options.isChromium)
throw new Error(`CDP session is only available in Chromium`);
const crBrowserContext = this._object as CRBrowserContext;
return { session: new CDPSessionDispatcher(this._scope, await crBrowserContext.newCDPSession((params.page as PageDispatcher)._object)) };

View File

@ -24,7 +24,7 @@ import { PageDispatcher } from './pageDispatcher';
export class BrowserDispatcher extends Dispatcher<Browser, channels.BrowserInitializer> implements channels.BrowserChannel {
constructor(scope: DispatcherScope, browser: Browser) {
super(scope, browser, 'Browser', { version: browser.version(), name: browser._options.name }, true);
super(scope, browser, 'Browser', { version: browser.version(), name: browser.options.name }, true);
browser.on(Browser.Events.Disconnected, () => this._didClose());
}
@ -45,21 +45,21 @@ export class BrowserDispatcher extends Dispatcher<Browser, channels.BrowserIniti
}
async crNewBrowserCDPSession(): Promise<channels.BrowserCrNewBrowserCDPSessionResult> {
if (!this._object._options.isChromium)
if (!this._object.options.isChromium)
throw new Error(`CDP session is only available in Chromium`);
const crBrowser = this._object as CRBrowser;
return { session: new CDPSessionDispatcher(this._scope, await crBrowser.newBrowserCDPSession()) };
}
async crStartTracing(params: channels.BrowserCrStartTracingParams): Promise<void> {
if (!this._object._options.isChromium)
if (!this._object.options.isChromium)
throw new Error(`Tracing is only available in Chromium`);
const crBrowser = this._object as CRBrowser;
await crBrowser.startTracing(params.page ? (params.page as PageDispatcher)._object : undefined, params);
}
async crStopTracing(): Promise<channels.BrowserCrStopTracingResult> {
if (!this._object._options.isChromium)
if (!this._object.options.isChromium)
throw new Error(`Tracing is only available in Chromium`);
const crBrowser = this._object as CRBrowser;
const buffer = await crBrowser.stopTracing();

View File

@ -15,22 +15,14 @@
*/
import { DispatcherConnection } from './dispatchers/dispatcher';
import { Playwright as PlaywrightImpl } from './server/playwright';
import { createPlaywright } from './server/playwright';
import type { Playwright as PlaywrightAPI } from './client/playwright';
import { PlaywrightDispatcher } from './dispatchers/playwrightDispatcher';
import { Connection } from './client/connection';
import { BrowserServerLauncherImpl } from './browserServerImpl';
import { installInspectorController } from './server/supplements/inspectorController';
import { installTracer } from './trace/tracer';
import { installHarTracer } from './trace/harTracer';
import * as path from 'path';
function setupInProcess(): PlaywrightAPI {
const playwright = new PlaywrightImpl(path.join(__dirname, '..'), require('../browsers.json')['browsers']);
installInspectorController();
installTracer();
installHarTracer();
const playwright = createPlaywright();
const clientConnection = new Connection();
const dispatcherConnection = new DispatcherConnection();

View File

@ -17,20 +17,13 @@
import * as debug from 'debug';
import * as http from 'http';
import * as WebSocket from 'ws';
import { installInspectorController } from '../server/supplements/inspectorController';
import { DispatcherConnection } from '../dispatchers/dispatcher';
import { PlaywrightDispatcher } from '../dispatchers/playwrightDispatcher';
import { Playwright } from '../server/playwright';
import { createPlaywright } from '../server/playwright';
import { gracefullyCloseAll } from '../server/processLauncher';
import { installTracer } from '../trace/tracer';
import { installHarTracer } from '../trace/harTracer';
const debugLog = debug('pw:server');
installInspectorController();
installTracer();
installHarTracer();
export class PlaywrightServer {
private _server: http.Server | undefined;
private _client: WebSocket | undefined;
@ -62,8 +55,7 @@ export class PlaywrightServer {
this._onDisconnect();
});
dispatcherConnection.onmessage = message => ws.send(JSON.stringify(message));
const playwright = new Playwright(__dirname, require('../../browsers.json')['browsers']);
new PlaywrightDispatcher(dispatcherConnection.rootDispatcher(), playwright);
new PlaywrightDispatcher(dispatcherConnection.rootDispatcher(), createPlaywright());
});
}

View File

@ -22,7 +22,7 @@ import * as stream from 'stream';
import * as util from 'util';
import * as ws from 'ws';
import { createGuid, makeWaitForNextTask } from '../../utils/utils';
import { BrowserOptions, BrowserProcess } from '../browser';
import { BrowserOptions, BrowserProcess, PlaywrightOptions } from '../browser';
import { BrowserContext, validateBrowserContextOptions } from '../browserContext';
import { ProgressController } from '../progress';
import { CRBrowser } from '../chromium/crBrowser';
@ -57,9 +57,11 @@ export class Android {
private _backend: Backend;
private _devices = new Map<string, AndroidDevice>();
readonly _timeoutSettings: TimeoutSettings;
readonly _playwrightOptions: PlaywrightOptions;
constructor(backend: Backend) {
constructor(backend: Backend, playwrightOptions: PlaywrightOptions) {
this._backend = backend;
this._playwrightOptions = playwrightOptions;
this._timeoutSettings = new TimeoutSettings();
}
@ -255,6 +257,7 @@ export class AndroidDevice extends EventEmitter {
this._browserConnections.add(androidBrowser);
const browserOptions: BrowserOptions = {
...this._android._playwrightOptions,
name: 'clank',
isChromium: true,
slowMo: 0,

View File

@ -15,7 +15,7 @@
*/
import * as types from './types';
import { BrowserContext, Video } from './browserContext';
import { BrowserContext, ContextListener, Video } from './browserContext';
import { Page } from './page';
import { EventEmitter } from 'events';
import { Download } from './download';
@ -30,7 +30,11 @@ export interface BrowserProcess {
close(): Promise<void>;
}
export type BrowserOptions = types.UIOptions & {
export type PlaywrightOptions = {
contextListeners: ContextListener[]
};
export type BrowserOptions = PlaywrightOptions & {
name: string,
isChromium: boolean,
downloadsPath?: string,
@ -40,6 +44,7 @@ export type BrowserOptions = types.UIOptions & {
proxy?: ProxySettings,
protocolLogger: types.ProtocolLogger,
browserLogsCollector: RecentLogsCollector,
slowMo?: number,
};
export abstract class Browser extends EventEmitter {
@ -47,7 +52,7 @@ export abstract class Browser extends EventEmitter {
Disconnected: 'disconnected',
};
readonly _options: BrowserOptions;
readonly options: BrowserOptions;
private _downloads = new Map<string, Download>();
_defaultContext: BrowserContext | null = null;
private _startedClosing = false;
@ -55,7 +60,7 @@ export abstract class Browser extends EventEmitter {
constructor(options: BrowserOptions) {
super();
this._options = options;
this.options = options;
}
abstract newContext(options?: types.BrowserContextOptions): Promise<BrowserContext>;
@ -71,7 +76,7 @@ export abstract class Browser extends EventEmitter {
}
_downloadCreated(page: Page, uuid: string, url: string, suggestedFilename?: string) {
const download = new Download(page, this._options.downloadsPath || '', uuid, url, suggestedFilename);
const download = new Download(page, this.options.downloadsPath || '', uuid, url, suggestedFilename);
this._downloads.set(uuid, download);
}
@ -117,7 +122,7 @@ export abstract class Browser extends EventEmitter {
async close() {
if (!this._startedClosing) {
this._startedClosing = true;
await this._options.browserProcess.close();
await this.options.browserProcess.close();
}
if (this.isConnected())
await new Promise(x => this.once(Browser.Events.Disconnected, x));

View File

@ -94,8 +94,6 @@ export interface ContextListener {
onContextDidDestroy(context: BrowserContext): Promise<void>;
}
export const contextListeners = new Set<ContextListener>();
export abstract class BrowserContext extends EventEmitter {
static Events = {
Close: 'close',
@ -140,7 +138,7 @@ export abstract class BrowserContext extends EventEmitter {
}
async _initialize() {
for (const listener of contextListeners)
for (const listener of this._browser.options.contextListeners)
await listener.onContextCreated(this);
}
@ -259,7 +257,7 @@ export abstract class BrowserContext extends EventEmitter {
}
protected _authenticateProxyViaHeader() {
const proxy = this._options.proxy || this._browser._options.proxy || { username: undefined, password: undefined };
const proxy = this._options.proxy || this._browser.options.proxy || { username: undefined, password: undefined };
const { username, password } = proxy;
if (username) {
this._options.httpCredentials = { username, password: password! };
@ -272,7 +270,7 @@ export abstract class BrowserContext extends EventEmitter {
}
protected _authenticateProxyViaCredentials() {
const proxy = this._options.proxy || this._browser._options.proxy;
const proxy = this._options.proxy || this._browser.options.proxy;
if (!proxy)
return;
const { username, password } = proxy;
@ -294,7 +292,7 @@ export abstract class BrowserContext extends EventEmitter {
this.emit(BrowserContext.Events.BeforeClose);
this._closedStatus = 'closing';
for (const listener of contextListeners)
for (const listener of this._browser.options.contextListeners)
await listener.onContextWillDestroy(this);
// Collect videos/downloads that we will await.
@ -323,7 +321,7 @@ export abstract class BrowserContext extends EventEmitter {
await this._browser.close();
// Bookkeeping.
for (const listener of contextListeners)
for (const listener of this._browser.options.contextListeners)
await listener.onContextDidDestroy(this);
this._didCloseInternal();
}

View File

@ -21,7 +21,7 @@ import * as util from 'util';
import { BrowserContext, normalizeProxySettings, validateBrowserContextOptions } from './browserContext';
import * as browserPaths from '../utils/browserPaths';
import { ConnectionTransport } from './transport';
import { BrowserOptions, Browser, BrowserProcess } from './browser';
import { BrowserOptions, Browser, BrowserProcess, PlaywrightOptions } from './browser';
import { launchProcess, Env, envArrayToObject } from './processLauncher';
import { PipeTransport } from './pipeTransport';
import { Progress, ProgressController } from './progress';
@ -42,8 +42,10 @@ export abstract class BrowserType {
private _executablePath: string;
private _browserDescriptor: browserPaths.BrowserDescriptor;
readonly _browserPath: string;
readonly _playwrightOptions: PlaywrightOptions;
constructor(packagePath: string, browser: browserPaths.BrowserDescriptor) {
constructor(packagePath: string, browser: browserPaths.BrowserDescriptor, playwrightOptions: PlaywrightOptions) {
this._playwrightOptions = playwrightOptions;
this._name = browser.name;
const browsersPath = browserPaths.browsersPath(packagePath);
this._browserDescriptor = browser;
@ -87,6 +89,7 @@ export abstract class BrowserType {
if ((options as any).__testHookBeforeCreateBrowser)
await (options as any).__testHookBeforeCreateBrowser();
const browserOptions: BrowserOptions = {
...this._playwrightOptions,
name: this._name,
isChromium: this._name === 'chromium',
slowMo: options.slowMo,

View File

@ -24,15 +24,15 @@ import { BrowserType } from '../browserType';
import { ConnectionTransport, ProtocolRequest } from '../transport';
import type { BrowserDescriptor } from '../../utils/browserPaths';
import { CRDevTools } from './crDevTools';
import { BrowserOptions } from '../browser';
import { BrowserOptions, PlaywrightOptions } from '../browser';
import * as types from '../types';
import { isDebugMode } from '../../utils/utils';
export class Chromium extends BrowserType {
private _devtools: CRDevTools | undefined;
constructor(packagePath: string, browser: BrowserDescriptor) {
super(packagePath, browser);
constructor(packagePath: string, browser: BrowserDescriptor, playwrightOptions: PlaywrightOptions) {
super(packagePath, browser, playwrightOptions);
if (isDebugMode())
this._devtools = this._createDevTools();
}

View File

@ -98,7 +98,7 @@ export class CRBrowser extends Browser {
}
async newContext(options: types.BrowserContextOptions = {}): Promise<BrowserContext> {
validateBrowserContextOptions(options, this._options);
validateBrowserContextOptions(options, this.options);
const { browserContextId } = await this._session.send('Target.createBrowserContext', {
disposeOnDetach: true,
proxyServer: options.proxy ? options.proxy.server : undefined,
@ -119,7 +119,7 @@ export class CRBrowser extends Browser {
}
isClank(): boolean {
return this._options.name === 'clank';
return this.options.name === 'clank';
}
_onAttachedToTarget({targetInfo, sessionId, waitingForDebugger}: Protocol.Target.attachedToTargetPayload) {
@ -293,11 +293,11 @@ export class CRBrowserContext extends BrowserContext {
async _initialize() {
assert(!Array.from(this._browser._crPages.values()).some(page => page._browserContext === this));
const promises: Promise<any>[] = [ super._initialize() ];
if (this._browser._options.downloadsPath) {
if (this._browser.options.downloadsPath) {
promises.push(this._browser._session.send('Browser.setDownloadBehavior', {
behavior: this._options.acceptDownloads ? 'allowAndName' : 'deny',
browserContextId: this._browserContextId,
downloadPath: this._browser._options.downloadsPath
downloadPath: this._browser.options.downloadsPath
}));
}
if (this._options.permissions)

View File

@ -845,7 +845,7 @@ class FrameSession {
];
if (this._windowId) {
let insets = { width: 0, height: 0 };
if (this._crPage._browserContext._browser._options.headful) {
if (this._crPage._browserContext._browser.options.headful) {
// TODO: popup windows have their own insets.
insets = { width: 24, height: 88 };
if (process.platform === 'win32')

View File

@ -29,7 +29,7 @@ import type {BrowserWindow} from 'electron';
import { Progress, ProgressController, runAbortableTask } from '../progress';
import { EventEmitter } from 'events';
import { helper } from '../helper';
import { BrowserOptions, BrowserProcess } from '../browser';
import { BrowserOptions, BrowserProcess, PlaywrightOptions } from '../browser';
import * as childProcess from 'child_process';
import * as readline from 'readline';
import { RecentLogsCollector } from '../../utils/debugLogger';
@ -139,6 +139,12 @@ export class ElectronApplication extends EventEmitter {
}
export class Electron {
private _playwrightOptions: PlaywrightOptions;
constructor(playwrightOptions: PlaywrightOptions) {
this._playwrightOptions = playwrightOptions;
}
async launch(executablePath: string, options: ElectronLaunchOptionsBase = {}): Promise<ElectronApplication> {
const {
args = [],
@ -190,6 +196,7 @@ export class Electron {
kill
};
const browserOptions: BrowserOptions = {
...this._playwrightOptions,
name: 'electron',
isChromium: true,
headful: true,

View File

@ -72,7 +72,7 @@ export class FFBrowser extends Browser {
}
async newContext(options: types.BrowserContextOptions = {}): Promise<BrowserContext> {
validateBrowserContextOptions(options, this._options);
validateBrowserContextOptions(options, this.options);
if (options.isMobile)
throw new Error('options.isMobile is not supported in Firefox');
const { browserContextId } = await this._connection.send('Browser.createBrowserContext', { removeOnDetach: true });
@ -149,12 +149,12 @@ export class FFBrowserContext extends BrowserContext {
assert(!this._ffPages().length);
const browserContextId = this._browserContextId;
const promises: Promise<any>[] = [ super._initialize() ];
if (this._browser._options.downloadsPath) {
if (this._browser.options.downloadsPath) {
promises.push(this._browser._connection.send('Browser.setDownloadOptions', {
browserContextId,
downloadOptions: {
behavior: this._options.acceptDownloads ? 'saveToDisk' : 'cancel',
downloadsDir: this._browser._options.downloadsPath,
downloadsDir: this._browser.options.downloadsPath,
},
}));
}

View File

@ -198,7 +198,7 @@ export class Page extends EventEmitter {
}
async _doSlowMo() {
const slowMo = this._browserContext._browser._options.slowMo;
const slowMo = this._browserContext._browser.options.slowMo;
if (!slowMo)
return;
await new Promise(x => setTimeout(x, slowMo));

View File

@ -14,6 +14,8 @@
* limitations under the License.
*/
import * as path from 'path';
import { Tracer } from '../trace/tracer';
import * as browserPaths from '../utils/browserPaths';
import { Android } from './android/android';
import { AdbBackend } from './android/backendAdb';
@ -21,6 +23,8 @@ import { Chromium } from './chromium/chromium';
import { Electron } from './electron/electron';
import { Firefox } from './firefox/firefox';
import { serverSelectors } from './selectors';
import { HarTracer } from './supplements/har/harTracer';
import { InspectorController } from './supplements/inspectorController';
import { WebKit } from './webkit/webkit';
export class Playwright {
@ -30,18 +34,29 @@ export class Playwright {
readonly electron: Electron;
readonly firefox: Firefox;
readonly webkit: WebKit;
readonly options = {
contextListeners: [
new InspectorController(),
new Tracer(),
new HarTracer()
]
};
constructor(packagePath: string, browsers: browserPaths.BrowserDescriptor[]) {
const chromium = browsers.find(browser => browser.name === 'chromium');
this.chromium = new Chromium(packagePath, chromium!);
this.chromium = new Chromium(packagePath, chromium!, this.options);
const firefox = browsers.find(browser => browser.name === 'firefox');
this.firefox = new Firefox(packagePath, firefox!);
this.firefox = new Firefox(packagePath, firefox!, this.options);
const webkit = browsers.find(browser => browser.name === 'webkit');
this.webkit = new WebKit(packagePath, webkit!);
this.webkit = new WebKit(packagePath, webkit!, this.options);
this.electron = new Electron();
this.android = new Android(new AdbBackend());
this.electron = new Electron(this.options);
this.android = new Android(new AdbBackend(), this.options);
}
}
export function createPlaywright() {
return new Playwright(path.join(__dirname, '..', '..'), require('../../browsers.json')['browsers']);
}

View File

@ -16,19 +16,15 @@
import * as fs from 'fs';
import * as util from 'util';
import { BrowserContext, ContextListener, contextListeners } from '../server/browserContext';
import { helper } from '../server/helper';
import * as network from '../server/network';
import { Page } from '../server/page';
import { BrowserContext, ContextListener } from '../../browserContext';
import { helper } from '../../helper';
import * as network from '../../network';
import { Page } from '../../page';
import * as har from './har';
const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs));
export function installHarTracer() {
contextListeners.add(new HarTracer());
}
class HarTracer implements ContextListener {
export class HarTracer implements ContextListener {
private _contextTracers = new Map<BrowserContext, HarContextTracer>();
async onContextCreated(context: BrowserContext): Promise<void> {
@ -68,10 +64,10 @@ class HarContextTracer {
version: '1.2',
creator: {
name: 'Playwright',
version: require('../../package.json')['version'],
version: require('../../../../package.json')['version'],
},
browser: {
name: context._browser._options.name,
name: context._browser.options.name,
version: context._browser.version()
},
pages: [],

View File

@ -14,18 +14,14 @@
* limitations under the License.
*/
import { BrowserContext, ContextListener, contextListeners } from '../browserContext';
import { BrowserContext, ContextListener } from '../browserContext';
import { isDebugMode } from '../../utils/utils';
import { ConsoleApiSupplement } from './consoleApiSupplement';
import { RecorderSupplement } from './recorderSupplement';
import { Page } from '../page';
import { ConsoleMessage } from '../console';
export function installInspectorController() {
contextListeners.add(new InspectorController());
}
class InspectorController implements ContextListener {
export class InspectorController implements ContextListener {
async onContextCreated(context: BrowserContext): Promise<void> {
if (isDebugMode()) {
const consoleApi = new ConsoleApiSupplement(context);

View File

@ -92,7 +92,7 @@ export class RecorderSupplement {
this._output.setEnabled(app === 'codegen');
context.on(BrowserContext.Events.BeforeClose, () => this._output.flush());
const generator = new CodeGenerator(context._browser._options.name, app === 'codegen', params.launchOptions || {}, params.contextOptions || {}, this._output, languageGenerator, params.device, params.saveStorage);
const generator = new CodeGenerator(context._browser.options.name, app === 'codegen', params.launchOptions || {}, params.contextOptions || {}, this._output, languageGenerator, params.device, params.saveStorage);
this._generator = generator;
}

View File

@ -271,7 +271,7 @@ type LaunchOptionsBase = {
chromiumSandbox?: boolean,
slowMo?: number,
};
export type LaunchOptions = LaunchOptionsBase & UIOptions & {
export type LaunchOptions = LaunchOptionsBase & {
firefoxUserPrefs?: { [key: string]: string | number | boolean },
};
export type LaunchPersistentOptions = LaunchOptionsBase & BrowserContextOptions;
@ -326,10 +326,6 @@ export type Error = {
stack?: string,
};
export type UIOptions = {
slowMo?: number;
};
export type NameValueList = {
name: string;
value: string;

View File

@ -74,7 +74,7 @@ export class WKBrowser extends Browser {
}
async newContext(options: types.BrowserContextOptions = {}): Promise<BrowserContext> {
validateBrowserContextOptions(options, this._options);
validateBrowserContextOptions(options, this.options);
const createOptions = options.proxy ? {
proxyServer: options.proxy.server,
proxyBypassList: options.proxy.bypass
@ -208,10 +208,10 @@ export class WKBrowserContext extends BrowserContext {
assert(!this._wkPages().length);
const browserContextId = this._browserContextId;
const promises: Promise<any>[] = [ super._initialize() ];
if (this._browser._options.downloadsPath) {
if (this._browser.options.downloadsPath) {
promises.push(this._browser._browserSession.send('Playwright.setDownloadBehavior', {
behavior: this._options.acceptDownloads ? 'allow' : 'deny',
downloadPath: this._browser._options.downloadsPath,
downloadPath: this._browser.options.downloadsPath,
browserContextId
}));
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { ActionListener, ActionMetadata, BrowserContext, ContextListener, contextListeners, Video } from '../server/browserContext';
import { ActionListener, ActionMetadata, BrowserContext, ContextListener, Video } from '../server/browserContext';
import type { SnapshotterResource as SnapshotterResource, SnapshotterBlob, SnapshotterDelegate } from './snapshotter';
import * as trace from './traceTypes';
import * as path from 'path';
@ -34,11 +34,7 @@ const fsAppendFileAsync = util.promisify(fs.appendFile.bind(fs));
const fsAccessAsync = util.promisify(fs.access.bind(fs));
const envTrace = getFromENV('PW_TRACE_DIR');
export function installTracer() {
contextListeners.add(new Tracer());
}
class Tracer implements ContextListener {
export class Tracer implements ContextListener {
private _contextTracers = new Map<BrowserContext, ContextTracer>();
async onContextCreated(context: BrowserContext): Promise<void> {
@ -93,7 +89,7 @@ class ContextTracer implements SnapshotterDelegate, ActionListener {
const event: trace.ContextCreatedTraceEvent = {
timestamp: monotonicTime(),
type: 'context-created',
browserName: context._browser._options.name,
browserName: context._browser.options.name,
contextId: this._contextId,
isMobile: !!context._options.isMobile,
deviceScaleFactor: context._options.deviceScaleFactor || 1,

View File

@ -17,7 +17,7 @@
import { folio as baseFolio } from './fixtures';
import * as fs from 'fs';
import type * as har from '../src/trace/har';
import type * as har from '../src/server/supplements/har/har';
import type { BrowserContext, Page } from '../index';
const builder = baseFolio.extend<{

View File

@ -138,7 +138,7 @@ DEPS['src/server/injected/'] = ['src/server/common/'];
DEPS['src/server/android/'] = [...DEPS['src/server/'], 'src/server/chromium/', 'src/protocol/'];
DEPS['src/server/electron/'] = [...DEPS['src/server/'], 'src/server/chromium/'];
DEPS['src/server/playwright.ts'] = [...DEPS['src/server/'], 'src/server/chromium/', 'src/server/webkit/', 'src/server/firefox/', 'src/server/android/', 'src/server/electron/'];
DEPS['src/server/playwright.ts'] = [...DEPS['src/server/'], 'src/trace/', 'src/server/chromium/', 'src/server/webkit/', 'src/server/firefox/', 'src/server/android/', 'src/server/electron/'];
DEPS['src/cli/driver.ts'] = DEPS['src/inprocess.ts'] = DEPS['src/browserServerImpl.ts'] = ['src/**'];
// Tracing is a client/server plugin, nothing should depend on it.