Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions packages/playwright-core/src/androidServerImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { PlaywrightServer } from './remote/playwrightServer';
import { createPlaywright } from './server/playwright';
import { createGuid } from './server/utils/crypto';
import { ws } from './utilsBundle';
import { ProgressController } from './server/progress';
import { serverSideCallMetadata } from './server';

import type { BrowserServer } from './client/browserType';
import type { LaunchAndroidServerOptions } from './client/types';
Expand All @@ -27,11 +29,12 @@ export class AndroidServerLauncherImpl {
async launchServer(options: LaunchAndroidServerOptions = {}): Promise<BrowserServer> {
const playwright = createPlaywright({ sdkLanguage: 'javascript', isServer: true });
// 1. Pre-connect to the device
let devices = await playwright.android.devices({
const controller = new ProgressController(serverSideCallMetadata(), playwright);
let devices = await controller.run(progress => playwright.android.devices(progress, {
host: options.adbHost,
port: options.adbPort,
omitDriverInstall: options.omitDriverInstall,
});
}));

if (devices.length === 0)
throw new Error('No devices found');
Expand Down
24 changes: 14 additions & 10 deletions packages/playwright-core/src/browserServerImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { rewriteErrorMessage } from './utils/isomorphic/stackTrace';
import { DEFAULT_PLAYWRIGHT_LAUNCH_TIMEOUT } from './utils/isomorphic/time';
import { ws } from './utilsBundle';
import * as validatorPrimitives from './protocol/validatorPrimitives';
import { ProgressController } from './server/progress';

import type { BrowserServer, BrowserServerLauncher } from './client/browserType';
import type { LaunchServerOptions, Logger, Env } from './client/types';
Expand Down Expand Up @@ -59,16 +60,19 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher {

let browser: Browser;
try {
if (options._userDataDir !== undefined) {
const validator = validatorPrimitives.scheme['BrowserTypeLaunchPersistentContextParams'];
launchOptions = validator({ ...launchOptions, userDataDir: options._userDataDir }, '', validatorContext);
const context = await playwright[this._browserName].launchPersistentContext(metadata, options._userDataDir, launchOptions);
browser = context._browser;
} else {
const validator = validatorPrimitives.scheme['BrowserTypeLaunchParams'];
launchOptions = validator(launchOptions, '', validatorContext);
browser = await playwright[this._browserName].launch(metadata, launchOptions, toProtocolLogger(options.logger));
}
const controller = new ProgressController(metadata, playwright[this._browserName]);
browser = await controller.run(async progress => {
if (options._userDataDir !== undefined) {
const validator = validatorPrimitives.scheme['BrowserTypeLaunchPersistentContextParams'];
launchOptions = validator({ ...launchOptions, userDataDir: options._userDataDir }, '', validatorContext);
const context = await playwright[this._browserName].launchPersistentContext(progress, options._userDataDir, launchOptions);
return context._browser;
} else {
const validator = validatorPrimitives.scheme['BrowserTypeLaunchParams'];
launchOptions = validator(launchOptions, '', validatorContext);
return await playwright[this._browserName].launch(progress, launchOptions, toProtocolLogger(options.logger));
}
});
} catch (e) {
const log = helper.formatBrowserLogs(metadata.log);
rewriteErrorMessage(e, `${e.message} Failed to launch browser.${log}`);
Expand Down
40 changes: 25 additions & 15 deletions packages/playwright-core/src/remote/playwrightServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ import { debugLogger, isUnderTest } from '../utils';
import { serverSideCallMetadata } from '../server';
import { SocksProxy } from '../server/utils/socksProxy';
import { Browser } from '../server/browser';
import { ProgressController } from '../server/progress';

import type { AndroidDevice } from '../server/android/android';
import type { Playwright } from '../server/playwright';
import type { LaunchOptions } from '../server/types';
import type { LaunchOptions as LaunchOptionsWithoutTimeout } from '../server/types';

type LaunchOptionsWithTimeout = LaunchOptionsWithoutTimeout & { timeout: number };

type ServerOptions = {
path: string;
Expand Down Expand Up @@ -93,9 +95,11 @@ export class PlaywrightServer {
const launchOptionsHeader = request.headers['x-playwright-launch-options'] || '';
const launchOptionsHeaderValue = Array.isArray(launchOptionsHeader) ? launchOptionsHeader[0] : launchOptionsHeader;
const launchOptionsParam = url.searchParams.get('launch-options');
let launchOptions: LaunchOptions = { timeout: DEFAULT_PLAYWRIGHT_LAUNCH_TIMEOUT };
let launchOptions: LaunchOptionsWithTimeout = { timeout: DEFAULT_PLAYWRIGHT_LAUNCH_TIMEOUT };
try {
launchOptions = JSON.parse(launchOptionsParam || launchOptionsHeaderValue);
if (!launchOptions.timeout)
launchOptions.timeout = DEFAULT_PLAYWRIGHT_LAUNCH_TIMEOUT;
} catch (e) {
}

Expand Down Expand Up @@ -172,7 +176,7 @@ export class PlaywrightServer {
});
}

private async _initReuseBrowsersMode(browserName: string | null, launchOptions: LaunchOptions, id: string): Promise<PlaywrightInitializeResult> {
private async _initReuseBrowsersMode(browserName: string | null, launchOptions: LaunchOptionsWithTimeout, id: string): Promise<PlaywrightInitializeResult> {
// Note: reuse browser mode does not support socks proxy, because
// clients come and go, while the browser stays the same.

Expand All @@ -184,7 +188,7 @@ export class PlaywrightServer {
return false;
if (this._dontReuseBrowsers.has(b))
return false;
const existingOptions = launchOptionsHash(b.options.originalLaunchOptions);
const existingOptions = launchOptionsHash({ ...b.options.originalLaunchOptions, timeout: DEFAULT_PLAYWRIGHT_LAUNCH_TIMEOUT });
return existingOptions === requestedOptions;
});

Expand All @@ -199,10 +203,12 @@ export class PlaywrightServer {
}

if (!browser) {
browser = await this._playwright[(browserName || 'chromium') as 'chromium'].launch(serverSideCallMetadata(), {
const browserType = this._playwright[(browserName || 'chromium') as 'chromium'];
const controller = new ProgressController(serverSideCallMetadata(), browserType);
browser = await controller.run(progress => browserType.launch(progress, {
...launchOptions,
headless: !!process.env.PW_DEBUG_CONTROLLER_HEADLESS,
});
}), launchOptions.timeout);
}

return {
Expand All @@ -222,14 +228,16 @@ export class PlaywrightServer {
};
}

private async _initConnectMode(id: string, filter: 'first', browserName: string | null, launchOptions: LaunchOptions): Promise<PlaywrightInitializeResult> {
private async _initConnectMode(id: string, filter: 'first', browserName: string | null, launchOptions: LaunchOptionsWithTimeout): Promise<PlaywrightInitializeResult> {
browserName ??= 'chromium';

debugLogger.log('server', `[${id}] engaged connect mode`);

let browser = this._playwright.allBrowsers().find(b => b.options.name === browserName);
if (!browser) {
browser = await this._playwright[browserName as 'chromium'].launch(serverSideCallMetadata(), launchOptions);
const browserType = this._playwright[browserName as 'chromium'];
const controller = new ProgressController(serverSideCallMetadata(), browserType);
browser = await controller.run(progress => browserType.launch(progress, launchOptions), launchOptions.timeout);
this._dontReuse(browser);
}

Expand Down Expand Up @@ -268,7 +276,7 @@ export class PlaywrightServer {
};
}

private async _initLaunchBrowserMode(browserName: string | null, proxyValue: string | undefined, launchOptions: LaunchOptions, id: string): Promise<PlaywrightInitializeResult> {
private async _initLaunchBrowserMode(browserName: string | null, proxyValue: string | undefined, launchOptions: LaunchOptionsWithTimeout, id: string): Promise<PlaywrightInitializeResult> {
debugLogger.log('server', `[${id}] engaged launch mode for "${browserName}"`);
let socksProxy: SocksProxy | undefined;
if (proxyValue) {
Expand All @@ -279,7 +287,9 @@ export class PlaywrightServer {
} else {
launchOptions.socksProxyPort = undefined;
}
const browser = await this._playwright[browserName as 'chromium'].launch(serverSideCallMetadata(), launchOptions);
const browserType = this._playwright[browserName as 'chromium'];
const controller = new ProgressController(serverSideCallMetadata(), browserType);
const browser = await controller.run(progress => browserType.launch(progress, launchOptions), launchOptions.timeout);
this._dontReuseBrowsers.add(browser);
return {
preLaunchedBrowser: browser,
Expand Down Expand Up @@ -334,10 +344,10 @@ function userAgentVersionMatchesErrorMessage(userAgent: string) {
}
}

function launchOptionsHash(options: LaunchOptions) {
function launchOptionsHash(options: LaunchOptionsWithTimeout) {
const copy = { ...options };
for (const k of Object.keys(copy)) {
const key = k as keyof LaunchOptions;
const key = k as keyof LaunchOptionsWithTimeout;
if (copy[key] === defaultLaunchOptions[key])
delete copy[key];
}
Expand All @@ -346,7 +356,7 @@ function launchOptionsHash(options: LaunchOptions) {
return JSON.stringify(copy);
}

function filterLaunchOptions(options: LaunchOptions, allowFSPaths: boolean): LaunchOptions {
function filterLaunchOptions(options: LaunchOptionsWithTimeout, allowFSPaths: boolean): LaunchOptionsWithTimeout {
return {
channel: options.channel,
args: options.args,
Expand All @@ -363,7 +373,7 @@ function filterLaunchOptions(options: LaunchOptions, allowFSPaths: boolean): Lau
};
}

const defaultLaunchOptions: Partial<LaunchOptions> = {
const defaultLaunchOptions: Partial<LaunchOptionsWithTimeout> = {
ignoreAllDefaultArgs: false,
handleSIGINT: false,
handleSIGTERM: false,
Expand All @@ -372,7 +382,7 @@ const defaultLaunchOptions: Partial<LaunchOptions> = {
devtools: false,
};

const optionsThatAllowBrowserReuse: (keyof LaunchOptions)[] = [
const optionsThatAllowBrowserReuse: (keyof LaunchOptionsWithTimeout)[] = [
'headless',
'timeout',
'tracesDir',
Expand Down
Loading
Loading