feat(launch): introduce client, server & persistent launch modes (1) (#838)
This commit is contained in:
parent
bdf8e39786
commit
0518625dcc
30
docs/api.md
30
docs/api.md
|
|
@ -149,10 +149,10 @@ An example of launching a browser executable and connecting to a [Browser] later
|
||||||
const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.
|
const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const browserApp = await webkit.launchBrowserApp({ webSocket: true });
|
const browserApp = await webkit.launchBrowserApp();
|
||||||
const connectOptions = browserApp.connectOptions();
|
const wsEndpoint = browserApp.wsEndpoint();
|
||||||
// Use connect options later to establish a connection.
|
// Use web socket endpoint later to establish a connection.
|
||||||
const browser = await webkit.connect(connectOptions);
|
const browser = await webkit.connect({ wsEndpoint });
|
||||||
// Close browser instance.
|
// Close browser instance.
|
||||||
await browserApp.close();
|
await browserApp.close();
|
||||||
})();
|
})();
|
||||||
|
|
@ -3413,7 +3413,6 @@ If the function passed to the `worker.evaluateHandle` returns a [Promise], then
|
||||||
<!-- GEN:toc -->
|
<!-- GEN:toc -->
|
||||||
- [event: 'close'](#event-close-2)
|
- [event: 'close'](#event-close-2)
|
||||||
- [browserApp.close()](#browserappclose)
|
- [browserApp.close()](#browserappclose)
|
||||||
- [browserApp.connectOptions()](#browserappconnectoptions)
|
|
||||||
- [browserApp.kill()](#browserappkill)
|
- [browserApp.kill()](#browserappkill)
|
||||||
- [browserApp.process()](#browserappprocess)
|
- [browserApp.process()](#browserappprocess)
|
||||||
- [browserApp.wsEndpoint()](#browserappwsendpoint)
|
- [browserApp.wsEndpoint()](#browserappwsendpoint)
|
||||||
|
|
@ -3428,14 +3427,6 @@ Emitted when the browser app closes.
|
||||||
|
|
||||||
Closes the browser gracefully and makes sure the process is terminated.
|
Closes the browser gracefully and makes sure the process is terminated.
|
||||||
|
|
||||||
#### browserApp.connectOptions()
|
|
||||||
- returns: <[Object]>
|
|
||||||
- `browserWSEndpoint` <?[string]> a browser websocket endpoint to connect to.
|
|
||||||
- `slowMo` <[number]>
|
|
||||||
- `transport` <[ConnectionTransport]> **Experimental** A custom transport object which should be used to connect.
|
|
||||||
|
|
||||||
This options object can be passed to [browserType.connect(options)](#browsertypeconnectoptions) to establish connection to the browser.
|
|
||||||
|
|
||||||
#### browserApp.kill()
|
#### browserApp.kill()
|
||||||
|
|
||||||
Kills the browser process.
|
Kills the browser process.
|
||||||
|
|
@ -3444,10 +3435,9 @@ Kills the browser process.
|
||||||
- returns: <?[ChildProcess]> Spawned browser application process.
|
- returns: <?[ChildProcess]> Spawned browser application process.
|
||||||
|
|
||||||
#### browserApp.wsEndpoint()
|
#### browserApp.wsEndpoint()
|
||||||
- returns: <?[string]> Browser websocket url.
|
- returns: <[string]> Browser websocket url.
|
||||||
|
|
||||||
Browser websocket endpoint which can be used as an argument to [browserType.connect(options)] to establish connection to the browser. Requires browser app to be launched with `browserType.launchBrowserApp({ webSocket: true, ... })`.
|
|
||||||
|
|
||||||
|
Browser websocket endpoint which can be used as an argument to [browserType.connect(options)](#browsertypeconnectoptions) to establish connection to the browser.
|
||||||
|
|
||||||
### class: BrowserType
|
### class: BrowserType
|
||||||
|
|
||||||
|
|
@ -3478,10 +3468,8 @@ const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'.
|
||||||
|
|
||||||
#### browserType.connect(options)
|
#### browserType.connect(options)
|
||||||
- `options` <[Object]>
|
- `options` <[Object]>
|
||||||
- `browserWSEndpoint` <?[string]> A browser websocket endpoint to connect to.
|
- `wsEndpoint` <?[string]> A browser websocket endpoint to connect to.
|
||||||
- `slowMo` <[number]> Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
- `slowMo` <[number]> Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
||||||
- `browserURL` <?[string]> **Chromium-only** A browser url to connect to, in format `http://${host}:${port}`. Use interchangeably with `browserWSEndpoint` to let Playwright fetch it from [metadata endpoint](https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target).
|
|
||||||
- `transport` <[ConnectionTransport]> **Experimental** Specify a custom transport object for Playwright to use.
|
|
||||||
- returns: <[Promise]<[Browser]>>
|
- returns: <[Promise]<[Browser]>>
|
||||||
|
|
||||||
This methods attaches Playwright to an existing browser instance.
|
This methods attaches Playwright to an existing browser instance.
|
||||||
|
|
@ -3547,7 +3535,6 @@ try {
|
||||||
- `options` <[Object]> Set of configurable options to set on the browser. Can have the following fields:
|
- `options` <[Object]> Set of configurable options to set on the browser. Can have the following fields:
|
||||||
- `headless` <[boolean]> Whether to run browser in headless mode. More details for [Chromium](https://developers.google.com/web/updates/2017/04/headless-chrome) and [Firefox](https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode). Defaults to `true` unless the `devtools` option is `true`.
|
- `headless` <[boolean]> Whether to run browser in headless mode. More details for [Chromium](https://developers.google.com/web/updates/2017/04/headless-chrome) and [Firefox](https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode). Defaults to `true` unless the `devtools` option is `true`.
|
||||||
- `executablePath` <[string]> Path to a browser executable to run instead of the bundled one. If `executablePath` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). **BEWARE**: Playwright is only [guaranteed to work](https://github.com/Microsoft/playwright/#q-why-doesnt-playwright-vxxx-work-with-chromium-vyyy) with the bundled Chromium, Firefox or WebKit, use at your own risk.
|
- `executablePath` <[string]> Path to a browser executable to run instead of the bundled one. If `executablePath` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). **BEWARE**: Playwright is only [guaranteed to work](https://github.com/Microsoft/playwright/#q-why-doesnt-playwright-vxxx-work-with-chromium-vyyy) with the bundled Chromium, Firefox or WebKit, use at your own risk.
|
||||||
- `slowMo` <[number]> Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
|
||||||
- `args` <[Array]<[string]>> Additional arguments to pass to the browser instance. The list of Chromium flags can be found [here](http://peter.sh/experiments/chromium-command-line-switches/).
|
- `args` <[Array]<[string]>> Additional arguments to pass to the browser instance. The list of Chromium flags can be found [here](http://peter.sh/experiments/chromium-command-line-switches/).
|
||||||
- `ignoreDefaultArgs` <[boolean]|[Array]<[string]>> If `true`, then do not use [`browserType.defaultArgs()`](#browsertypedefaultargsoptions). If an array is given, then filter out the given default arguments. Dangerous option; use with care. Defaults to `false`.
|
- `ignoreDefaultArgs` <[boolean]|[Array]<[string]>> If `true`, then do not use [`browserType.defaultArgs()`](#browsertypedefaultargsoptions). If an array is given, then filter out the given default arguments. Dangerous option; use with care. Defaults to `false`.
|
||||||
- `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`.
|
- `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`.
|
||||||
|
|
@ -3557,7 +3544,6 @@ try {
|
||||||
- `dumpio` <[boolean]> Whether to pipe the browser process stdout and stderr into `process.stdout` and `process.stderr`. Defaults to `false`.
|
- `dumpio` <[boolean]> Whether to pipe the browser process stdout and stderr into `process.stdout` and `process.stderr`. Defaults to `false`.
|
||||||
- `userDataDir` <[string]> Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for [Chromium](https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md) and [Firefox](https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options#User_Profile).
|
- `userDataDir` <[string]> Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for [Chromium](https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md) and [Firefox](https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options#User_Profile).
|
||||||
- `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
|
- `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
|
||||||
- `webSocket` <[boolean]> Connects to the browser over a WebSocket instead of a pipe. Defaults to `false`.
|
|
||||||
- `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`.
|
- `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`.
|
||||||
- returns: <[Promise]<[Browser]>> Promise which resolves to browser instance.
|
- returns: <[Promise]<[Browser]>> Promise which resolves to browser instance.
|
||||||
|
|
||||||
|
|
@ -3591,7 +3577,6 @@ 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`.
|
- `dumpio` <[boolean]> Whether to pipe the browser process stdout and stderr into `process.stdout` and `process.stderr`. Defaults to `false`.
|
||||||
- `userDataDir` <[string]> Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for [Chromium](https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md) and [Firefox](https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options#User_Profile).
|
- `userDataDir` <[string]> Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for [Chromium](https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md) and [Firefox](https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options#User_Profile).
|
||||||
- `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
|
- `env` <[Object]> Specify environment variables that will be visible to the browser. Defaults to `process.env`.
|
||||||
- `webSocket` <[boolean]> Connects to the browser over a WebSocket instead of a pipe. Defaults to `false`.
|
|
||||||
- `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`.
|
- `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`.
|
||||||
- returns: <[Promise]<[BrowserApp]>> Promise which resolves to the browser app instance.
|
- returns: <[Promise]<[BrowserApp]>> Promise which resolves to the browser app instance.
|
||||||
|
|
||||||
|
|
@ -3898,7 +3883,6 @@ const { chromium } = require('playwright');
|
||||||
[ChromiumBrowser]: #class-chromiumbrowser "ChromiumBrowser"
|
[ChromiumBrowser]: #class-chromiumbrowser "ChromiumBrowser"
|
||||||
[ChromiumSession]: #class-chromiumsession "ChromiumSession"
|
[ChromiumSession]: #class-chromiumsession "ChromiumSession"
|
||||||
[ChromiumTarget]: #class-chromiumtarget "ChromiumTarget"
|
[ChromiumTarget]: #class-chromiumtarget "ChromiumTarget"
|
||||||
[ConnectionTransport]: ../lib/WebSocketTransport.js "ConnectionTransport"
|
|
||||||
[ConsoleMessage]: #class-consolemessage "ConsoleMessage"
|
[ConsoleMessage]: #class-consolemessage "ConsoleMessage"
|
||||||
[Coverage]: #class-coverage "Coverage"
|
[Coverage]: #class-coverage "Coverage"
|
||||||
[Dialog]: #class-dialog "Dialog"
|
[Dialog]: #class-dialog "Dialog"
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { BrowserContext, BrowserContextOptions } from './browserContext';
|
import { BrowserContext, BrowserContextOptions } from './browserContext';
|
||||||
import { ConnectionTransport, SlowMoTransport } from './transport';
|
|
||||||
import * as platform from './platform';
|
import * as platform from './platform';
|
||||||
import { assert } from './helper';
|
|
||||||
|
|
||||||
export interface Browser extends platform.EventEmitterType {
|
export interface Browser extends platform.EventEmitterType {
|
||||||
newContext(options?: BrowserContextOptions): Promise<BrowserContext>;
|
newContext(options?: BrowserContextOptions): Promise<BrowserContext>;
|
||||||
|
|
@ -31,16 +29,5 @@ export interface Browser extends platform.EventEmitterType {
|
||||||
|
|
||||||
export type ConnectOptions = {
|
export type ConnectOptions = {
|
||||||
slowMo?: number,
|
slowMo?: number,
|
||||||
browserWSEndpoint?: string;
|
wsEndpoint: string
|
||||||
transport?: ConnectionTransport;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function createTransport(options: ConnectOptions): Promise<ConnectionTransport> {
|
|
||||||
assert(Number(!!options.browserWSEndpoint) + Number(!!options.transport) === 1, 'Exactly one of browserWSEndpoint or transport must be passed to connect');
|
|
||||||
let transport: ConnectionTransport | undefined;
|
|
||||||
if (options.transport)
|
|
||||||
transport = options.transport;
|
|
||||||
else if (options.browserWSEndpoint)
|
|
||||||
transport = await platform.createWebSocketTransport(options.browserWSEndpoint);
|
|
||||||
return SlowMoTransport.wrap(transport!, options.slowMo);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,12 @@ import { Page, Worker } from '../page';
|
||||||
import { CRTarget } from './crTarget';
|
import { CRTarget } from './crTarget';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
import { CRPage } from './crPage';
|
import { CRPage } from './crPage';
|
||||||
import { Browser, createTransport, ConnectOptions } from '../browser';
|
import { Browser } from '../browser';
|
||||||
import * as network from '../network';
|
import * as network from '../network';
|
||||||
import * as types from '../types';
|
import * as types from '../types';
|
||||||
import * as platform from '../platform';
|
import * as platform from '../platform';
|
||||||
import { readProtocolStream } from './crProtocolHelper';
|
import { readProtocolStream } from './crProtocolHelper';
|
||||||
|
import { ConnectionTransport, SlowMoTransport } from '../transport';
|
||||||
|
|
||||||
export class CRBrowser extends platform.EventEmitter implements Browser {
|
export class CRBrowser extends platform.EventEmitter implements Browser {
|
||||||
_connection: CRConnection;
|
_connection: CRConnection;
|
||||||
|
|
@ -41,9 +42,8 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
|
||||||
private _tracingPath: string | null = '';
|
private _tracingPath: string | null = '';
|
||||||
private _tracingClient: CRSession | undefined;
|
private _tracingClient: CRSession | undefined;
|
||||||
|
|
||||||
static async connect(options: ConnectOptions): Promise<CRBrowser> {
|
static async connect(transport: ConnectionTransport, slowMo?: number): Promise<CRBrowser> {
|
||||||
const transport = await createTransport(options);
|
const connection = new CRConnection(SlowMoTransport.wrap(transport, slowMo));
|
||||||
const connection = new CRConnection(transport);
|
|
||||||
const { browserContextIds } = await connection.rootSession.send('Target.getBrowserContexts');
|
const { browserContextIds } = await connection.rootSession.send('Target.getBrowserContexts');
|
||||||
const browser = new CRBrowser(connection, browserContextIds);
|
const browser = new CRBrowser(connection, browserContextIds);
|
||||||
await connection.rootSession.send('Target.setDiscoverTargets', { discover: true });
|
await connection.rootSession.send('Target.setDiscoverTargets', { discover: true });
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Browser, createTransport, ConnectOptions } from '../browser';
|
import { Browser } from '../browser';
|
||||||
import { BrowserContext, BrowserContextOptions } from '../browserContext';
|
import { BrowserContext, BrowserContextOptions } from '../browserContext';
|
||||||
import { Events } from '../events';
|
import { Events } from '../events';
|
||||||
import { assert, helper, RegisteredListener } from '../helper';
|
import { assert, helper, RegisteredListener } from '../helper';
|
||||||
|
|
@ -26,6 +26,7 @@ import { ConnectionEvents, FFConnection, FFSessionEvents } from './ffConnection'
|
||||||
import { FFPage } from './ffPage';
|
import { FFPage } from './ffPage';
|
||||||
import * as platform from '../platform';
|
import * as platform from '../platform';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
|
import { ConnectionTransport, SlowMoTransport } from '../transport';
|
||||||
|
|
||||||
export class FFBrowser extends platform.EventEmitter implements Browser {
|
export class FFBrowser extends platform.EventEmitter implements Browser {
|
||||||
_connection: FFConnection;
|
_connection: FFConnection;
|
||||||
|
|
@ -34,10 +35,9 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
|
||||||
private _contexts: Map<string, BrowserContext>;
|
private _contexts: Map<string, BrowserContext>;
|
||||||
private _eventListeners: RegisteredListener[];
|
private _eventListeners: RegisteredListener[];
|
||||||
|
|
||||||
static async connect(options: ConnectOptions): Promise<FFBrowser> {
|
static async connect(transport: ConnectionTransport, slowMo?: number): Promise<FFBrowser> {
|
||||||
const transport = await createTransport(options);
|
const connection = new FFConnection(SlowMoTransport.wrap(transport, slowMo));
|
||||||
const connection = new FFConnection(transport);
|
const { browserContextIds } = await connection.send('Target.getBrowserContexts');
|
||||||
const {browserContextIds} = await connection.send('Target.getBrowserContexts');
|
|
||||||
const browser = new FFBrowser(connection, browserContextIds);
|
const browser = new FFBrowser(connection, browserContextIds);
|
||||||
await connection.send('Target.enable');
|
await connection.send('Target.enable');
|
||||||
await browser._waitForTarget(t => t.type() === 'page');
|
await browser._waitForTarget(t => t.type() === 'page');
|
||||||
|
|
|
||||||
|
|
@ -15,19 +15,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ChildProcess, execSync } from 'child_process';
|
import { ChildProcess, execSync } from 'child_process';
|
||||||
import { ConnectOptions } from '../browser';
|
|
||||||
import * as platform from '../platform';
|
import * as platform from '../platform';
|
||||||
|
|
||||||
export class BrowserApp extends platform.EventEmitter {
|
export class BrowserApp extends platform.EventEmitter {
|
||||||
private _process: ChildProcess;
|
private _process: ChildProcess;
|
||||||
private _gracefullyClose: () => Promise<void>;
|
private _gracefullyClose: () => Promise<void>;
|
||||||
private _connectOptions: ConnectOptions;
|
private _browserWSEndpoint: string | null = null;
|
||||||
|
|
||||||
constructor(process: ChildProcess, gracefullyClose: () => Promise<void>, connectOptions: ConnectOptions) {
|
constructor(process: ChildProcess, gracefullyClose: () => Promise<void>, wsEndpoint: string | null) {
|
||||||
super();
|
super();
|
||||||
this._process = process;
|
this._process = process;
|
||||||
this._gracefullyClose = gracefullyClose;
|
this._gracefullyClose = gracefullyClose;
|
||||||
this._connectOptions = connectOptions;
|
this._browserWSEndpoint = wsEndpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
process(): ChildProcess {
|
process(): ChildProcess {
|
||||||
|
|
@ -35,11 +34,7 @@ export class BrowserApp extends platform.EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
wsEndpoint(): string | null {
|
wsEndpoint(): string | null {
|
||||||
return this._connectOptions.browserWSEndpoint || null;
|
return this._browserWSEndpoint;
|
||||||
}
|
|
||||||
|
|
||||||
connectOptions(): ConnectOptions {
|
|
||||||
return this._connectOptions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kill() {
|
kill() {
|
||||||
|
|
|
||||||
|
|
@ -34,18 +34,16 @@ export type LaunchOptions = BrowserArgOptions & {
|
||||||
handleSIGHUP?: boolean,
|
handleSIGHUP?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
dumpio?: boolean,
|
dumpio?: boolean,
|
||||||
env?: {[key: string]: string} | undefined,
|
env?: {[key: string]: string} | undefined
|
||||||
webSocket?: boolean,
|
|
||||||
slowMo?: number, // TODO: we probably don't want this in launchBrowserApp.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface BrowserType {
|
export interface BrowserType {
|
||||||
executablePath(): string;
|
executablePath(): string;
|
||||||
name(): string;
|
name(): string;
|
||||||
launchBrowserApp(options?: LaunchOptions): Promise<BrowserApp>;
|
launchBrowserApp(options?: LaunchOptions): Promise<BrowserApp>;
|
||||||
launch(options?: LaunchOptions): Promise<Browser>;
|
launch(options?: LaunchOptions & { slowMo?: number }): Promise<Browser>;
|
||||||
defaultArgs(options?: BrowserArgOptions): string[];
|
defaultArgs(options?: BrowserArgOptions): string[];
|
||||||
connect(options: ConnectOptions & { browserURL?: string }): Promise<Browser>;
|
connect(options: ConnectOptions): Promise<Browser>;
|
||||||
devices: types.Devices;
|
devices: types.Devices;
|
||||||
errors: { TimeoutError: typeof TimeoutError };
|
errors: { TimeoutError: typeof TimeoutError };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,10 @@ import { launchProcess, waitForLine } from '../server/processLauncher';
|
||||||
import { kBrowserCloseMessageId } from '../chromium/crConnection';
|
import { kBrowserCloseMessageId } from '../chromium/crConnection';
|
||||||
import { PipeTransport } from './pipeTransport';
|
import { PipeTransport } from './pipeTransport';
|
||||||
import { LaunchOptions, BrowserArgOptions, BrowserType } from './browserType';
|
import { LaunchOptions, BrowserArgOptions, BrowserType } from './browserType';
|
||||||
import { createTransport, ConnectOptions } from '../browser';
|
import { ConnectOptions } from '../browser';
|
||||||
import { BrowserApp } from './browserApp';
|
import { BrowserApp } from './browserApp';
|
||||||
import { Events } from '../events';
|
import { Events } from '../events';
|
||||||
|
import { ConnectionTransport } from '../transport';
|
||||||
|
|
||||||
export class Chromium implements BrowserType {
|
export class Chromium implements BrowserType {
|
||||||
private _projectRoot: string;
|
private _projectRoot: string;
|
||||||
|
|
@ -47,26 +48,29 @@ export class Chromium implements BrowserType {
|
||||||
return 'chromium';
|
return 'chromium';
|
||||||
}
|
}
|
||||||
|
|
||||||
async launch(options?: LaunchOptions): Promise<CRBrowser> {
|
async launch(options?: LaunchOptions & { slowMo?: number }): Promise<CRBrowser> {
|
||||||
const app = await this.launchBrowserApp(options);
|
const { browserApp, transport } = await this._launchBrowserApp(options, false);
|
||||||
const browser = await CRBrowser.connect(app.connectOptions());
|
const browser = await CRBrowser.connect(transport!, options && options.slowMo);
|
||||||
// Hack: for typical launch scenario, ensure that close waits for actual process termination.
|
// Hack: for typical launch scenario, ensure that close waits for actual process termination.
|
||||||
browser.close = () => app.close();
|
browser.close = () => browserApp.close();
|
||||||
|
(browser as any)['__app__'] = browserApp;
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
async launchBrowserApp(options: LaunchOptions = {}): Promise<BrowserApp> {
|
async launchBrowserApp(options?: LaunchOptions): Promise<BrowserApp> {
|
||||||
|
return (await this._launchBrowserApp(options, true)).browserApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _launchBrowserApp(options: LaunchOptions = {}, isServer: boolean): Promise<{ browserApp: BrowserApp, transport?: ConnectionTransport }> {
|
||||||
const {
|
const {
|
||||||
ignoreDefaultArgs = false,
|
ignoreDefaultArgs = false,
|
||||||
args = [],
|
args = [],
|
||||||
dumpio = false,
|
dumpio = false,
|
||||||
executablePath = null,
|
executablePath = null,
|
||||||
webSocket = false,
|
|
||||||
env = process.env,
|
env = process.env,
|
||||||
handleSIGINT = true,
|
handleSIGINT = true,
|
||||||
handleSIGTERM = true,
|
handleSIGTERM = true,
|
||||||
handleSIGHUP = true,
|
handleSIGHUP = true,
|
||||||
slowMo = 0,
|
|
||||||
timeout = 30000
|
timeout = 30000
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
|
|
@ -81,7 +85,7 @@ export class Chromium implements BrowserType {
|
||||||
let temporaryUserDataDir: string | null = null;
|
let temporaryUserDataDir: string | null = null;
|
||||||
|
|
||||||
if (!chromeArguments.some(argument => argument.startsWith('--remote-debugging-')))
|
if (!chromeArguments.some(argument => argument.startsWith('--remote-debugging-')))
|
||||||
chromeArguments.push(webSocket ? '--remote-debugging-port=0' : '--remote-debugging-pipe');
|
chromeArguments.push(isServer ? '--remote-debugging-port=0' : '--remote-debugging-pipe');
|
||||||
if (!chromeArguments.some(arg => arg.startsWith('--user-data-dir'))) {
|
if (!chromeArguments.some(arg => arg.startsWith('--user-data-dir'))) {
|
||||||
temporaryUserDataDir = await mkdtempAsync(CHROMIUM_PROFILE_PATH);
|
temporaryUserDataDir = await mkdtempAsync(CHROMIUM_PROFILE_PATH);
|
||||||
chromeArguments.push(`--user-data-dir=${temporaryUserDataDir}`);
|
chromeArguments.push(`--user-data-dir=${temporaryUserDataDir}`);
|
||||||
|
|
@ -96,8 +100,8 @@ export class Chromium implements BrowserType {
|
||||||
}
|
}
|
||||||
|
|
||||||
const usePipe = chromeArguments.includes('--remote-debugging-pipe');
|
const usePipe = chromeArguments.includes('--remote-debugging-pipe');
|
||||||
if (usePipe && webSocket)
|
if (usePipe && isServer)
|
||||||
throw new Error(`Argument "--remote-debugging-pipe" is not compatible with "webSocket" launch option.`);
|
throw new Error(`Argument "--remote-debugging-pipe" is not compatible with the launchBrowserApp.`);
|
||||||
|
|
||||||
let browserApp: BrowserApp | undefined = undefined;
|
let browserApp: BrowserApp | undefined = undefined;
|
||||||
const { launchedProcess, gracefullyClose } = await launchProcess({
|
const { launchedProcess, gracefullyClose } = await launchProcess({
|
||||||
|
|
@ -116,9 +120,9 @@ export class Chromium implements BrowserType {
|
||||||
// We try to gracefully close to prevent crash reporting and core dumps.
|
// We try to gracefully close to prevent crash reporting and core dumps.
|
||||||
// Note that it's fine to reuse the pipe transport, since
|
// Note that it's fine to reuse the pipe transport, since
|
||||||
// our connection ignores kBrowserCloseMessageId.
|
// our connection ignores kBrowserCloseMessageId.
|
||||||
const transport = await createTransport(browserApp.connectOptions());
|
const t = transport || await platform.createWebSocketTransport(browserWSEndpoint!);
|
||||||
const message = { method: 'Browser.close', id: kBrowserCloseMessageId };
|
const message = { method: 'Browser.close', id: kBrowserCloseMessageId };
|
||||||
transport.send(JSON.stringify(message));
|
t.send(JSON.stringify(message));
|
||||||
},
|
},
|
||||||
onkill: (exitCode, signal) => {
|
onkill: (exitCode, signal) => {
|
||||||
if (browserApp)
|
if (browserApp)
|
||||||
|
|
@ -126,37 +130,23 @@ export class Chromium implements BrowserType {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let connectOptions: ConnectOptions;
|
let transport: ConnectionTransport | undefined;
|
||||||
if (!usePipe) {
|
let browserWSEndpoint: string | null;
|
||||||
|
if (isServer) {
|
||||||
const timeoutError = new TimeoutError(`Timed out after ${timeout} ms while trying to connect to Chromium! The only Chromium revision guaranteed to work is r${this._revision}`);
|
const timeoutError = new TimeoutError(`Timed out after ${timeout} ms while trying to connect to Chromium! The only Chromium revision guaranteed to work is r${this._revision}`);
|
||||||
const match = await waitForLine(launchedProcess, launchedProcess.stderr, /^DevTools listening on (ws:\/\/.*)$/, timeout, timeoutError);
|
const match = await waitForLine(launchedProcess, launchedProcess.stderr, /^DevTools listening on (ws:\/\/.*)$/, timeout, timeoutError);
|
||||||
const browserWSEndpoint = match[1];
|
browserWSEndpoint = match[1];
|
||||||
connectOptions = { browserWSEndpoint, slowMo };
|
|
||||||
} else {
|
} else {
|
||||||
const transport = new PipeTransport(launchedProcess.stdio[3] as NodeJS.WritableStream, launchedProcess.stdio[4] as NodeJS.ReadableStream);
|
transport = new PipeTransport(launchedProcess.stdio[3] as NodeJS.WritableStream, launchedProcess.stdio[4] as NodeJS.ReadableStream);
|
||||||
connectOptions = { slowMo, transport };
|
browserWSEndpoint = null;
|
||||||
}
|
}
|
||||||
browserApp = new BrowserApp(launchedProcess, gracefullyClose, connectOptions);
|
browserApp = new BrowserApp(launchedProcess, gracefullyClose, browserWSEndpoint);
|
||||||
return browserApp;
|
return { browserApp, transport };
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect(options: ConnectOptions & { browserURL?: string }): Promise<CRBrowser> {
|
async connect(options: ConnectOptions): Promise<CRBrowser> {
|
||||||
if (options.transport && options.transport.onmessage)
|
const transport = await platform.createWebSocketTransport(options.wsEndpoint);
|
||||||
throw new Error('Transport is already in use');
|
return CRBrowser.connect(transport, options.slowMo);
|
||||||
if (options.browserURL) {
|
|
||||||
assert(!options.browserWSEndpoint && !options.transport, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to connect');
|
|
||||||
let connectionURL: string;
|
|
||||||
try {
|
|
||||||
const data = await platform.fetchUrl(new URL('/json/version', options.browserURL).href);
|
|
||||||
connectionURL = JSON.parse(data).webSocketDebuggerUrl;
|
|
||||||
} catch (e) {
|
|
||||||
e.message = `Failed to fetch browser webSocket url from ${options.browserURL}: ` + e.message;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
const transport = await platform.createWebSocketTransport(connectionURL);
|
|
||||||
options = { ...options, transport };
|
|
||||||
}
|
|
||||||
return CRBrowser.connect(options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
executablePath(): string {
|
executablePath(): string {
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,10 @@ import * as util from 'util';
|
||||||
import { TimeoutError } from '../errors';
|
import { TimeoutError } from '../errors';
|
||||||
import { assert } from '../helper';
|
import { assert } from '../helper';
|
||||||
import { LaunchOptions, BrowserArgOptions, BrowserType } from './browserType';
|
import { LaunchOptions, BrowserArgOptions, BrowserType } from './browserType';
|
||||||
import { createTransport, ConnectOptions } from '../browser';
|
import { ConnectOptions } from '../browser';
|
||||||
import { BrowserApp } from './browserApp';
|
import { BrowserApp } from './browserApp';
|
||||||
import { Events } from '../events';
|
import { Events } from '../events';
|
||||||
|
import { ConnectionTransport } from '../transport';
|
||||||
|
|
||||||
export class Firefox implements BrowserType {
|
export class Firefox implements BrowserType {
|
||||||
private _projectRoot: string;
|
private _projectRoot: string;
|
||||||
|
|
@ -46,15 +47,20 @@ export class Firefox implements BrowserType {
|
||||||
return 'firefox';
|
return 'firefox';
|
||||||
}
|
}
|
||||||
|
|
||||||
async launch(options?: LaunchOptions): Promise<FFBrowser> {
|
async launch(options?: LaunchOptions & { slowMo?: number }): Promise<FFBrowser> {
|
||||||
const app = await this.launchBrowserApp(options);
|
const { browserApp, transport } = await this._launchBrowserApp(options, false);
|
||||||
const browser = await FFBrowser.connect(app.connectOptions());
|
const browser = await FFBrowser.connect(transport!, options && options.slowMo);
|
||||||
// Hack: for typical launch scenario, ensure that close waits for actual process termination.
|
// Hack: for typical launch scenario, ensure that close waits for actual process termination.
|
||||||
browser.close = () => app.close();
|
browser.close = () => browserApp.close();
|
||||||
|
(browser as any)['__app__'] = browserApp;
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
async launchBrowserApp(options: LaunchOptions = {}): Promise<BrowserApp> {
|
async launchBrowserApp(options?: LaunchOptions): Promise<BrowserApp> {
|
||||||
|
return (await this._launchBrowserApp(options, true)).browserApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _launchBrowserApp(options: LaunchOptions = {}, isServer: boolean): Promise<{ browserApp: BrowserApp, transport?: ConnectionTransport }> {
|
||||||
const {
|
const {
|
||||||
ignoreDefaultArgs = false,
|
ignoreDefaultArgs = false,
|
||||||
args = [],
|
args = [],
|
||||||
|
|
@ -64,9 +70,7 @@ export class Firefox implements BrowserType {
|
||||||
handleSIGHUP = true,
|
handleSIGHUP = true,
|
||||||
handleSIGINT = true,
|
handleSIGINT = true,
|
||||||
handleSIGTERM = true,
|
handleSIGTERM = true,
|
||||||
slowMo = 0,
|
|
||||||
timeout = 30000,
|
timeout = 30000,
|
||||||
webSocket = false,
|
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const firefoxArguments = [];
|
const firefoxArguments = [];
|
||||||
|
|
@ -115,7 +119,7 @@ export class Firefox implements BrowserType {
|
||||||
// We try to gracefully close to prevent crash reporting and core dumps.
|
// We try to gracefully close to prevent crash reporting and core dumps.
|
||||||
// Note that it's fine to reuse the pipe transport, since
|
// Note that it's fine to reuse the pipe transport, since
|
||||||
// our connection ignores kBrowserCloseMessageId.
|
// our connection ignores kBrowserCloseMessageId.
|
||||||
const transport = await createTransport(browserApp.connectOptions());
|
const transport = await platform.createWebSocketTransport(browserWSEndpoint);
|
||||||
const message = { method: 'Browser.close', params: {}, id: kBrowserCloseMessageId };
|
const message = { method: 'Browser.close', params: {}, id: kBrowserCloseMessageId };
|
||||||
transport.send(JSON.stringify(message));
|
transport.send(JSON.stringify(message));
|
||||||
},
|
},
|
||||||
|
|
@ -128,23 +132,13 @@ export class Firefox implements BrowserType {
|
||||||
const timeoutError = new TimeoutError(`Timed out after ${timeout} ms while trying to connect to Firefox!`);
|
const timeoutError = new TimeoutError(`Timed out after ${timeout} ms while trying to connect to Firefox!`);
|
||||||
const match = await waitForLine(launchedProcess, launchedProcess.stdout, /^Juggler listening on (ws:\/\/.*)$/, timeout, timeoutError);
|
const match = await waitForLine(launchedProcess, launchedProcess.stdout, /^Juggler listening on (ws:\/\/.*)$/, timeout, timeoutError);
|
||||||
const browserWSEndpoint = match[1];
|
const browserWSEndpoint = match[1];
|
||||||
let connectOptions: ConnectOptions;
|
browserApp = new BrowserApp(launchedProcess, gracefullyClose, isServer ? browserWSEndpoint : null);
|
||||||
if (webSocket) {
|
return { browserApp, transport: isServer ? undefined : await platform.createWebSocketTransport(browserWSEndpoint) };
|
||||||
connectOptions = { browserWSEndpoint, slowMo };
|
|
||||||
} else {
|
|
||||||
const transport = await platform.createWebSocketTransport(browserWSEndpoint);
|
|
||||||
connectOptions = { transport, slowMo };
|
|
||||||
}
|
|
||||||
browserApp = new BrowserApp(launchedProcess, gracefullyClose, connectOptions);
|
|
||||||
return browserApp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect(options: ConnectOptions & { browserURL?: string }): Promise<FFBrowser> {
|
async connect(options: ConnectOptions): Promise<FFBrowser> {
|
||||||
if (options.browserURL)
|
const transport = await platform.createWebSocketTransport(options.wsEndpoint);
|
||||||
throw new Error('Option "browserURL" is not supported by Firefox');
|
return FFBrowser.connect(transport, options.slowMo);
|
||||||
if (options.transport && options.transport.onmessage)
|
|
||||||
throw new Error('Transport is already in use');
|
|
||||||
return FFBrowser.connect(options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
executablePath(): string {
|
executablePath(): string {
|
||||||
|
|
|
||||||
|
|
@ -51,15 +51,20 @@ export class WebKit implements BrowserType {
|
||||||
return 'webkit';
|
return 'webkit';
|
||||||
}
|
}
|
||||||
|
|
||||||
async launch(options?: LaunchOptions): Promise<WKBrowser> {
|
async launch(options?: LaunchOptions & { slowMo?: number }): Promise<WKBrowser> {
|
||||||
const app = await this.launchBrowserApp(options);
|
const { browserApp, transport } = await this._launchBrowserApp(options, false);
|
||||||
const browser = await WKBrowser.connect(app.connectOptions());
|
const browser = await WKBrowser.connect(transport!, options && options.slowMo);
|
||||||
// Hack: for typical launch scenario, ensure that close waits for actual process termination.
|
// Hack: for typical launch scenario, ensure that close waits for actual process termination.
|
||||||
browser.close = () => app.close();
|
browser.close = () => browserApp.close();
|
||||||
|
(browser as any)['__app__'] = browserApp;
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
async launchBrowserApp(options: LaunchOptions = {}): Promise<BrowserApp> {
|
async launchBrowserApp(options?: LaunchOptions): Promise<BrowserApp> {
|
||||||
|
return (await this._launchBrowserApp(options, true)).browserApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _launchBrowserApp(options: LaunchOptions = {}, isServer: boolean): Promise<{ browserApp: BrowserApp, transport?: ConnectionTransport }> {
|
||||||
const {
|
const {
|
||||||
ignoreDefaultArgs = false,
|
ignoreDefaultArgs = false,
|
||||||
args = [],
|
args = [],
|
||||||
|
|
@ -69,8 +74,6 @@ export class WebKit implements BrowserType {
|
||||||
handleSIGINT = true,
|
handleSIGINT = true,
|
||||||
handleSIGTERM = true,
|
handleSIGTERM = true,
|
||||||
handleSIGHUP = true,
|
handleSIGHUP = true,
|
||||||
slowMo = 0,
|
|
||||||
webSocket = false,
|
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const webkitArguments = [];
|
const webkitArguments = [];
|
||||||
|
|
@ -128,24 +131,13 @@ export class WebKit implements BrowserType {
|
||||||
});
|
});
|
||||||
|
|
||||||
transport = new PipeTransport(launchedProcess.stdio[3] as NodeJS.WritableStream, launchedProcess.stdio[4] as NodeJS.ReadableStream);
|
transport = new PipeTransport(launchedProcess.stdio[3] as NodeJS.WritableStream, launchedProcess.stdio[4] as NodeJS.ReadableStream);
|
||||||
|
browserApp = new BrowserApp(launchedProcess, gracefullyClose, isServer ? wrapTransportWithWebSocket(transport) : null);
|
||||||
let connectOptions: ConnectOptions;
|
return { browserApp, transport };
|
||||||
if (webSocket) {
|
|
||||||
const browserWSEndpoint = wrapTransportWithWebSocket(transport);
|
|
||||||
connectOptions = { browserWSEndpoint, slowMo };
|
|
||||||
} else {
|
|
||||||
connectOptions = { transport, slowMo };
|
|
||||||
}
|
|
||||||
browserApp = new BrowserApp(launchedProcess, gracefullyClose, connectOptions);
|
|
||||||
return browserApp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect(options: ConnectOptions & { browserURL?: string }): Promise<WKBrowser> {
|
async connect(options: ConnectOptions): Promise<WKBrowser> {
|
||||||
if (options.browserURL)
|
const transport = await platform.createWebSocketTransport(options.wsEndpoint);
|
||||||
throw new Error('Option "browserURL" is not supported by Firefox');
|
return WKBrowser.connect(transport, options.slowMo);
|
||||||
if (options.transport && options.transport.onmessage)
|
|
||||||
throw new Error('Transport is already in use');
|
|
||||||
return WKBrowser.connect(options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
executablePath(): string {
|
executablePath(): string {
|
||||||
|
|
|
||||||
22
src/web.ts
22
src/web.ts
|
|
@ -17,10 +17,26 @@
|
||||||
import { CRBrowser as ChromiumBrowser } from './chromium/crBrowser';
|
import { CRBrowser as ChromiumBrowser } from './chromium/crBrowser';
|
||||||
import { FFBrowser as FirefoxBrowser } from './firefox/ffBrowser';
|
import { FFBrowser as FirefoxBrowser } from './firefox/ffBrowser';
|
||||||
import { WKBrowser as WebKitBrowser } from './webkit/wkBrowser';
|
import { WKBrowser as WebKitBrowser } from './webkit/wkBrowser';
|
||||||
|
import * as platform from './platform';
|
||||||
|
|
||||||
const connect = {
|
const connect = {
|
||||||
chromium: { connect: ChromiumBrowser.connect },
|
chromium: {
|
||||||
firefox: { connect: FirefoxBrowser.connect },
|
connect: async (url: string) => {
|
||||||
webkit: { connect: WebKitBrowser.connect },
|
const transport = await platform.createWebSocketTransport(url);
|
||||||
|
return ChromiumBrowser.connect(transport);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
webkit: {
|
||||||
|
connect: async (url: string) => {
|
||||||
|
const transport = await platform.createWebSocketTransport(url);
|
||||||
|
return WebKitBrowser.connect(transport);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
firefox: {
|
||||||
|
connect: async (url: string) => {
|
||||||
|
const transport = await platform.createWebSocketTransport(url);
|
||||||
|
return FirefoxBrowser.connect(transport);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
export = connect;
|
export = connect;
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,12 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Browser, createTransport, ConnectOptions } from '../browser';
|
import { Browser } from '../browser';
|
||||||
import { BrowserContext, BrowserContextOptions } from '../browserContext';
|
import { BrowserContext, BrowserContextOptions } from '../browserContext';
|
||||||
import { assert, helper, RegisteredListener } from '../helper';
|
import { assert, helper, RegisteredListener } from '../helper';
|
||||||
import * as network from '../network';
|
import * as network from '../network';
|
||||||
import { Page } from '../page';
|
import { Page } from '../page';
|
||||||
import { ConnectionTransport } from '../transport';
|
import { ConnectionTransport, SlowMoTransport } from '../transport';
|
||||||
import * as types from '../types';
|
import * as types from '../types';
|
||||||
import { Events } from '../events';
|
import { Events } from '../events';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
|
|
@ -41,9 +41,8 @@ export class WKBrowser extends platform.EventEmitter implements Browser {
|
||||||
private _firstPageProxyCallback?: () => void;
|
private _firstPageProxyCallback?: () => void;
|
||||||
private readonly _firstPageProxyPromise: Promise<void>;
|
private readonly _firstPageProxyPromise: Promise<void>;
|
||||||
|
|
||||||
static async connect(options: ConnectOptions): Promise<WKBrowser> {
|
static async connect(transport: ConnectionTransport, slowMo: number = 0): Promise<WKBrowser> {
|
||||||
const transport = await createTransport(options);
|
const browser = new WKBrowser(SlowMoTransport.wrap(transport, slowMo));
|
||||||
const browser = new WKBrowser(transport);
|
|
||||||
// TODO: figure out the timeout.
|
// TODO: figure out the timeout.
|
||||||
await browser._waitForFirstPageTarget(30000);
|
await browser._waitForFirstPageTarget(30000);
|
||||||
return browser;
|
return browser;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script src='../../web.js'></script>
|
<script src='../../web.js'></script>
|
||||||
<script>
|
<script>
|
||||||
async function setup(product, connectOptions) {
|
async function setup(product, wsEndpoint) {
|
||||||
window.browser = await window.playwrightweb[product].connect(connectOptions);
|
window.browser = await window.playwrightweb[product].connect(wsEndpoint);
|
||||||
window.context = await window.browser.newContext();
|
window.context = await window.browser.newContext();
|
||||||
window.page = await window.context.newPage();
|
window.page = await window.context.newPage();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,76 +31,23 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||||
|
|
||||||
describe('CrPlaywright', function() {
|
describe('CrPlaywright', function() {
|
||||||
describe('Playwright.launch |browserURL| option', function() {
|
|
||||||
function getBrowserUrl(wsEndpoint) {
|
|
||||||
const port = wsEndpoint.match(/ws:\/\/([0-9A-Za-z\.]*):(\d+)\//)[2];
|
|
||||||
return `http://127.0.0.1:${port}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should be able to connect using browserUrl, with and without trailing slash', async({server}) => {
|
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
|
||||||
const browserURL = getBrowserUrl(browserApp.wsEndpoint());
|
|
||||||
|
|
||||||
const browser1 = await playwright.connect({browserURL});
|
|
||||||
const page1 = await browser1.defaultContext().newPage();
|
|
||||||
expect(await page1.evaluate(() => 7 * 8)).toBe(56);
|
|
||||||
browser1.disconnect();
|
|
||||||
|
|
||||||
const browser2 = await playwright.connect({browserURL: browserURL + '/'});
|
|
||||||
const page2 = await browser2.defaultContext().newPage();
|
|
||||||
expect(await page2.evaluate(() => 8 * 7)).toBe(56);
|
|
||||||
browser2.disconnect();
|
|
||||||
await browserApp.close();
|
|
||||||
});
|
|
||||||
it('should throw when using both browserWSEndpoint and browserURL', async({server}) => {
|
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
|
||||||
const browserURL = getBrowserUrl(browserApp.wsEndpoint());
|
|
||||||
|
|
||||||
let error = null;
|
|
||||||
await playwright.connect({browserURL, browserWSEndpoint: browserApp.wsEndpoint()}).catch(e => error = e);
|
|
||||||
expect(error.message).toContain('Exactly one of browserWSEndpoint, browserURL or transport');
|
|
||||||
|
|
||||||
await browserApp.close();
|
|
||||||
});
|
|
||||||
it('should throw when trying to connect to non-existing browser', async({server}) => {
|
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
|
||||||
const browserURL = getBrowserUrl(browserApp.wsEndpoint());
|
|
||||||
|
|
||||||
let error = null;
|
|
||||||
await playwright.connect({browserURL: browserURL + 'foo'}).catch(e => error = e);
|
|
||||||
expect(error.message).toContain('Failed to fetch browser webSocket url from');
|
|
||||||
await browserApp.close();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Playwright.launch webSocket option', function() {
|
describe('Playwright.launch webSocket option', function() {
|
||||||
it('should support the remote-debugging-port argument', async() => {
|
it('should support the remote-debugging-port argument', async() => {
|
||||||
const options = Object.assign({}, defaultBrowserOptions);
|
const options = Object.assign({}, defaultBrowserOptions);
|
||||||
options.args = ['--remote-debugging-port=0'].concat(options.args || []);
|
options.args = ['--remote-debugging-port=0'].concat(options.args || []);
|
||||||
const browserApp = await playwright.launchBrowserApp(options);
|
const browserApp = await playwright.launchBrowserApp(options);
|
||||||
const browser = await playwright.connect(browserApp.connectOptions());
|
const browser = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
expect(browserApp.wsEndpoint()).not.toBe(null);
|
expect(browserApp.wsEndpoint()).not.toBe(null);
|
||||||
const page = await browser.defaultContext().newPage();
|
const page = await browser.defaultContext().newPage();
|
||||||
expect(await page.evaluate('11 * 11')).toBe(121);
|
expect(await page.evaluate('11 * 11')).toBe(121);
|
||||||
await page.close();
|
await page.close();
|
||||||
await browserApp.close();
|
await browserApp.close();
|
||||||
});
|
});
|
||||||
it('should support the remote-debugging-pipe argument', async() => {
|
it('should throw with remote-debugging-pipe argument and webSocket', async() => {
|
||||||
const options = Object.assign({}, defaultBrowserOptions);
|
const options = Object.assign({}, defaultBrowserOptions);
|
||||||
options.args = ['--remote-debugging-pipe'].concat(options.args || []);
|
options.args = ['--remote-debugging-pipe'].concat(options.args || []);
|
||||||
const browserApp = await playwright.launchBrowserApp(options);
|
|
||||||
const browser = await playwright.connect(browserApp.connectOptions());
|
|
||||||
expect(browserApp.wsEndpoint()).toBe(null);
|
|
||||||
const page = await browser.defaultContext().newPage();
|
|
||||||
expect(await page.evaluate('11 * 11')).toBe(121);
|
|
||||||
await page.close();
|
|
||||||
await browserApp.close();
|
|
||||||
});
|
|
||||||
it('should throw with remote-debugging-pipe argument and webSocket', async() => {
|
|
||||||
const options = Object.assign({webSocket: true}, defaultBrowserOptions);
|
|
||||||
options.args = ['--remote-debugging-pipe'].concat(options.args || []);
|
|
||||||
const error = await playwright.launchBrowserApp(options).catch(e => e);
|
const error = await playwright.launchBrowserApp(options).catch(e => e);
|
||||||
expect(error.message).toBe('Argument "--remote-debugging-pipe" is not compatible with "webSocket" launch option.');
|
expect(error.message).toBe('Argument "--remote-debugging-pipe" is not compatible with the launchBrowserApp.');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ module.exports.describe = function({testRunner, expect, product, playwright, pla
|
||||||
const options = Object.assign({}, defaultBrowserOptions, {
|
const options = Object.assign({}, defaultBrowserOptions, {
|
||||||
// Disable DUMPIO to cleanly read stdout.
|
// Disable DUMPIO to cleanly read stdout.
|
||||||
dumpio: false,
|
dumpio: false,
|
||||||
webSocket: true,
|
|
||||||
handleSIGINT: true,
|
handleSIGINT: true,
|
||||||
handleSIGTERM: true,
|
handleSIGTERM: true,
|
||||||
handleSIGHUP: true,
|
handleSIGHUP: true,
|
||||||
|
|
@ -56,7 +55,7 @@ module.exports.describe = function({testRunner, expect, product, playwright, pla
|
||||||
browserPid = +match[1];
|
browserPid = +match[1];
|
||||||
});
|
});
|
||||||
res.on('error', (...args) => console.log("ERROR", ...args));
|
res.on('error', (...args) => console.log("ERROR", ...args));
|
||||||
const browser = await playwright.connect({ browserWSEndpoint: await wsEndPointPromise });
|
const browser = await playwright.connect({ wsEndpoint: await wsEndPointPromise });
|
||||||
const promises = [
|
const promises = [
|
||||||
new Promise(resolve => browser.once('disconnected', resolve)),
|
new Promise(resolve => browser.once('disconnected', resolve)),
|
||||||
new Promise(resolve => res.on('exit', resolve)),
|
new Promise(resolve => res.on('exit', resolve)),
|
||||||
|
|
|
||||||
|
|
@ -132,16 +132,16 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
|
|
||||||
describe('Browser.isConnected', () => {
|
describe('Browser.isConnected', () => {
|
||||||
it('should set the browser connected state', async () => {
|
it('should set the browser connected state', async () => {
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions });
|
||||||
const remote = await playwright.connect({browserWSEndpoint: browserApp.wsEndpoint()});
|
const remote = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
expect(remote.isConnected()).toBe(true);
|
expect(remote.isConnected()).toBe(true);
|
||||||
await remote.disconnect();
|
await remote.disconnect();
|
||||||
expect(remote.isConnected()).toBe(false);
|
expect(remote.isConnected()).toBe(false);
|
||||||
await browserApp.close();
|
await browserApp.close();
|
||||||
});
|
});
|
||||||
it('should throw when used after isConnected returns false', async({server}) => {
|
it('should throw when used after isConnected returns false', async({server}) => {
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions });
|
||||||
const remote = await playwright.connect(browserApp.connectOptions());
|
const remote = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const page = await remote.defaultContext().newPage();
|
const page = await remote.defaultContext().newPage();
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
browserApp.close(),
|
browserApp.close(),
|
||||||
|
|
@ -156,8 +156,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
describe('Browser.disconnect', function() {
|
describe('Browser.disconnect', function() {
|
||||||
it('should reject navigation when browser closes', async({server}) => {
|
it('should reject navigation when browser closes', async({server}) => {
|
||||||
server.setRoute('/one-style.css', () => {});
|
server.setRoute('/one-style.css', () => {});
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions });
|
||||||
const remote = await playwright.connect(browserApp.connectOptions());
|
const remote = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const page = await remote.defaultContext().newPage();
|
const page = await remote.defaultContext().newPage();
|
||||||
const navigationPromise = page.goto(server.PREFIX + '/one-style.html', {timeout: 60000}).catch(e => e);
|
const navigationPromise = page.goto(server.PREFIX + '/one-style.html', {timeout: 60000}).catch(e => e);
|
||||||
await server.waitForRequest('/one-style.css');
|
await server.waitForRequest('/one-style.css');
|
||||||
|
|
@ -168,8 +168,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
});
|
});
|
||||||
it('should reject waitForSelector when browser closes', async({server}) => {
|
it('should reject waitForSelector when browser closes', async({server}) => {
|
||||||
server.setRoute('/empty.html', () => {});
|
server.setRoute('/empty.html', () => {});
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions });
|
||||||
const remote = await playwright.connect(browserApp.connectOptions());
|
const remote = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const page = await remote.defaultContext().newPage();
|
const page = await remote.defaultContext().newPage();
|
||||||
const watchdog = page.waitForSelector('div', { timeout: 60000 }).catch(e => e);
|
const watchdog = page.waitForSelector('div', { timeout: 60000 }).catch(e => e);
|
||||||
|
|
||||||
|
|
@ -182,8 +182,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
await browserApp.close();
|
await browserApp.close();
|
||||||
});
|
});
|
||||||
it('should throw if used after disconnect', async({server}) => {
|
it('should throw if used after disconnect', async({server}) => {
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions });
|
||||||
const remote = await playwright.connect(browserApp.connectOptions());
|
const remote = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const page = await remote.defaultContext().newPage();
|
const page = await remote.defaultContext().newPage();
|
||||||
await remote.disconnect();
|
await remote.disconnect();
|
||||||
const error = await page.evaluate('1 + 1').catch(e => e);
|
const error = await page.evaluate('1 + 1').catch(e => e);
|
||||||
|
|
@ -194,8 +194,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
|
|
||||||
describe('Browser.close', function() {
|
describe('Browser.close', function() {
|
||||||
it('should terminate network waiters', async({context, server}) => {
|
it('should terminate network waiters', async({context, server}) => {
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions });
|
||||||
const remote = await playwright.connect(browserApp.connectOptions());
|
const remote = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const newPage = await remote.defaultContext().newPage();
|
const newPage = await remote.defaultContext().newPage();
|
||||||
const results = await Promise.all([
|
const results = await Promise.all([
|
||||||
newPage.waitForRequest(server.EMPTY_PAGE).catch(e => e),
|
newPage.waitForRequest(server.EMPTY_PAGE).catch(e => e),
|
||||||
|
|
@ -209,8 +209,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
it('should be able to close remote browser', async({server}) => {
|
it('should be able to close remote browser', async({server}) => {
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions });
|
||||||
const remote = await playwright.connect(browserApp.connectOptions());
|
const remote = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
new Promise(f => browserApp.once('close', f)),
|
new Promise(f => browserApp.once('close', f)),
|
||||||
remote.close(),
|
remote.close(),
|
||||||
|
|
@ -219,20 +219,10 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Playwright.launch |webSocket| option', function() {
|
describe('Playwright.launch |webSocket| option', function() {
|
||||||
it('should not have websocket by default', async() => {
|
|
||||||
const browserApp = await playwright.launchBrowserApp(defaultBrowserOptions);
|
|
||||||
const browser = await playwright.connect(browserApp.connectOptions());
|
|
||||||
expect((await browser.defaultContext().pages()).length).toBe(1);
|
|
||||||
expect(browserApp.wsEndpoint()).toBe(null);
|
|
||||||
const page = await browser.defaultContext().newPage();
|
|
||||||
expect(await page.evaluate('11 * 11')).toBe(121);
|
|
||||||
await page.close();
|
|
||||||
await browserApp.close();
|
|
||||||
});
|
|
||||||
it('should support the webSocket option', async() => {
|
it('should support the webSocket option', async() => {
|
||||||
const options = Object.assign({webSocket: true}, defaultBrowserOptions);
|
const options = Object.assign({}, defaultBrowserOptions);
|
||||||
const browserApp = await playwright.launchBrowserApp(options);
|
const browserApp = await playwright.launchBrowserApp(options);
|
||||||
const browser = await playwright.connect(browserApp.connectOptions());
|
const browser = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
expect((await browser.defaultContext().pages()).length).toBe(1);
|
expect((await browser.defaultContext().pages()).length).toBe(1);
|
||||||
expect(browserApp.wsEndpoint()).not.toBe(null);
|
expect(browserApp.wsEndpoint()).not.toBe(null);
|
||||||
const page = await browser.defaultContext().newPage();
|
const page = await browser.defaultContext().newPage();
|
||||||
|
|
@ -240,17 +230,10 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
await page.close();
|
await page.close();
|
||||||
await browserApp.close();
|
await browserApp.close();
|
||||||
});
|
});
|
||||||
it('should fire "disconnected" when closing without webSocket', async() => {
|
|
||||||
const browserApp = await playwright.launchBrowserApp(defaultBrowserOptions);
|
|
||||||
const browser = await playwright.connect(browserApp.connectOptions());
|
|
||||||
const disconnectedEventPromise = new Promise(resolve => browser.once('disconnected', resolve));
|
|
||||||
browserApp.kill();
|
|
||||||
await disconnectedEventPromise;
|
|
||||||
});
|
|
||||||
it('should fire "disconnected" when closing with webSocket', async() => {
|
it('should fire "disconnected" when closing with webSocket', async() => {
|
||||||
const options = Object.assign({webSocket: true}, defaultBrowserOptions);
|
const options = Object.assign({}, defaultBrowserOptions);
|
||||||
const browserApp = await playwright.launchBrowserApp(options);
|
const browserApp = await playwright.launchBrowserApp(options);
|
||||||
const browser = await playwright.connect(browserApp.connectOptions());
|
const browser = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const disconnectedEventPromise = new Promise(resolve => browser.once('disconnected', resolve));
|
const disconnectedEventPromise = new Promise(resolve => browser.once('disconnected', resolve));
|
||||||
browserApp.kill();
|
browserApp.kill();
|
||||||
await disconnectedEventPromise;
|
await disconnectedEventPromise;
|
||||||
|
|
@ -259,13 +242,13 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
|
|
||||||
describe('Playwright.connect', function() {
|
describe('Playwright.connect', function() {
|
||||||
it.skip(WEBKIT)('should be able to reconnect to a browser', async({server}) => {
|
it.skip(WEBKIT)('should be able to reconnect to a browser', async({server}) => {
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions });
|
||||||
const browser = await playwright.connect(browserApp.connectOptions());
|
const browser = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const page = await browser.defaultContext().newPage();
|
const page = await browser.defaultContext().newPage();
|
||||||
await page.goto(server.PREFIX + '/frames/nested-frames.html');
|
await page.goto(server.PREFIX + '/frames/nested-frames.html');
|
||||||
await browser.disconnect();
|
await browser.disconnect();
|
||||||
|
|
||||||
const remote = await playwright.connect(browserApp.connectOptions());
|
const remote = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const pages = await remote.defaultContext().pages();
|
const pages = await remote.defaultContext().pages();
|
||||||
const restoredPage = pages.find(page => page.url() === server.PREFIX + '/frames/nested-frames.html');
|
const restoredPage = pages.find(page => page.url() === server.PREFIX + '/frames/nested-frames.html');
|
||||||
expect(utils.dumpFrames(restoredPage.mainFrame())).toEqual([
|
expect(utils.dumpFrames(restoredPage.mainFrame())).toEqual([
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,12 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
|
|
||||||
describe('BrowserContext', function() {
|
describe('BrowserContext', function() {
|
||||||
it('should work across sessions', async () => {
|
it('should work across sessions', async () => {
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions });
|
||||||
const browser = await playwright.connect(browserApp.connectOptions());
|
const browser = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
expect(browser.browserContexts().length).toBe(1);
|
expect(browser.browserContexts().length).toBe(1);
|
||||||
await browser.newContext();
|
await browser.newContext();
|
||||||
expect(browser.browserContexts().length).toBe(2);
|
expect(browser.browserContexts().length).toBe(2);
|
||||||
const remoteBrowser = await playwright.connect(browserApp.connectOptions());
|
const remoteBrowser = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const contexts = remoteBrowser.browserContexts();
|
const contexts = remoteBrowser.browserContexts();
|
||||||
expect(contexts.length).toBe(2);
|
expect(contexts.length).toBe(2);
|
||||||
await browserApp.close();
|
await browserApp.close();
|
||||||
|
|
@ -37,12 +37,12 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Browser.Events.disconnected', function() {
|
describe('Browser.Events.disconnected', function() {
|
||||||
it('should be emitted when: browser gets closed, disconnected or underlying websocket gets closed', async() => {
|
it('should be emitted when: browser gets closed, disconnected or underlying websocket gets closed', async () => {
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({ ...defaultBrowserOptions });
|
||||||
const originalBrowser = await playwright.connect(browserApp.connectOptions());
|
const originalBrowser = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const browserWSEndpoint = browserApp.wsEndpoint();
|
const wsEndpoint = browserApp.wsEndpoint();
|
||||||
const remoteBrowser1 = await playwright.connect({browserWSEndpoint});
|
const remoteBrowser1 = await playwright.connect({ wsEndpoint });
|
||||||
const remoteBrowser2 = await playwright.connect({browserWSEndpoint});
|
const remoteBrowser2 = await playwright.connect({ wsEndpoint });
|
||||||
|
|
||||||
let disconnectedOriginal = 0;
|
let disconnectedOriginal = 0;
|
||||||
let disconnectedRemote1 = 0;
|
let disconnectedRemote1 = 0;
|
||||||
|
|
@ -74,9 +74,9 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
|
|
||||||
describe('Playwright.connect', function() {
|
describe('Playwright.connect', function() {
|
||||||
it('should be able to connect multiple times to the same browser', async({server}) => {
|
it('should be able to connect multiple times to the same browser', async({server}) => {
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions });
|
||||||
const local = await playwright.connect(browserApp.connectOptions());
|
const local = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const remote = await playwright.connect(browserApp.connectOptions());
|
const remote = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const page = await remote.defaultContext().newPage();
|
const page = await remote.defaultContext().newPage();
|
||||||
expect(await page.evaluate(() => 7 * 8)).toBe(56);
|
expect(await page.evaluate(() => 7 * 8)).toBe(56);
|
||||||
remote.disconnect();
|
remote.disconnect();
|
||||||
|
|
@ -85,21 +85,10 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
expect(await secondPage.evaluate(() => 7 * 6)).toBe(42, 'original browser should still work');
|
expect(await secondPage.evaluate(() => 7 * 6)).toBe(42, 'original browser should still work');
|
||||||
await browserApp.close();
|
await browserApp.close();
|
||||||
});
|
});
|
||||||
it('should not be able to connect multiple times without websocket', async({server}) => {
|
|
||||||
const browserApp = await playwright.launchBrowserApp(defaultBrowserOptions);
|
|
||||||
const connectOptions = browserApp.connectOptions();
|
|
||||||
expect(connectOptions.transport).toBeTruthy();
|
|
||||||
expect(browserApp.wsEndpoint()).toBe(null);
|
|
||||||
expect(connectOptions.browserWSEndpoint).toBe(undefined);
|
|
||||||
const local = await playwright.connect(connectOptions);
|
|
||||||
const error = await playwright.connect(connectOptions).catch(e => e);
|
|
||||||
expect(error.message).toBe('Transport is already in use');
|
|
||||||
await browserApp.close();
|
|
||||||
});
|
|
||||||
it('should be able to close remote browser', async({server}) => {
|
it('should be able to close remote browser', async({server}) => {
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions });
|
||||||
const local = await playwright.connect(browserApp.connectOptions());
|
const local = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const remote = await playwright.connect(browserApp.connectOptions());
|
const remote = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
utils.waitEvent(local, 'disconnected'),
|
utils.waitEvent(local, 'disconnected'),
|
||||||
remote.close(),
|
remote.close(),
|
||||||
|
|
@ -107,11 +96,11 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
});
|
});
|
||||||
// @see https://github.com/GoogleChrome/puppeteer/issues/4197#issuecomment-481793410
|
// @see https://github.com/GoogleChrome/puppeteer/issues/4197#issuecomment-481793410
|
||||||
it('should be able to connect to the same page simultaneously', async({server}) => {
|
it('should be able to connect to the same page simultaneously', async({server}) => {
|
||||||
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({...defaultBrowserOptions });
|
||||||
const browser1 = await playwright.connect(browserApp.connectOptions());
|
const browser1 = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const page1 = await browser1.defaultContext().newPage();
|
const page1 = await browser1.defaultContext().newPage();
|
||||||
await page1.goto(server.EMPTY_PAGE);
|
await page1.goto(server.EMPTY_PAGE);
|
||||||
const browser2 = await playwright.connect(browserApp.connectOptions());
|
const browser2 = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const page2 = (await browser2.defaultContext().pages()).find(page => page.url() === server.EMPTY_PAGE);
|
const page2 = (await browser2.defaultContext().pages()).find(page => page.url() === server.EMPTY_PAGE);
|
||||||
expect(await page1.evaluate(() => 7 * 8)).toBe(56);
|
expect(await page1.evaluate(() => 7 * 8)).toBe(56);
|
||||||
expect(await page2.evaluate(() => 7 * 6)).toBe(42);
|
expect(await page2.evaluate(() => 7 * 6)).toBe(42);
|
||||||
|
|
|
||||||
|
|
@ -92,8 +92,8 @@ module.exports.describe = ({testRunner, product, playwrightPath}) => {
|
||||||
|
|
||||||
describe('Browser', function() {
|
describe('Browser', function() {
|
||||||
beforeAll(async state => {
|
beforeAll(async state => {
|
||||||
state.browserApp = await playwright.launchBrowserApp(defaultBrowserOptions);
|
state.browser = await playwright.launch();
|
||||||
state.browser = await playwright.connect(state.browserApp.connectOptions());
|
state.browserApp = state.browser.__app__;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async state => {
|
afterAll(async state => {
|
||||||
|
|
|
||||||
|
|
@ -21,15 +21,13 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
|
|
||||||
(CHROMIUM || FFOX) && describe('Web SDK', function() {
|
(CHROMIUM || FFOX) && describe('Web SDK', function() {
|
||||||
beforeAll(async state => {
|
beforeAll(async state => {
|
||||||
state.controlledBrowserApp = await playwright.launchBrowserApp({ ...defaultBrowserOptions, webSocket: true });
|
state.controlledBrowserApp = await playwright.launchBrowserApp(defaultBrowserOptions);
|
||||||
state.hostBrowserApp = await playwright.launchBrowserApp(defaultBrowserOptions);
|
state.hostBrowser = await playwright.launch(defaultBrowserOptions);
|
||||||
state.hostBrowser = await playwright.connect(state.hostBrowserApp.connectOptions());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async state => {
|
afterAll(async state => {
|
||||||
await state.hostBrowserApp.close();
|
await state.hostBrowser.close();
|
||||||
state.hostBrowser = null;
|
state.hostBrowser = null;
|
||||||
state.hostBrowserApp = null;
|
|
||||||
|
|
||||||
await state.controlledBrowserApp.close();
|
await state.controlledBrowserApp.close();
|
||||||
state.controlledBrowserApp = null;
|
state.controlledBrowserApp = null;
|
||||||
|
|
@ -40,7 +38,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
state.page = await state.hostBrowser.defaultContext().newPage();
|
state.page = await state.hostBrowser.defaultContext().newPage();
|
||||||
state.page.on('console', message => console.log('TEST: ' + message.text()));
|
state.page.on('console', message => console.log('TEST: ' + message.text()));
|
||||||
await state.page.goto(state.sourceServer.PREFIX + '/test/assets/playwrightweb.html');
|
await state.page.goto(state.sourceServer.PREFIX + '/test/assets/playwrightweb.html');
|
||||||
await state.page.evaluate((product, connectOptions) => setup(product, connectOptions), product.toLowerCase(), state.controlledBrowserApp.connectOptions());
|
await state.page.evaluate((product, wsEndpoint) => setup(product, wsEndpoint), product.toLowerCase(), state.controlledBrowserApp.wsEndpoint());
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async state => {
|
afterEach(async state => {
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ async function generateChromiunProtocol(revision) {
|
||||||
if (revision.local && fs.existsSync(outputPath))
|
if (revision.local && fs.existsSync(outputPath))
|
||||||
return;
|
return;
|
||||||
const playwright = await require('../../index').chromium;
|
const playwright = await require('../../index').chromium;
|
||||||
const browserApp = await playwright.launchBrowserApp({executablePath: revision.executablePath, webSocket: true});
|
const browserApp = await playwright.launchBrowserApp({ executablePath: revision.executablePath });
|
||||||
const origin = browserApp.wsEndpoint().match(/ws:\/\/([0-9A-Za-z:\.]*)\//)[1];
|
const origin = browserApp.wsEndpoint().match(/ws:\/\/([0-9A-Za-z:\.]*)\//)[1];
|
||||||
const browser = await playwright.connect(browserApp.connectOptions());
|
const browser = await playwright.connect({ wsEndpoint: browserApp.wsEndpoint() });
|
||||||
const page = await browser.defaultContext().newPage();
|
const page = await browser.defaultContext().newPage();
|
||||||
await page.goto(`http://${origin}/json/protocol`);
|
await page.goto(`http://${origin}/json/protocol`);
|
||||||
const json = JSON.parse(await page.evaluate(() => document.documentElement.innerText));
|
const json = JSON.parse(await page.evaluate(() => document.documentElement.innerText));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue