chore: use internal BrowserOptions to unify browsers (#2230)

This commit is contained in:
Dmitry Gozman 2020-05-14 13:22:33 -07:00 committed by GitHub
parent 696b40a508
commit e8e761f77f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 128 additions and 105 deletions

View file

@ -21,6 +21,17 @@ import { Download } from './download';
import type { BrowserServer } from './server/browserServer';
import { Events } from './events';
import { InnerLogger, Log } from './logger';
import * as types from './types';
export type BrowserOptions = {
logger: InnerLogger,
downloadsPath: string,
headful?: boolean,
persistent?: boolean,
slowMo?: number,
viewport?: types.Size | null,
ownedServer?: BrowserServer,
};
export interface Browser extends EventEmitter {
newContext(options?: BrowserContextOptions): Promise<BrowserContext>;
@ -31,14 +42,12 @@ export interface Browser extends EventEmitter {
}
export abstract class BrowserBase extends EventEmitter implements Browser, InnerLogger {
_downloadsPath: string = '';
readonly _options: BrowserOptions;
private _downloads = new Map<string, Download>();
_ownedServer: BrowserServer | null = null;
readonly _logger: InnerLogger;
constructor(logger: InnerLogger) {
constructor(options: BrowserOptions) {
super();
this._logger = logger;
this._options = options;
}
abstract newContext(options?: BrowserContextOptions): Promise<BrowserContext>;
@ -54,7 +63,7 @@ export abstract class BrowserBase extends EventEmitter implements Browser, Inner
}
_downloadCreated(page: Page, uuid: string, url: string, suggestedFilename?: string) {
const download = new Download(page, this._downloadsPath, uuid, url, suggestedFilename);
const download = new Download(page, this._options.downloadsPath, uuid, url, suggestedFilename);
this._downloads.set(uuid, download);
}
@ -74,8 +83,8 @@ export abstract class BrowserBase extends EventEmitter implements Browser, Inner
}
async close() {
if (this._ownedServer) {
await this._ownedServer.close();
if (this._options.ownedServer) {
await this._options.ownedServer.close();
} else {
await Promise.all(this.contexts().map(context => context.close()));
this._disconnect();
@ -85,11 +94,11 @@ export abstract class BrowserBase extends EventEmitter implements Browser, Inner
}
_isLogEnabled(log: Log): boolean {
return this._logger._isLogEnabled(log);
return this._options.logger._isLogEnabled(log);
}
_log(log: Log, message: string | Error, ...args: any[]) {
return this._logger._log(log, message, ...args);
return this._options.logger._log(log, message, ...args);
}
}

View file

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { BrowserBase } from '../browser';
import { BrowserBase, BrowserOptions } from '../browser';
import { assertBrowserContextIsNotOwned, BrowserContext, BrowserContextBase, BrowserContextOptions, validateBrowserContextOptions, verifyGeolocation } from '../browserContext';
import { Events as CommonEvents } from '../events';
import { assert, helper } from '../helper';
@ -29,7 +29,7 @@ import { readProtocolStream } from './crProtocolHelper';
import { Events } from './events';
import { Protocol } from './protocol';
import { CRExecutionContext } from './crExecutionContext';
import { InnerLogger, logError } from '../logger';
import { logError } from '../logger';
export class CRBrowser extends BrowserBase {
readonly _connection: CRConnection;
@ -44,13 +44,12 @@ export class CRBrowser extends BrowserBase {
private _tracingRecording = false;
private _tracingPath: string | null = '';
private _tracingClient: CRSession | undefined;
readonly _isHeadful: boolean;
static async connect(transport: ConnectionTransport, isPersistent: boolean, logger: InnerLogger, options: { slowMo?: number, headless?: boolean, viewport?: types.Size | null } = {}): Promise<CRBrowser> {
const connection = new CRConnection(SlowMoTransport.wrap(transport, options.slowMo), logger);
const browser = new CRBrowser(connection, logger, { persistent: isPersistent, headful: !options.headless, viewport: options.viewport });
static async connect(transport: ConnectionTransport, options: BrowserOptions): Promise<CRBrowser> {
const connection = new CRConnection(SlowMoTransport.wrap(transport, options.slowMo), options.logger);
const browser = new CRBrowser(connection, options);
const session = connection.rootSession;
if (!isPersistent) {
if (!options.persistent) {
await session.send('Target.setAutoAttach', { autoAttach: true, waitForDebuggerOnStart: true, flatten: true });
return browser;
}
@ -83,14 +82,13 @@ export class CRBrowser extends BrowserBase {
return browser;
}
constructor(connection: CRConnection, logger: InnerLogger, options: { headful?: boolean, persistent?: boolean, viewport?: types.Size | null } = {}) {
super(logger);
constructor(connection: CRConnection, options: BrowserOptions) {
super(options);
this._connection = connection;
this._session = this._connection.rootSession;
if (options.persistent)
this._defaultContext = new CRBrowserContext(this, null, validateBrowserContextOptions({ viewport: options.viewport }));
this._isHeadful = !!options.headful;
this._connection.on(ConnectionEvents.Disconnected, () => {
for (const context of this._contexts.values())
context._browserClosed();
@ -150,7 +148,7 @@ export class CRBrowser extends BrowserBase {
if (targetInfo.type === 'page') {
const opener = targetInfo.openerId ? this._crPages.get(targetInfo.openerId) || null : null;
const crPage = new CRPage(session, targetInfo.targetId, context, opener, this._isHeadful);
const crPage = new CRPage(session, targetInfo.targetId, context, opener, !!this._options.headful);
this._crPages.set(targetInfo.targetId, crPage);
crPage.pageOrError().then(() => {
context!.emit(CommonEvents.BrowserContext.Page, crPage._page);
@ -289,7 +287,7 @@ export class CRBrowserContext extends BrowserContextBase {
this._browser._session.send('Browser.setDownloadBehavior', {
behavior: this._options.acceptDownloads ? 'allowAndName' : 'deny',
browserContextId: this._browserContextId || undefined,
downloadPath: this._browser._downloadsPath
downloadPath: this._browser._options.downloadsPath
})
];
if (this._options.permissions)

View file

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { BrowserBase } from '../browser';
import { BrowserBase, BrowserOptions } from '../browser';
import { assertBrowserContextIsNotOwned, BrowserContext, BrowserContextBase, BrowserContextOptions, validateBrowserContextOptions, verifyGeolocation } from '../browserContext';
import { Events } from '../events';
import { assert, helper, RegisteredListener } from '../helper';
@ -27,7 +27,6 @@ import { ConnectionEvents, FFConnection } from './ffConnection';
import { headersArray } from './ffNetworkManager';
import { FFPage } from './ffPage';
import { Protocol } from './protocol';
import { InnerLogger } from '../logger';
export class FFBrowser extends BrowserBase {
_connection: FFConnection;
@ -36,19 +35,19 @@ export class FFBrowser extends BrowserBase {
readonly _contexts: Map<string, FFBrowserContext>;
private _eventListeners: RegisteredListener[];
static async connect(transport: ConnectionTransport, logger: InnerLogger, attachToDefaultContext: boolean, slowMo?: number): Promise<FFBrowser> {
const connection = new FFConnection(SlowMoTransport.wrap(transport, slowMo), logger);
const browser = new FFBrowser(connection, logger, attachToDefaultContext);
await connection.send('Browser.enable', { attachToDefaultContext });
static async connect(transport: ConnectionTransport, options: BrowserOptions): Promise<FFBrowser> {
const connection = new FFConnection(SlowMoTransport.wrap(transport, options.slowMo), options.logger);
const browser = new FFBrowser(connection, options);
await connection.send('Browser.enable', { attachToDefaultContext: !!options.persistent });
return browser;
}
constructor(connection: FFConnection, logger: InnerLogger, isPersistent: boolean) {
super(logger);
constructor(connection: FFConnection, options: BrowserOptions) {
super(options);
this._connection = connection;
this._ffPages = new Map();
if (isPersistent)
if (options.persistent)
this._defaultContext = new FFBrowserContext(this, null, validateBrowserContextOptions({}));
this._contexts = new Map();
this._connection.on(ConnectionEvents.Disconnected, () => {
@ -159,7 +158,7 @@ export class FFBrowserContext extends BrowserContextBase {
browserContextId,
downloadOptions: {
behavior: this._options.acceptDownloads ? 'saveToDisk' : 'cancel',
downloadsDir: this._browser._downloadsPath,
downloadsDir: this._browser._options.downloadsPath,
},
}),
];

View file

@ -36,6 +36,11 @@ type LaunchOptionsBase = BrowserArgOptions & {
env?: {[key: string]: string|number|boolean}
};
export function processBrowserArgOptions(options: LaunchOptionsBase): { devtools: boolean, headless: boolean } {
const { devtools = false, headless = !devtools } = options;
return { devtools, headless };
}
export type ConnectOptions = {
wsEndpoint: string,
slowMo?: number,

View file

@ -25,7 +25,7 @@ import * as ws from 'ws';
import { launchProcess } from './processLauncher';
import { kBrowserCloseMessageId } from '../chromium/crConnection';
import { PipeTransport } from './pipeTransport';
import { LaunchOptions, BrowserArgOptions, ConnectOptions, LaunchServerOptions, AbstractBrowserType } from './browserType';
import { LaunchOptions, BrowserArgOptions, ConnectOptions, LaunchServerOptions, AbstractBrowserType, processBrowserArgOptions } from './browserType';
import { LaunchType } from '../browser';
import { BrowserServer, WebSocketWrapper } from './browserServer';
import { Events } from '../events';
@ -48,10 +48,13 @@ export class Chromium extends AbstractBrowserType<CRBrowser> {
return await browserServer._initializeOrClose(deadline, async () => {
if ((options as any).__testHookBeforeCreateBrowser)
await (options as any).__testHookBeforeCreateBrowser();
const browser = await CRBrowser.connect(transport!, false, logger, options);
browser._ownedServer = browserServer;
browser._downloadsPath = downloadsPath;
return browser;
return await CRBrowser.connect(transport!, {
slowMo: options.slowMo,
headful: !processBrowserArgOptions(options).headless,
logger,
downloadsPath,
ownedServer: browserServer
});
});
}
@ -62,12 +65,18 @@ export class Chromium extends AbstractBrowserType<CRBrowser> {
async launchPersistentContext(userDataDir: string, options: LaunchOptions = {}): Promise<BrowserContext> {
const { timeout = 30000 } = options;
const deadline = TimeoutSettings.computeDeadline(timeout);
const { transport, browserServer, logger } = await this._launchServer(options, 'persistent', userDataDir);
const { transport, browserServer, downloadsPath, logger } = await this._launchServer(options, 'persistent', userDataDir);
return await browserServer._initializeOrClose(deadline, async () => {
if ((options as any).__testHookBeforeCreateBrowser)
await (options as any).__testHookBeforeCreateBrowser();
const browser = await CRBrowser.connect(transport!, true, logger, options);
browser._ownedServer = browserServer;
const browser = await CRBrowser.connect(transport!, {
slowMo: options.slowMo,
persistent: true,
logger,
downloadsPath,
headful: !processBrowserArgOptions(options).headless,
ownedServer: browserServer
});
const context = browser._defaultContext!;
if (!options.ignoreDefaultArgs || Array.isArray(options.ignoreDefaultArgs))
await context._loadDefaultContext();
@ -109,6 +118,11 @@ export class Chromium extends AbstractBrowserType<CRBrowser> {
const chromeExecutable = executablePath || this.executablePath();
if (!chromeExecutable)
throw new Error(`No executable path is specified. Pass "executablePath" option directly.`);
// Note: it is important to define these variables before launchProcess, so that we don't get
// "Cannot access 'browserServer' before initialization" if something went wrong.
let transport: PipeTransport | undefined = undefined;
let browserServer: BrowserServer | undefined = undefined;
const { launchedProcess, gracefullyClose, downloadsPath } = await launchProcess({
executablePath: chromeExecutable,
args: chromeArguments,
@ -134,8 +148,6 @@ export class Chromium extends AbstractBrowserType<CRBrowser> {
},
});
let transport: PipeTransport | undefined = undefined;
let browserServer: BrowserServer | undefined = undefined;
const stdio = launchedProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream];
transport = new PipeTransport(stdio[3], stdio[4], logger);
browserServer = new BrowserServer(launchedProcess, gracefullyClose, launchType === 'server' ? wrapTransportWithWebSocket(transport, logger, port) : null);
@ -146,16 +158,13 @@ export class Chromium extends AbstractBrowserType<CRBrowser> {
return await WebSocketTransport.connect(options.wsEndpoint, async transport => {
if ((options as any).__testHookBeforeCreateBrowser)
await (options as any).__testHookBeforeCreateBrowser();
return CRBrowser.connect(transport, false, new RootLogger(options.logger), options);
return CRBrowser.connect(transport, { slowMo: options.slowMo, logger: new RootLogger(options.logger), downloadsPath: '' });
});
}
private _defaultArgs(options: BrowserArgOptions = {}, launchType: LaunchType, userDataDir: string): string[] {
const {
devtools = false,
headless = !devtools,
args = [],
} = options;
const { devtools, headless } = processBrowserArgOptions(options);
const { args = [] } = options;
const userDataDirArg = args.find(arg => arg.startsWith('--user-data-dir'));
if (userDataDirArg)
throw new Error('Pass userDataDir parameter instead of specifying --user-data-dir argument');

View file

@ -204,8 +204,7 @@ export class Electron {
return transport;
});
const browserServer = new BrowserServer(launchedProcess, gracefullyClose, null);
const browser = await CRBrowser.connect(chromeTransport, true, logger, { ...options, viewport: null });
browser._ownedServer = browserServer;
const browser = await CRBrowser.connect(chromeTransport, { headful: true, logger, persistent: true, viewport: null, ownedServer: browserServer, downloadsPath: '' });
app = new ElectronApplication(logger, browser, nodeConnection);
await app._init();
return app;

View file

@ -28,7 +28,7 @@ import { FFBrowser } from '../firefox/ffBrowser';
import { kBrowserCloseMessageId } from '../firefox/ffConnection';
import { helper, assert } from '../helper';
import { BrowserServer, WebSocketWrapper } from './browserServer';
import { BrowserArgOptions, LaunchOptions, LaunchServerOptions, ConnectOptions, AbstractBrowserType } from './browserType';
import { BrowserArgOptions, LaunchOptions, LaunchServerOptions, ConnectOptions, AbstractBrowserType, processBrowserArgOptions } from './browserType';
import { launchProcess, waitForLine } from './processLauncher';
import { ConnectionTransport, SequenceNumberMixer, WebSocketTransport } from '../transport';
import { RootLogger, InnerLogger, logError } from '../logger';
@ -51,10 +51,14 @@ export class Firefox extends AbstractBrowserType<FFBrowser> {
if ((options as any).__testHookBeforeCreateBrowser)
await (options as any).__testHookBeforeCreateBrowser();
const browser = await WebSocketTransport.connect(browserServer.wsEndpoint()!, transport => {
return FFBrowser.connect(transport, logger, false, options.slowMo);
return FFBrowser.connect(transport, {
slowMo: options.slowMo,
logger,
downloadsPath,
headful: !processBrowserArgOptions(options).headless,
ownedServer: browserServer,
});
});
browser._ownedServer = browserServer;
browser._downloadsPath = downloadsPath;
return browser;
});
}
@ -64,20 +68,22 @@ export class Firefox extends AbstractBrowserType<FFBrowser> {
}
async launchPersistentContext(userDataDir: string, options: LaunchOptions = {}): Promise<BrowserContext> {
const {
timeout = 30000,
slowMo = 0,
} = options;
const { timeout = 30000 } = options;
const deadline = TimeoutSettings.computeDeadline(timeout);
const { browserServer, downloadsPath, logger } = await this._launchServer(options, 'persistent', userDataDir);
return await browserServer._initializeOrClose(deadline, async () => {
if ((options as any).__testHookBeforeCreateBrowser)
await (options as any).__testHookBeforeCreateBrowser();
const browser = await WebSocketTransport.connect(browserServer.wsEndpoint()!, transport => {
return FFBrowser.connect(transport, logger, true, slowMo);
return FFBrowser.connect(transport, {
slowMo: options.slowMo,
logger,
persistent: true,
downloadsPath,
ownedServer: browserServer,
headful: !processBrowserArgOptions(options).headless,
});
});
browser._ownedServer = browserServer;
browser._downloadsPath = downloadsPath;
const context = browser._defaultContext!;
if (!options.ignoreDefaultArgs || Array.isArray(options.ignoreDefaultArgs))
await context._loadDefaultContext();
@ -118,6 +124,10 @@ export class Firefox extends AbstractBrowserType<FFBrowser> {
if (!firefoxExecutable)
throw new Error(`No executable path is specified. Pass "executablePath" option directly.`);
// Note: it is important to define these variables before launchProcess, so that we don't get
// "Cannot access 'browserServer' before initialization" if something went wrong.
let browserServer: BrowserServer | undefined = undefined;
let browserWSEndpoint: string | undefined = undefined;
const { launchedProcess, gracefullyClose, downloadsPath } = await launchProcess({
executablePath: firefoxExecutable,
args: firefoxArguments,
@ -149,8 +159,6 @@ export class Firefox extends AbstractBrowserType<FFBrowser> {
const match = await waitForLine(launchedProcess, launchedProcess.stdout, /^Juggler listening on (ws:\/\/.*)$/, timeout, timeoutError);
const innerEndpoint = match[1];
let browserServer: BrowserServer | undefined = undefined;
let browserWSEndpoint: string | undefined = undefined;
const webSocketWrapper = launchType === 'server' ? (await WebSocketTransport.connect(innerEndpoint, t => wrapTransportWithWebSocket(t, logger, port))) : new WebSocketWrapper(innerEndpoint, []);
browserWSEndpoint = webSocketWrapper.wsEndpoint;
browserServer = new BrowserServer(launchedProcess, gracefullyClose, webSocketWrapper);
@ -161,16 +169,13 @@ export class Firefox extends AbstractBrowserType<FFBrowser> {
return await WebSocketTransport.connect(options.wsEndpoint, async transport => {
if ((options as any).__testHookBeforeCreateBrowser)
await (options as any).__testHookBeforeCreateBrowser();
return FFBrowser.connect(transport, new RootLogger(options.logger), false, options.slowMo);
return FFBrowser.connect(transport, { slowMo: options.slowMo, logger: new RootLogger(options.logger), downloadsPath: '' });
});
}
private _defaultArgs(options: BrowserArgOptions = {}, launchType: LaunchType, userDataDir: string, port: number): string[] {
const {
devtools = false,
headless = !devtools,
args = [],
} = options;
const { devtools, headless } = processBrowserArgOptions(options);
const { args = [] } = options;
if (devtools)
console.warn('devtools parameter is not supported as a launch argument in Firefox. You can launch the devtools window manually.');
const userDataDirArg = args.find(arg => arg.startsWith('-profile') || arg.startsWith('--profile'));

View file

@ -24,7 +24,7 @@ import * as os from 'os';
import * as util from 'util';
import { helper, assert } from '../helper';
import { kBrowserCloseMessageId } from '../webkit/wkConnection';
import { LaunchOptions, BrowserArgOptions, LaunchServerOptions, ConnectOptions, AbstractBrowserType } from './browserType';
import { LaunchOptions, BrowserArgOptions, LaunchServerOptions, ConnectOptions, AbstractBrowserType, processBrowserArgOptions } from './browserType';
import { ConnectionTransport, SequenceNumberMixer, WebSocketTransport } from '../transport';
import * as ws from 'ws';
import { LaunchType } from '../browser';
@ -48,10 +48,13 @@ export class WebKit extends AbstractBrowserType<WKBrowser> {
return await browserServer._initializeOrClose(deadline, async () => {
if ((options as any).__testHookBeforeCreateBrowser)
await (options as any).__testHookBeforeCreateBrowser();
const browser = await WKBrowser.connect(transport!, logger, options.slowMo, false);
browser._ownedServer = browserServer;
browser._downloadsPath = downloadsPath;
return browser;
return await WKBrowser.connect(transport!, {
slowMo: options.slowMo,
headful: !processBrowserArgOptions(options).headless,
logger,
downloadsPath,
ownedServer: browserServer
});
});
}
@ -60,17 +63,20 @@ export class WebKit extends AbstractBrowserType<WKBrowser> {
}
async launchPersistentContext(userDataDir: string, options: LaunchOptions = {}): Promise<BrowserContext> {
const {
timeout = 30000,
slowMo = 0,
} = options;
const { timeout = 30000 } = options;
const deadline = TimeoutSettings.computeDeadline(timeout);
const { transport, browserServer, logger } = await this._launchServer(options, 'persistent', userDataDir);
const { transport, browserServer, logger, downloadsPath } = await this._launchServer(options, 'persistent', userDataDir);
return await browserServer._initializeOrClose(deadline, async () => {
if ((options as any).__testHookBeforeCreateBrowser)
await (options as any).__testHookBeforeCreateBrowser();
const browser = await WKBrowser.connect(transport!, logger, slowMo, true);
browser._ownedServer = browserServer;
const browser = await WKBrowser.connect(transport!, {
slowMo: options.slowMo,
headful: !processBrowserArgOptions(options).headless,
logger,
persistent: true,
downloadsPath,
ownedServer: browserServer
});
const context = browser._defaultContext!;
if (!options.ignoreDefaultArgs || Array.isArray(options.ignoreDefaultArgs))
await context._loadDefaultContext();
@ -110,6 +116,10 @@ export class WebKit extends AbstractBrowserType<WKBrowser> {
if (!webkitExecutable)
throw new Error(`No executable path is specified.`);
// Note: it is important to define these variables before launchProcess, so that we don't get
// "Cannot access 'browserServer' before initialization" if something went wrong.
let transport: ConnectionTransport | undefined = undefined;
let browserServer: BrowserServer | undefined = undefined;
const { launchedProcess, gracefullyClose, downloadsPath } = await launchProcess({
executablePath: webkitExecutable,
args: webkitArguments,
@ -133,10 +143,6 @@ export class WebKit extends AbstractBrowserType<WKBrowser> {
},
});
// Note: it is important to define these variables before launchProcess, so that we don't get
// "Cannot access 'browserServer' before initialization" if something went wrong.
let transport: ConnectionTransport | undefined = undefined;
let browserServer: BrowserServer | undefined = undefined;
const stdio = launchedProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream];
transport = new PipeTransport(stdio[3], stdio[4], logger);
browserServer = new BrowserServer(launchedProcess, gracefullyClose, launchType === 'server' ? wrapTransportWithWebSocket(transport, logger, port || 0) : null);
@ -147,16 +153,13 @@ export class WebKit extends AbstractBrowserType<WKBrowser> {
return await WebSocketTransport.connect(options.wsEndpoint, async transport => {
if ((options as any).__testHookBeforeCreateBrowser)
await (options as any).__testHookBeforeCreateBrowser();
return WKBrowser.connect(transport, new RootLogger(options.logger), options.slowMo);
return WKBrowser.connect(transport, { slowMo: options.slowMo, logger: new RootLogger(options.logger), downloadsPath: '' });
});
}
_defaultArgs(options: BrowserArgOptions = {}, launchType: LaunchType, userDataDir: string, port: number): string[] {
const {
devtools = false,
headless = !devtools,
args = [],
} = options;
const { devtools, headless } = processBrowserArgOptions(options);
const { args = [] } = options;
if (devtools)
console.warn('devtools parameter as a launch argument in WebKit is not supported. Also starting Web Inspector manually will terminate the execution in WebKit.');
const userDataDirArg = args.find(arg => arg.startsWith('--user-data-dir='));

View file

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { BrowserBase } from '../browser';
import { BrowserBase, BrowserOptions } from '../browser';
import { assertBrowserContextIsNotOwned, BrowserContext, BrowserContextBase, BrowserContextOptions, validateBrowserContextOptions, verifyGeolocation } from '../browserContext';
import { Events } from '../events';
import { helper, RegisteredListener } from '../helper';
@ -26,7 +26,6 @@ import * as types from '../types';
import { Protocol } from './protocol';
import { kPageProxyMessageReceived, PageProxyMessageReceivedPayload, WKConnection, WKSession } from './wkConnection';
import { WKPage } from './wkPage';
import { InnerLogger } from '../logger';
const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.4 Safari/605.1.15';
@ -38,17 +37,17 @@ export class WKBrowser extends BrowserBase {
readonly _wkPages = new Map<string, WKPage>();
private readonly _eventListeners: RegisteredListener[];
static async connect(transport: ConnectionTransport, logger: InnerLogger, slowMo: number = 0, attachToDefaultContext: boolean = false): Promise<WKBrowser> {
const browser = new WKBrowser(SlowMoTransport.wrap(transport, slowMo), logger, attachToDefaultContext);
static async connect(transport: ConnectionTransport, options: BrowserOptions): Promise<WKBrowser> {
const browser = new WKBrowser(SlowMoTransport.wrap(transport, options.slowMo), options);
return browser;
}
constructor(transport: ConnectionTransport, logger: InnerLogger, attachToDefaultContext: boolean) {
super(logger);
this._connection = new WKConnection(transport, logger, this._onDisconnect.bind(this));
constructor(transport: ConnectionTransport, options: BrowserOptions) {
super(options);
this._connection = new WKConnection(transport, options.logger, this._onDisconnect.bind(this));
this._browserSession = this._connection.browserSession;
if (attachToDefaultContext)
if (options.persistent)
this._defaultContext = new WKBrowserContext(this, undefined, validateBrowserContextOptions({}));
this._eventListeners = [
@ -205,7 +204,7 @@ export class WKBrowserContext extends BrowserContextBase {
const promises: Promise<any>[] = [
this._browser._browserSession.send('Playwright.setDownloadBehavior', {
behavior: this._options.acceptDownloads ? 'allow' : 'deny',
downloadPath: this._browser._downloadsPath,
downloadPath: this._browser._options.downloadsPath,
browserContextId
})
];

View file

@ -146,7 +146,7 @@ describe('Electron per window', function() {
afterEach(async state => {
await state.page.close();
});
it('should click the button', async({page, server}) => {
await page.goto(server.PREFIX + '/input/button.html');
await page.click('button');

View file

@ -80,17 +80,16 @@ function collect(browserNames) {
const playwrightEnvironment = new Environment('Playwright');
playwrightEnvironment.beforeAll(async state => {
state.playwright = playwright;
global.playwright = playwright;
});
playwrightEnvironment.afterAll(async state => {
delete state.playwright;
delete global.playwright;
});
testRunner.collector().useEnvironment(playwrightEnvironment);
for (const e of config.globalEnvironments || [])
testRunner.collector().useEnvironment(e);
global.playwright = playwright;
for (const browserName of browserNames) {
const browserType = playwright[browserName];
const browserTypeEnvironment = new Environment('BrowserType');
@ -172,7 +171,6 @@ function collect(browserNames) {
const suiteName = { 'chromium': 'Chromium', 'firefox': 'Firefox', 'webkit': 'WebKit' }[browserName];
describe(suiteName, () => {
// In addition to state, expose these two on global so that describes can access them.
global.playwright = playwright;
global.browserType = browserType;
global.HEADLESS = !!launchOptions.headless;
@ -200,7 +198,6 @@ function collect(browserNames) {
delete global.HEADLESS;
delete global.browserType;
delete global.playwright;
});
}
for (const [key, value] of Object.entries(testRunner.api())) {