diff --git a/packages/playwright-core/src/grid/gridAgent.ts b/packages/playwright-core/src/grid/gridAgent.ts index b40cdf4198..a9daa422d7 100644 --- a/packages/playwright-core/src/grid/gridAgent.ts +++ b/packages/playwright-core/src/grid/gridAgent.ts @@ -30,16 +30,16 @@ export function launchGridAgent(agentId: string, gridURL: string, runId: string const ws = new WebSocket(gridURL.replace('http://', 'ws://') + `/registerAgent?` + params.toString()); ws.on('message', (message: string) => { log('worker requested ' + message); - const { workerId, browserAlias } = JSON.parse(message); + const { workerId, browserName } = JSON.parse(message); if (!workerId) { log('workerId not specified'); return; } - if (!browserAlias) { - log('browserAlias not specified'); + if (!browserName) { + log('browserName not specified'); return; } - fork(require.resolve('./gridBrowserWorker.js'), [gridURL, agentId, workerId, browserAlias], { detached: true }); + fork(require.resolve('./gridBrowserWorker.js'), [gridURL, agentId, workerId, browserName], { detached: true }); }); ws.on('close', () => process.exit(0)); } diff --git a/packages/playwright-core/src/grid/gridBrowserWorker.ts b/packages/playwright-core/src/grid/gridBrowserWorker.ts index a49ce27d03..725fdb8822 100644 --- a/packages/playwright-core/src/grid/gridBrowserWorker.ts +++ b/packages/playwright-core/src/grid/gridBrowserWorker.ts @@ -19,11 +19,11 @@ import { ws as WebSocket } from '../utilsBundle'; import { PlaywrightConnection } from '../remote/playwrightConnection'; import { gracefullyCloseAll } from '../utils/processLauncher'; -function launchGridBrowserWorker(gridURL: string, agentId: string, workerId: string, browserAlias: string) { +function launchGridBrowserWorker(gridURL: string, agentId: string, workerId: string, browserName: string) { const log = debug(`pw:grid:worker:${workerId}`); log('created'); const ws = new WebSocket(gridURL.replace('http://', 'ws://') + `/registerWorker?agentId=${agentId}&workerId=${workerId}`); - new PlaywrightConnection(Promise.resolve(), 'auto', ws, { enableSocksProxy: true, browserAlias, launchOptions: {} }, { playwright: null, browser: null }, log, async () => { + new PlaywrightConnection(Promise.resolve(), 'auto', ws, { enableSocksProxy: true, browserName, launchOptions: {} }, { playwright: null, browser: null }, log, async () => { log('exiting process'); setTimeout(() => process.exit(0), 30000); // Meanwhile, try to gracefully close all browsers. diff --git a/packages/playwright-core/src/grid/gridServer.ts b/packages/playwright-core/src/grid/gridServer.ts index f6ffd7f34e..2b99c6bedc 100644 --- a/packages/playwright-core/src/grid/gridServer.ts +++ b/packages/playwright-core/src/grid/gridServer.ts @@ -64,8 +64,7 @@ const WSErrors = { type GridWorkerParams = { - browserAlias?: string; - headless?: boolean; + browserName?: string; }; class GridWorker extends EventEmitter { @@ -284,8 +283,7 @@ export class GridServer { } agent.createWorker(ws, { - browserAlias: request.headers['x-playwright-browser'] as string | undefined, - headless: request.headers['x-playwright-headless'] !== '0', + browserName: request.headers['x-playwright-browser'] as string, }); return; } diff --git a/packages/playwright-core/src/remote/playwrightConnection.ts b/packages/playwright-core/src/remote/playwrightConnection.ts index 352101ed75..afa84413e4 100644 --- a/packages/playwright-core/src/remote/playwrightConnection.ts +++ b/packages/playwright-core/src/remote/playwrightConnection.ts @@ -15,12 +15,11 @@ */ import type { WebSocket } from '../utilsBundle'; -import type { Playwright, DispatcherScope, Executable } from '../server'; +import type { Playwright, DispatcherScope } from '../server'; import { createPlaywright, DispatcherConnection, Root, PlaywrightDispatcher } from '../server'; import { Browser } from '../server/browser'; import { serverSideCallMetadata } from '../server/instrumentation'; import { gracefullyCloseAll } from '../utils/processLauncher'; -import { registry } from '../server'; import { SocksProxy } from '../common/socksProxy'; import type { Mode } from './playwrightServer'; import { assert } from '../utils'; @@ -28,7 +27,7 @@ import type { LaunchOptions } from '../server/types'; type Options = { enableSocksProxy: boolean, - browserAlias: string | null, + browserName: string | null, launchOptions: LaunchOptions, }; @@ -78,7 +77,7 @@ export class PlaywrightConnection { return await this._initReuseBrowsersMode(scope); if (mode === 'use-pre-launched-browser') return await this._initPreLaunchedBrowserMode(scope); - if (!options.browserAlias) + if (!options.browserName) return await this._initPlaywrightConnectMode(scope); return await this._initLaunchBrowserMode(scope); }); @@ -95,15 +94,11 @@ export class PlaywrightConnection { } private async _initLaunchBrowserMode(scope: DispatcherScope) { - this._debugLog(`engaged launch mode for "${this._options.browserAlias}"`); - const executable = this._executableForBrowerAlias(this._options.browserAlias!); + this._debugLog(`engaged launch mode for "${this._options.browserName}"`); const playwright = createPlaywright('javascript'); const socksProxy = this._options.enableSocksProxy ? await this._enableSocksProxy(playwright) : undefined; - const browser = await playwright[executable.browserName!].launch(serverSideCallMetadata(), { - channel: executable.type === 'browser' ? undefined : executable.name, - headless: this._options.launchOptions?.headless, - }); + const browser = await playwright[this._options.browserName as 'chromium'].launch(serverSideCallMetadata(), this._options.launchOptions); // Close the browser on disconnect. // TODO: it is technically possible to launch more browsers over protocol. @@ -132,20 +127,26 @@ export class PlaywrightConnection { } private async _initReuseBrowsersMode(scope: DispatcherScope) { - this._debugLog(`engaged reuse browsers mode for ${this._options.browserAlias}`); - const executable = this._executableForBrowerAlias(this._options.browserAlias!); + this._debugLog(`engaged reuse browsers mode for ${this._options.browserName}`); const playwright = this._preLaunched.playwright!; const requestedOptions = launchOptionsHash(this._options.launchOptions); let browser = playwright.allBrowsers().find(b => { + if (b.options.name !== this._options.browserName) + return false; const existingOptions = launchOptionsHash(b.options.originalLaunchOptions); return existingOptions === requestedOptions; }); - const remaining = playwright.allBrowsers().filter(b => b !== browser); - for (const r of remaining) - await r.close(); + + // Close remaining browsers of this type+channel. Keep different browser types for the speed. + for (const b of playwright.allBrowsers()) { + if (b === browser) + continue; + if (b.options.name === this._options.browserName && b.options.channel === this._options.launchOptions.channel) + await b.close(); + } if (!browser) { - browser = await playwright[executable.browserName!].launch(serverSideCallMetadata(), { + browser = await playwright[this._options.browserName as 'chromium'].launch(serverSideCallMetadata(), { ...this._options.launchOptions, headless: false, }); @@ -187,13 +188,6 @@ export class PlaywrightConnection { } catch (e) { } } - - private _executableForBrowerAlias(browserAlias: string): Executable { - const executable = registry.findExecutable(browserAlias); - if (!executable || !executable.browserName) - throw new Error(`Unsupported browser "${browserAlias}`); - return executable; - } } function launchOptionsHash(options: LaunchOptions) { diff --git a/packages/playwright-core/src/remote/playwrightServer.ts b/packages/playwright-core/src/remote/playwrightServer.ts index 091ee3de04..2155a0cdd7 100644 --- a/packages/playwright-core/src/remote/playwrightServer.ts +++ b/packages/playwright-core/src/remote/playwrightServer.ts @@ -120,7 +120,7 @@ export class PlaywrightServer { } const url = new URL('http://localhost' + (request.url || '')); const browserHeader = request.headers['x-playwright-browser']; - const browserAlias = url.searchParams.get('browser') || (Array.isArray(browserHeader) ? browserHeader[0] : browserHeader) || null; + const browserName = url.searchParams.get('browser') || (Array.isArray(browserHeader) ? browserHeader[0] : browserHeader) || null; const proxyHeader = request.headers['x-playwright-proxy']; const proxyValue = url.searchParams.get('proxy') || (Array.isArray(proxyHeader) ? proxyHeader[0] : proxyHeader); const enableSocksProxy = this._options.enableSocksProxy && proxyValue === '*'; @@ -132,17 +132,12 @@ export class PlaywrightServer { } catch (e) { } - const headlessHeader = request.headers['x-playwright-headless']; - const headlessValue = url.searchParams.get('headless') || (Array.isArray(headlessHeader) ? headlessHeader[0] : headlessHeader); - if (headlessValue && headlessValue !== '0') - launchOptions.headless = true; - const log = newLogger(); log(`serving connection: ${request.url}`); const connection = new PlaywrightConnection( semaphore.aquire(), this._mode, ws, - { enableSocksProxy, browserAlias, launchOptions }, + { enableSocksProxy, browserName, launchOptions }, { playwright: this._preLaunchedPlaywright, browser: this._options.preLaunchedBrowser || null }, log, () => semaphore.release()); (ws as any)[kConnectionSymbol] = connection; diff --git a/packages/playwright-test/src/index.ts b/packages/playwright-test/src/index.ts index c45bcf121b..dd8d7f8c84 100644 --- a/packages/playwright-test/src/index.ts +++ b/packages/playwright-test/src/index.ts @@ -115,8 +115,7 @@ export const test = _baseTest.extend({ throw new Error(`Unexpected browserName "${browserName}", must be one of "chromium", "firefox" or "webkit"`); const browser = await playwright[browserName].connect(connectOptions.wsEndpoint, { headers: { - 'x-playwright-browser': channel || browserName, - 'x-playwright-headless': headless ? '1' : '0', + 'x-playwright-browser': browserName, 'x-playwright-launch-options': JSON.stringify(launchOptions), ...connectOptions.headers, }, diff --git a/tests/library/port-forwarding-server.spec.ts b/tests/library/port-forwarding-server.spec.ts index 9ae7fcc503..43dfd2789b 100644 --- a/tests/library/port-forwarding-server.spec.ts +++ b/tests/library/port-forwarding-server.spec.ts @@ -66,7 +66,8 @@ const it = contextTest.extend<{ pageFactory: (redirectPortForTest?: number) => P const server = new OutOfProcessPlaywrightServer(0, 3200 + testInfo.workerIndex); playwrightServers.push(server); const browser = await browserType.connect({ - wsEndpoint: await server.wsEndpoint() + '?proxy=*&browser=' + (channel || browserName), + wsEndpoint: await server.wsEndpoint() + '?proxy=*&browser=' + browserName, + headers: { 'x-playwright-launch-options': JSON.stringify({ channel }) }, __testHookRedirectPortForwarding: redirectPortForTest, } as any); browsers.push(browser);