From e6bf21f0f5fcfc84a4acc3b001ce434eaa311302 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Wed, 4 Jun 2025 16:34:09 +0100 Subject: [PATCH] chore: launchServer() with userDataDir (#36185) --- .../playwright-core/src/browserServerImpl.ts | 18 ++++++++++++++---- tests/library/multiclient.spec.ts | 8 ++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/playwright-core/src/browserServerImpl.ts b/packages/playwright-core/src/browserServerImpl.ts index d8bcda0e79..927bb6d68d 100644 --- a/packages/playwright-core/src/browserServerImpl.ts +++ b/packages/playwright-core/src/browserServerImpl.ts @@ -28,6 +28,7 @@ import type { BrowserServer, BrowserServerLauncher } from './client/browserType' import type { LaunchServerOptions, Logger, Env } from './client/types'; import type { ProtocolLogger } from './server/types'; import type { WebSocketEventEmitter } from './utilsBundle'; +import type { Browser } from './server/browser'; export class BrowserServerLauncherImpl implements BrowserServerLauncher { private _browserName: 'chromium' | 'firefox' | 'webkit' | 'bidiFirefox' | 'bidiChromium'; @@ -36,7 +37,7 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher { this._browserName = browserName; } - async launchServer(options: LaunchServerOptions & { _sharedBrowser?: boolean } = {}): Promise { + async launchServer(options: LaunchServerOptions & { _sharedBrowser?: boolean, _userDataDir?: string } = {}): Promise { const playwright = createPlaywright({ sdkLanguage: 'javascript', isServer: true }); // TODO: enable socks proxy once ipv6 is supported. const socksProxy = false ? new SocksProxy() : undefined; @@ -44,17 +45,26 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher { // 1. Pre-launch the browser const metadata = serverSideCallMetadata(); - const browser = await playwright[this._browserName].launch(metadata, { + const launchOptions = { ...options, ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined, ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs), env: options.env ? envObjectToArray(options.env) : undefined, timeout: options.timeout ?? DEFAULT_PLAYWRIGHT_LAUNCH_TIMEOUT, - }, toProtocolLogger(options.logger)).catch(e => { + }; + let browser: Browser; + try { + if (options._userDataDir !== undefined) { + const context = await playwright[this._browserName].launchPersistentContext(metadata, options._userDataDir, launchOptions); + browser = context._browser; + } else { + browser = await playwright[this._browserName].launch(metadata, launchOptions, toProtocolLogger(options.logger)); + } + } catch (e) { const log = helper.formatBrowserLogs(metadata.log); rewriteErrorMessage(e, `${e.message} Failed to launch browser.${log}`); throw e; - }); + } const path = options.wsPath ? (options.wsPath.startsWith('/') ? options.wsPath : `/${options.wsPath}`) : `/${createGuid()}`; diff --git a/tests/library/multiclient.spec.ts b/tests/library/multiclient.spec.ts index 3b6180c5f7..c6a983c5d2 100644 --- a/tests/library/multiclient.spec.ts +++ b/tests/library/multiclient.spec.ts @@ -315,3 +315,11 @@ test('should remove locator handlers upon disconnect', async ({ twoPages, server expect(error.message).toContain('intercepts pointer events'); expect(error.message).not.toContain('locator handler'); }); + +test('should launch persistent', async ({ browserType }) => { + const browserServer = await browserType.launchServer({ _userDataDir: '', _sharedBrowser: true } as any); + const browser = await browserType.connect(browserServer.wsEndpoint()); + expect(browser.contexts().length).toBe(1); + await browser.close(); + await browserServer.close(); +});