Skip to content

Commit

Permalink
feat: add missing slowMo to launchPersistentContext (#1597)
Browse files Browse the repository at this point in the history
`slowMo` was missing in `launchPersistentContext`, and I refactored the types a bit.
  • Loading branch information
JoelEinbinder committed Mar 31, 2020
1 parent a853690 commit 6053784
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 52 deletions.
1 change: 1 addition & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -3690,6 +3690,7 @@ const browser = await chromium.launch({ // Or 'firefox' or 'webkit'.
- `dumpio` <[boolean]> Whether to pipe the browser process stdout and stderr into `process.stdout` and `process.stderr`. Defaults to `false`.
- `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
- `devtools` <[boolean]> **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is `true`, the `headless` option will be set `false`.
- `slowMo` <[number]> Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on. Defaults to 0.
- returns: <[Promise]<[BrowserContext]>> Promise which resolves to the browser app instance.

Launches browser instance that uses persistent storage located at `userDataDir`.
Expand Down
5 changes: 0 additions & 5 deletions src/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@ export interface Browser extends platform.EventEmitterType {
_setDebugFunction(debugFunction: (message: string) => void): void;
}

export type ConnectOptions = {
slowMo?: number,
wsEndpoint: string
};

export async function createPageInNewContext(browser: Browser, options?: BrowserContextOptions): Promise<Page> {
const context = await browser.newContext(options);
const page = await context.newPage();
Expand Down
13 changes: 9 additions & 4 deletions src/server/browserType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* limitations under the License.
*/

import { ConnectOptions } from '../browser';
import { BrowserContext } from '../browserContext';
import { BrowserServer } from './browserServer';

Expand All @@ -24,7 +23,7 @@ export type BrowserArgOptions = {
devtools?: boolean,
};

export type LaunchOptions = BrowserArgOptions & {
type LaunchOptionsBase = BrowserArgOptions & {
executablePath?: string,
ignoreDefaultArgs?: boolean | string[],
handleSIGINT?: boolean,
Expand All @@ -39,11 +38,17 @@ export type LaunchOptions = BrowserArgOptions & {
env?: {[key: string]: string} | undefined
};

export type ConnectOptions = {
wsEndpoint: string,
slowMo?: number
};
export type LaunchOptions = LaunchOptionsBase & { slowMo?: number };
export type LaunchServerOptions = LaunchOptionsBase & { port?: number };
export interface BrowserType<Browser> {
executablePath(): string;
name(): string;
launch(options?: LaunchOptions & { slowMo?: number }): Promise<Browser>;
launchServer(options?: LaunchOptions & { port?: number }): Promise<BrowserServer>;
launch(options?: LaunchOptions): Promise<Browser>;
launchServer(options?: LaunchServerOptions): Promise<BrowserServer>;
launchPersistentContext(userDataDir: string, options?: LaunchOptions): Promise<BrowserContext>;
connect(options: ConnectOptions): Promise<Browser>;
}
32 changes: 18 additions & 14 deletions src/server/chromium.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { debugError, helper } from '../helper';
import { debugError, helper, assert } from '../helper';
import { CRBrowser } from '../chromium/crBrowser';
import * as platform from '../platform';
import * as ws from 'ws';
import { launchProcess } from '../server/processLauncher';
import { kBrowserCloseMessageId } from '../chromium/crConnection';
import { PipeTransport } from './pipeTransport';
import { LaunchOptions, BrowserArgOptions, BrowserType } from './browserType';
import { ConnectOptions, LaunchType } from '../browser';
import { LaunchOptions, BrowserArgOptions, BrowserType, ConnectOptions, LaunchServerOptions } from './browserType';
import { LaunchType } from '../browser';
import { BrowserServer, WebSocketWrapper } from './browserServer';
import { Events } from '../events';
import { ConnectionTransport, ProtocolRequest } from '../transport';
Expand All @@ -45,28 +45,30 @@ export class Chromium implements BrowserType<CRBrowser> {
return 'chromium';
}

async launch(options?: LaunchOptions & { slowMo?: number }): Promise<CRBrowser> {
if (options && (options as any).userDataDir)
throw new Error('userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
async launch(options: LaunchOptions = {}): Promise<CRBrowser> {
assert(!(options as any).userDataDir, 'userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
const { browserServer, transport } = await this._launchServer(options, 'local');
const browser = await CRBrowser.connect(transport!, false, options && options.slowMo);
const browser = await CRBrowser.connect(transport!, false, options.slowMo);
(browser as any)['__server__'] = browserServer;
return browser;
}

async launchServer(options?: LaunchOptions & { port?: number }): Promise<BrowserServer> {
return (await this._launchServer(options, 'server', undefined, options && options.port)).browserServer;
async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServer> {
return (await this._launchServer(options, 'server')).browserServer;
}

async launchPersistentContext(userDataDir: string, options?: LaunchOptions): Promise<BrowserContext> {
const { timeout = 30000 } = options || {};
async launchPersistentContext(userDataDir: string, options: LaunchOptions = {}): Promise<BrowserContext> {
const {
timeout = 30000,
slowMo = 0
} = options;
const { transport } = await this._launchServer(options, 'persistent', userDataDir);
const browser = await CRBrowser.connect(transport!, true);
const browser = await CRBrowser.connect(transport!, true, slowMo);
await helper.waitWithTimeout(browser._firstPagePromise, 'first page', timeout);
return browser._defaultContext;
}

private async _launchServer(options: LaunchOptions = {}, launchType: LaunchType, userDataDir?: string, port?: number): Promise<{ browserServer: BrowserServer, transport?: ConnectionTransport }> {
private async _launchServer(options: LaunchServerOptions, launchType: LaunchType, userDataDir?: string): Promise<{ browserServer: BrowserServer, transport?: ConnectionTransport }> {
const {
ignoreDefaultArgs = false,
args = [],
Expand All @@ -76,7 +78,9 @@ export class Chromium implements BrowserType<CRBrowser> {
handleSIGINT = true,
handleSIGTERM = true,
handleSIGHUP = true,
port = 0,
} = options;
assert(!port || launchType === 'server', 'Cannot specify a port without launching as a server.');

let temporaryUserDataDir: string | null = null;
if (!userDataDir) {
Expand Down Expand Up @@ -124,7 +128,7 @@ export class Chromium implements BrowserType<CRBrowser> {
let transport: PipeTransport | undefined = undefined;
let browserServer: BrowserServer | undefined = undefined;
transport = new PipeTransport(launchedProcess.stdio[3] as NodeJS.WritableStream, launchedProcess.stdio[4] as NodeJS.ReadableStream, () => browserServer!.close());
browserServer = new BrowserServer(launchedProcess, gracefullyClose, launchType === 'server' ? wrapTransportWithWebSocket(transport, port || 0) : null);
browserServer = new BrowserServer(launchedProcess, gracefullyClose, launchType === 'server' ? wrapTransportWithWebSocket(transport, port) : null);
return { browserServer, transport };
}

Expand Down
32 changes: 18 additions & 14 deletions src/server/firefox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import * as ws from 'ws';
import { ConnectOptions, LaunchType } from '../browser';
import { LaunchType } from '../browser';
import { BrowserContext } from '../browserContext';
import { TimeoutError } from '../errors';
import { Events } from '../events';
import { FFBrowser } from '../firefox/ffBrowser';
import { kBrowserCloseMessageId } from '../firefox/ffConnection';
import { debugError, helper } from '../helper';
import { debugError, helper, assert } from '../helper';
import * as platform from '../platform';
import { BrowserServer, WebSocketWrapper } from './browserServer';
import { BrowserArgOptions, BrowserType, LaunchOptions } from './browserType';
import { BrowserArgOptions, BrowserType, LaunchOptions, LaunchServerOptions, ConnectOptions } from './browserType';
import { launchProcess, waitForLine } from './processLauncher';
import { ConnectionTransport, SequenceNumberMixer } from '../transport';

Expand All @@ -47,28 +47,30 @@ export class Firefox implements BrowserType<FFBrowser> {
return 'firefox';
}

async launch(options?: LaunchOptions & { slowMo?: number }): Promise<FFBrowser> {
if (options && (options as any).userDataDir)
throw new Error('userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
async launch(options: LaunchOptions = {}): Promise<FFBrowser> {
assert(!(options as any).userDataDir, 'userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
const browserServer = await this._launchServer(options, 'local');
const browser = await platform.connectToWebsocket(browserServer.wsEndpoint()!, transport => {
return FFBrowser.connect(transport, false, options && options.slowMo);
return FFBrowser.connect(transport, false, options.slowMo);
});
// Hack: for typical launch scenario, ensure that close waits for actual process termination.
browser.close = () => browserServer.close();
(browser as any)['__server__'] = browserServer;
return browser;
}

async launchServer(options?: LaunchOptions & { port?: number }): Promise<BrowserServer> {
return await this._launchServer(options, 'server', undefined, options && options.port);
async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServer> {
return await this._launchServer(options, 'server');
}

async launchPersistentContext(userDataDir: string, options?: LaunchOptions): Promise<BrowserContext> {
const { timeout = 30000 } = options || {};
async launchPersistentContext(userDataDir: string, options: LaunchOptions = {}): Promise<BrowserContext> {
const {
timeout = 30000,
slowMo = 0,
} = options;
const browserServer = await this._launchServer(options, 'persistent', userDataDir);
const browser = await platform.connectToWebsocket(browserServer.wsEndpoint()!, transport => {
return FFBrowser.connect(transport, true);
return FFBrowser.connect(transport, true, slowMo);
});
await helper.waitWithTimeout(browser._firstPagePromise, 'first page', timeout);
// Hack: for typical launch scenario, ensure that close waits for actual process termination.
Expand All @@ -77,7 +79,7 @@ export class Firefox implements BrowserType<FFBrowser> {
return browserContext;
}

private async _launchServer(options: LaunchOptions = {}, launchType: LaunchType, userDataDir?: string, port?: number): Promise<BrowserServer> {
private async _launchServer(options: LaunchServerOptions, launchType: LaunchType, userDataDir?: string): Promise<BrowserServer> {
const {
ignoreDefaultArgs = false,
args = [],
Expand All @@ -88,7 +90,9 @@ export class Firefox implements BrowserType<FFBrowser> {
handleSIGINT = true,
handleSIGTERM = true,
timeout = 30000,
port = 0,
} = options;
assert(!port || launchType === 'server', 'Cannot specify a port without launching as a server.');

const firefoxArguments = [];

Expand Down Expand Up @@ -145,7 +149,7 @@ export class Firefox implements BrowserType<FFBrowser> {

let browserServer: BrowserServer | undefined = undefined;
let browserWSEndpoint: string | undefined = undefined;
const webSocketWrapper = launchType === 'server' ? (await platform.connectToWebsocket(innerEndpoint, t => wrapTransportWithWebSocket(t, port || 0))) : new WebSocketWrapper(innerEndpoint, []);
const webSocketWrapper = launchType === 'server' ? (await platform.connectToWebsocket(innerEndpoint, t => wrapTransportWithWebSocket(t, port))) : new WebSocketWrapper(innerEndpoint, []);
browserWSEndpoint = webSocketWrapper.wsEndpoint;
browserServer = new BrowserServer(launchedProcess, gracefullyClose, webSocketWrapper);
return browserServer;
Expand Down
34 changes: 19 additions & 15 deletions src/server/webkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import * as fs from 'fs';
import * as path from 'path';
import * as platform from '../platform';
import * as os from 'os';
import { debugError, helper } from '../helper';
import { debugError, helper, assert } from '../helper';
import { kBrowserCloseMessageId } from '../webkit/wkConnection';
import { LaunchOptions, BrowserArgOptions, BrowserType } from './browserType';
import { LaunchOptions, BrowserArgOptions, BrowserType, LaunchServerOptions, ConnectOptions } from './browserType';
import { ConnectionTransport, SequenceNumberMixer } from '../transport';
import * as ws from 'ws';
import { ConnectOptions, LaunchType } from '../browser';
import { LaunchType } from '../browser';
import { BrowserServer, WebSocketWrapper } from './browserServer';
import { Events } from '../events';
import { BrowserContext } from '../browserContext';
Expand All @@ -45,28 +45,30 @@ export class WebKit implements BrowserType<WKBrowser> {
return 'webkit';
}

async launch(options?: LaunchOptions & { slowMo?: number }): Promise<WKBrowser> {
if (options && (options as any).userDataDir)
throw new Error('userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
async launch(options: LaunchOptions = {}): Promise<WKBrowser> {
assert(!(options as any).userDataDir, 'userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
const { browserServer, transport } = await this._launchServer(options, 'local');
const browser = await WKBrowser.connect(transport!, options && options.slowMo);
const browser = await WKBrowser.connect(transport!, options.slowMo);
(browser as any)['__server__'] = browserServer;
return browser;
}

async launchServer(options?: LaunchOptions & { port?: number }): Promise<BrowserServer> {
return (await this._launchServer(options, 'server', undefined, options && options.port)).browserServer;
async launchServer(options: LaunchServerOptions = {}): Promise<BrowserServer> {
return (await this._launchServer(options, 'server')).browserServer;
}

async launchPersistentContext(userDataDir: string, options?: LaunchOptions): Promise<BrowserContext> {
const { timeout = 30000 } = options || {};
async launchPersistentContext(userDataDir: string, options: LaunchOptions = {}): Promise<BrowserContext> {
const {
timeout = 30000,
slowMo = 0,
} = options;
const { transport } = await this._launchServer(options, 'persistent', userDataDir);
const browser = await WKBrowser.connect(transport!, undefined, true);
const browser = await WKBrowser.connect(transport!, slowMo, true);
await helper.waitWithTimeout(browser._waitForFirstPageTarget(), 'first page', timeout);
return browser._defaultContext;
}

private async _launchServer(options: LaunchOptions = {}, launchType: LaunchType, userDataDir?: string, port?: number): Promise<{ browserServer: BrowserServer, transport?: ConnectionTransport }> {
private async _launchServer(options: LaunchServerOptions, launchType: LaunchType, userDataDir?: string): Promise<{ browserServer: BrowserServer, transport?: ConnectionTransport }> {
const {
ignoreDefaultArgs = false,
args = [],
Expand All @@ -76,7 +78,9 @@ export class WebKit implements BrowserType<WKBrowser> {
handleSIGINT = true,
handleSIGTERM = true,
handleSIGHUP = true,
port = 0,
} = options;
assert(!port || launchType === 'server', 'Cannot specify a port without launching as a server.');

let temporaryUserDataDir: string | null = null;
if (!userDataDir) {
Expand All @@ -86,9 +90,9 @@ export class WebKit implements BrowserType<WKBrowser> {

const webkitArguments = [];
if (!ignoreDefaultArgs)
webkitArguments.push(...this._defaultArgs(options, launchType, userDataDir!, port || 0));
webkitArguments.push(...this._defaultArgs(options, launchType, userDataDir!, port));
else if (Array.isArray(ignoreDefaultArgs))
webkitArguments.push(...this._defaultArgs(options, launchType, userDataDir!, port || 0).filter(arg => ignoreDefaultArgs.indexOf(arg) === -1));
webkitArguments.push(...this._defaultArgs(options, launchType, userDataDir!, port).filter(arg => ignoreDefaultArgs.indexOf(arg) === -1));
else
webkitArguments.push(...args);

Expand Down

0 comments on commit 6053784

Please sign in to comment.