From 241fd52ba47213b604a7cee3631f4f68d6cd5832 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Wed, 18 Mar 2026 11:35:24 -0700 Subject: [PATCH] chore(api): remove Browser.launchOptions/userDataDir, rename isClosedOrClosing to isClosed --- docs/src/api/class-browser.md | 16 ------ docs/src/api/class-browsercontext.md | 2 +- packages/playwright-client/types/types.d.ts | 14 +---- .../playwright-core/src/client/browser.ts | 12 +--- .../src/client/browserContext.ts | 6 +- .../playwright-core/src/client/browserType.ts | 2 +- packages/playwright-core/src/client/page.ts | 2 +- .../playwright-core/src/serverRegistry.ts | 2 - .../src/tools/cli-daemon/daemon.ts | 15 ++--- .../src/tools/cli-daemon/program.ts | 6 +- .../src/tools/mcp/browserFactory.ts | 56 +++++++++++++++---- packages/playwright-core/types/types.d.ts | 14 +---- .../playwright/src/mcp/test/browserBackend.ts | 2 +- tests/library/browser.spec.ts | 4 -- tests/mcp/cli-session.spec.ts | 4 +- utils/generate_types/overrides.d.ts | 2 - 16 files changed, 69 insertions(+), 90 deletions(-) diff --git a/docs/src/api/class-browser.md b/docs/src/api/class-browser.md index 21f89f40d266d..7867ce5c8ba71 100644 --- a/docs/src/api/class-browser.md +++ b/docs/src/api/class-browser.md @@ -158,14 +158,6 @@ System.Console.WriteLine(browser.Contexts.Count); // prints "1" Indicates that the browser is connected. -## method: Browser.launchOptions -* since: v1.59 -* langs: js -- returns: <[Object]> - -Returns the launch options that were used to launch this browser. The return type matches the options -accepted by [`method: BrowserType.launch`]. - ## async method: Browser.newBrowserCDPSession * since: v1.11 - returns: <[CDPSession]> @@ -390,14 +382,6 @@ This API controls [Chromium Tracing](https://www.chromium.org/developers/how-tos Returns the buffer with trace data. -## method: Browser.userDataDir -* since: v1.59 -* langs: js -- returns: <[null]|[string]> - -Returns the user data directory that the browser was launched with, or `null` if the browser was -launched without a persistent context. - ## method: Browser.version * since: v1.8 - returns: <[string]> diff --git a/docs/src/api/class-browsercontext.md b/docs/src/api/class-browsercontext.md index 806aaee33b283..e45950fe1bcec 100644 --- a/docs/src/api/class-browsercontext.md +++ b/docs/src/api/class-browsercontext.md @@ -975,7 +975,7 @@ Here are some permissions that may be supported by some browsers: The [origin] to grant permissions to, e.g. "https://example.com". -## method: BrowserContext.isClosedOrClosing +## method: BrowserContext.isClosed * since: v1.59 - returns: <[boolean]> diff --git a/packages/playwright-client/types/types.d.ts b/packages/playwright-client/types/types.d.ts index 98132f06fd933..5208c9f304467 100644 --- a/packages/playwright-client/types/types.d.ts +++ b/packages/playwright-client/types/types.d.ts @@ -9140,7 +9140,7 @@ export interface BrowserContext { /** * Indicates that the browser context is in the process of closing or has already been closed. */ - isClosedOrClosing(): boolean; + isClosed(): boolean; /** * **NOTE** CDP sessions are only supported on Chromium-based browsers. @@ -9761,12 +9761,6 @@ export interface Browser { */ behavior?: 'wait'|'ignoreErrors'|'default' }): Promise; - - /** - * Returns the launch options that were used to launch this browser. The return type matches the options accepted by - * [browserType.launch([options])](https://playwright.dev/docs/api/class-browsertype#browser-type-launch). - */ - launchOptions(): LaunchOptions; /** * Emitted when Browser gets disconnected from the browser application. This might happen because of one of the * following: @@ -10415,12 +10409,6 @@ export interface Browser { */ stopTracing(): Promise; - /** - * Returns the user data directory that the browser was launched with, or `null` if the browser was launched without a - * persistent context. - */ - userDataDir(): null|string; - /** * Returns the browser version. */ diff --git a/packages/playwright-core/src/client/browser.ts b/packages/playwright-core/src/client/browser.ts index 5390ba6143072..e14889a3b9d80 100644 --- a/packages/playwright-core/src/client/browser.ts +++ b/packages/playwright-core/src/client/browser.ts @@ -35,7 +35,6 @@ export class Browser extends ChannelOwner implements ap _shouldCloseConnectionOnClose = false; _browserType!: BrowserType; private _options: LaunchOptions = {}; - private _userDataDir: string | undefined; readonly _name: string; readonly _browserName: 'chromium' | 'webkit' | 'firefox'; private _path: string | undefined; @@ -92,13 +91,12 @@ export class Browser extends ChannelOwner implements ap return context; } - _connectToBrowserType(browserType: BrowserType, browserOptions: LaunchOptions, logger: Logger | undefined, userDataDir?: string) { + _connectToBrowserType(browserType: BrowserType, browserOptions: LaunchOptions, logger: Logger | undefined) { // Note: when using connect(), `browserType` is different from `this._parent`. // This is why browser type is not wired up in the constructor, // and instead this separate method is called later on. this._browserType = browserType; this._options = browserOptions; - this._userDataDir = userDataDir; this._logger = logger; for (const context of this._contexts) this._setupBrowserContext(context); @@ -153,14 +151,6 @@ export class Browser extends ChannelOwner implements ap return this._isConnected; } - launchOptions(): LaunchOptions { - return this._options; - } - - userDataDir(): string | null { - return this._userDataDir ?? null; - } - async newBrowserCDPSession(): Promise { return CDPSession.from((await this._channel.newBrowserCDPSession()).session); } diff --git a/packages/playwright-core/src/client/browserContext.ts b/packages/playwright-core/src/client/browserContext.ts index 7212dec579286..fc12a9e69b3bb 100644 --- a/packages/playwright-core/src/client/browserContext.ts +++ b/packages/playwright-core/src/client/browserContext.ts @@ -232,7 +232,7 @@ export class BrowserContext extends ChannelOwner const routeHandlers = this._routes.slice(); for (const routeHandler of routeHandlers) { // If the page or the context was closed we stall all requests right away. - if (page?._closeWasCalled || this.isClosedOrClosing()) + if (page?._closeWasCalled || this.isClosed()) return; if (!routeHandler.matches(route.request().url())) continue; @@ -298,7 +298,7 @@ export class BrowserContext extends ChannelOwner return [...this._pages]; } - isClosedOrClosing(): boolean { + isClosed(): boolean { return this._closingStatus !== 'none'; } @@ -520,7 +520,7 @@ export class BrowserContext extends ChannelOwner } async close(options: { reason?: string } = {}): Promise { - if (this.isClosedOrClosing()) + if (this.isClosed()) return; this._closeReason = options.reason; this._closingStatus = 'closing'; diff --git a/packages/playwright-core/src/client/browserType.ts b/packages/playwright-core/src/client/browserType.ts index 550518ba32109..e77b1d076e739 100644 --- a/packages/playwright-core/src/client/browserType.ts +++ b/packages/playwright-core/src/client/browserType.ts @@ -109,7 +109,7 @@ export class BrowserType extends ChannelOwner imple const context = await this._wrapApiCall(async () => { const result = await this._channel.launchPersistentContext(persistentParams); const browser = Browser.from(result.browser); - browser._connectToBrowserType(this, options, logger, userDataDir); + browser._connectToBrowserType(this, options, logger); const context = BrowserContext.from(result.context); await context._initializeHarFromOptions(options.recordHar); return context; diff --git a/packages/playwright-core/src/client/page.ts b/packages/playwright-core/src/client/page.ts index 3109aa8c5468e..bcebed4c159f8 100644 --- a/packages/playwright-core/src/client/page.ts +++ b/packages/playwright-core/src/client/page.ts @@ -191,7 +191,7 @@ export class Page extends ChannelOwner implements api.Page const routeHandlers = this._routes.slice(); for (const routeHandler of routeHandlers) { // If the page was closed we stall all requests right away. - if (this._closeWasCalled || this._browserContext.isClosedOrClosing()) + if (this._closeWasCalled || this._browserContext.isClosed()) return; if (!routeHandler.matches(route.request().url())) continue; diff --git a/packages/playwright-core/src/serverRegistry.ts b/packages/playwright-core/src/serverRegistry.ts index 1d01068390b18..f1c1172c20d01 100644 --- a/packages/playwright-core/src/serverRegistry.ts +++ b/packages/playwright-core/src/serverRegistry.ts @@ -33,7 +33,6 @@ export type BrowserInfo = { export type EndpointInfo = { title: string; - wsEndpoint?: string; pipeName?: string; workspaceDir?: string; metadata?: Record; @@ -94,7 +93,6 @@ class ServerRegistry { playwrightLib: require.resolve('..'), title: endpoint.title, browser, - wsEndpoint: endpoint.wsEndpoint, pipeName: endpoint.pipeName, workspaceDir: endpoint.workspaceDir, }; diff --git a/packages/playwright-core/src/tools/cli-daemon/daemon.ts b/packages/playwright-core/src/tools/cli-daemon/daemon.ts index 5cfe12bd89b48..60518b49bbf9c 100644 --- a/packages/playwright-core/src/tools/cli-daemon/daemon.ts +++ b/packages/playwright-core/src/tools/cli-daemon/daemon.ts @@ -37,6 +37,7 @@ import type * as playwright from '../../..'; import type { SessionConfig, ClientInfo } from '../cli-client/registry'; import type { CallToolRequest, CallToolResult } from '../backend/tool'; import type { ContextConfig } from '../backend/context'; +import type { BrowserInfo } from '../../serverRegistry'; const daemonDebug = debug('pw:daemon'); @@ -53,6 +54,7 @@ async function socketExists(socketPath: string): Promise { export async function startCliDaemonServer( sessionName: string, browserContext: playwright.BrowserContext, + browserInfo: BrowserInfo, contextConfig: ContextConfig = {}, clientInfo = createClientInfo(), options?: { @@ -60,7 +62,7 @@ export async function startCliDaemonServer( exitOnClose?: boolean, } ): Promise { - const sessionConfig = createSessionConfig(clientInfo, sessionName, browserContext, options); + const sessionConfig = createSessionConfig(clientInfo, sessionName, browserInfo, options); const { socketPath } = sessionConfig; // Clean up existing socket file on Unix @@ -79,7 +81,7 @@ export async function startCliDaemonServer( await fs.promises.mkdir(path.dirname(socketPath), { recursive: true }); - if (browserContext.isClosedOrClosing()) + if (browserContext.isClosed()) throw new Error('Browser context was closed before the daemon could start'); const server = net.createServer(socket => { @@ -172,11 +174,10 @@ function daemonSocketPath(clientInfo: ClientInfo, sessionName: string): string { return path.join(socketsDir, clientInfo.workspaceDirHash, socketName); } -function createSessionConfig(clientInfo: ClientInfo, sessionName: string, browserContext: playwright.BrowserContext, options: { +function createSessionConfig(clientInfo: ClientInfo, sessionName: string, browserInfo: BrowserInfo, options: { persistent?: boolean, exitOnStop?: boolean, } = {}): SessionConfig { - const browser = browserContext.browser()!; return { name: sessionName, version: clientInfo.version, @@ -185,9 +186,9 @@ function createSessionConfig(clientInfo: ClientInfo, sessionName: string, browse workspaceDir: clientInfo.workspaceDir, cli: { persistent: options.persistent }, browser: { - browserName: browser.browserType().name(), - launchOptions: browser.launchOptions(), - userDataDir: browser.userDataDir() ?? undefined, + browserName: browserInfo.browserName, + launchOptions: browserInfo.launchOptions, + userDataDir: browserInfo.userDataDir, }, }; } diff --git a/packages/playwright-core/src/tools/cli-daemon/program.ts b/packages/playwright-core/src/tools/cli-daemon/program.ts index b301cecf485d0..cbcd465e35e22 100644 --- a/packages/playwright-core/src/tools/cli-daemon/program.ts +++ b/packages/playwright-core/src/tools/cli-daemon/program.ts @@ -21,7 +21,7 @@ import path from 'path'; import { startCliDaemonServer } from './daemon'; import { setupExitWatchdog } from '../mcp/watchdog'; -import { createBrowser } from '../mcp/browserFactory'; +import { createBrowserWithInfo } from '../mcp/browserFactory'; import * as configUtils from '../mcp/config'; import { ClientInfo, createClientInfo } from '../cli-client/registry'; import { program } from '../../utilsBundle'; @@ -48,12 +48,12 @@ program.argument('[session-name]', 'name of the session to create or connect to' }; try { - const browser = await createBrowser(mcpConfig, clientInfoEx); + const { browser, browserInfo } = await createBrowserWithInfo(mcpConfig, clientInfoEx); const browserContext = mcpConfig.browser.isolated ? await browser.newContext(mcpConfig.browser.contextOptions) : browser.contexts()[0]; if (!browserContext) throw new Error('Error: unable to connect to a browser that does not have any contexts'); const persistent = options.persistent || options.profile || mcpConfig.browser.userDataDir ? true : undefined; - const socketPath = await startCliDaemonServer(sessionName, browserContext, mcpConfig, clientInfo, { persistent, exitOnClose: true }); + const socketPath = await startCliDaemonServer(sessionName, browserContext, browserInfo, mcpConfig, clientInfo, { persistent, exitOnClose: true }); console.log(`### Success\nDaemon listening on ${socketPath}`); console.log(''); } catch (error) { diff --git a/packages/playwright-core/src/tools/mcp/browserFactory.ts b/packages/playwright-core/src/tools/mcp/browserFactory.ts index 6b3f9b2c958dd..f1343536e447b 100644 --- a/packages/playwright-core/src/tools/mcp/browserFactory.ts +++ b/packages/playwright-core/src/tools/mcp/browserFactory.ts @@ -35,22 +35,38 @@ import type { ClientInfo } from '../utils/mcp/server'; import type { Playwright } from '../../client/playwright'; // eslint-disable-next-line no-restricted-imports import type { Browser } from '../../client/browser'; +import type { BrowserInfo } from '../../serverRegistry'; type ClientInfoEx = ClientInfo & { sessionName?: string; workspaceDir?: string; }; +type BrowserWithInfo = { + browser: playwright.Browser, + browserInfo: BrowserInfo +}; + export async function createBrowser(config: FullConfig, clientInfo: ClientInfoEx): Promise { + const { browser } = await createBrowserWithInfo(config, clientInfo); + return browser; +} + +export async function createBrowserWithInfo(config: FullConfig, clientInfo: ClientInfoEx): Promise { if (config.browser.remoteEndpoint) return await createRemoteBrowser(config); + + let browser: playwright.Browser; if (config.browser.cdpEndpoint) - return await createCDPBrowser(config, clientInfo); - if (config.browser.isolated) - return await createIsolatedBrowser(config, clientInfo); - if (config.extension) - return await createExtensionBrowser(config, clientInfo); - return await createPersistentBrowser(config, clientInfo); + browser = await createCDPBrowser(config, clientInfo); + else if (config.browser.isolated) + browser = await createIsolatedBrowser(config, clientInfo); + else if (config.extension) + browser = await createExtensionBrowser(config, clientInfo); + else + browser = await createPersistentBrowser(config, clientInfo); + + return { browser, browserInfo: browserInfo(browser, config) }; } export interface BrowserContextFactory { @@ -58,6 +74,16 @@ export interface BrowserContextFactory { createContext(clientInfo: ClientInfo): Promise; } +function browserInfo(browser: playwright.Browser, config: FullConfig): BrowserInfo { + return { + // eslint-disable-next-line no-restricted-syntax + guid: (browser as any)._guid, + browserName: config.browser.browserName, + launchOptions: config.browser.launchOptions, + userDataDir: config.browser.userDataDir + }; +} + async function createIsolatedBrowser(config: FullConfig, clientInfo: ClientInfoEx): Promise { testDebug('create browser (isolated)'); await injectCdpPort(config.browser); @@ -87,18 +113,28 @@ async function createCDPBrowser(config: FullConfig, clientInfo: ClientInfoEx): P return browser; } -async function createRemoteBrowser(config: FullConfig): Promise { +async function createRemoteBrowser(config: FullConfig): Promise { testDebug('create browser (remote)'); const descriptor = await serverRegistry.find(config.browser.remoteEndpoint!); - if (descriptor) - return await connectToBrowserAcrossVersions(descriptor); + if (descriptor) { + const browser = await connectToBrowserAcrossVersions(descriptor); + return { + browser, + browserInfo: { + guid: descriptor.browser.guid, + browserName: descriptor.browser.browserName, + launchOptions: descriptor.browser.launchOptions, + userDataDir: descriptor.browser.userDataDir + } + }; + } const endpoint = config.browser.remoteEndpoint!; const playwrightObject = playwright as Playwright; // Use connectToBrowser instead of playwright[browserName].connect because we don't have browserName. const browser = await connectToBrowser(playwrightObject, { endpoint }); browser._connectToBrowserType(playwrightObject[browser._browserName], {}, undefined); - return browser; + return { browser, browserInfo: browserInfo(browser, config) }; } async function createPersistentBrowser(config: FullConfig, clientInfo: ClientInfoEx): Promise { diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index 98132f06fd933..5208c9f304467 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -9140,7 +9140,7 @@ export interface BrowserContext { /** * Indicates that the browser context is in the process of closing or has already been closed. */ - isClosedOrClosing(): boolean; + isClosed(): boolean; /** * **NOTE** CDP sessions are only supported on Chromium-based browsers. @@ -9761,12 +9761,6 @@ export interface Browser { */ behavior?: 'wait'|'ignoreErrors'|'default' }): Promise; - - /** - * Returns the launch options that were used to launch this browser. The return type matches the options accepted by - * [browserType.launch([options])](https://playwright.dev/docs/api/class-browsertype#browser-type-launch). - */ - launchOptions(): LaunchOptions; /** * Emitted when Browser gets disconnected from the browser application. This might happen because of one of the * following: @@ -10415,12 +10409,6 @@ export interface Browser { */ stopTracing(): Promise; - /** - * Returns the user data directory that the browser was launched with, or `null` if the browser was launched without a - * persistent context. - */ - userDataDir(): null|string; - /** * Returns the browser version. */ diff --git a/packages/playwright/src/mcp/test/browserBackend.ts b/packages/playwright/src/mcp/test/browserBackend.ts index 0b3ac3718e31e..5239f204b5ba7 100644 --- a/packages/playwright/src/mcp/test/browserBackend.ts +++ b/packages/playwright/src/mcp/test/browserBackend.ts @@ -115,7 +115,7 @@ export async function runDaemonForContext(testInfo: TestInfoImpl, context: playw return false; const sessionName = `tw-${createGuid().slice(0, 6)}`; - await (context.browser() as Browser)._register(sessionName, { workspaceDir: testInfo.project.testDir }); + await (context.browser() as Browser)!._register(sessionName, { workspaceDir: testInfo.project.testDir }); /* eslint-disable-next-line no-console */ console.log([ diff --git a/tests/library/browser.spec.ts b/tests/library/browser.spec.ts index a2911f4ad65ef..19d47f871a4ea 100644 --- a/tests/library/browser.spec.ts +++ b/tests/library/browser.spec.ts @@ -51,10 +51,6 @@ test('version should work', async function({ browser, browserName }) { expect(version.match(/^\d+\.\d+/)).toBeTruthy(); }); -test('launchOptions() should work', async function({ browser, headless }) { - expect(!!browser.launchOptions().headless).toBe(!!headless); -}); - test('should dispatch page.on(close) upon browser.close and reject evaluate', async ({ browserType }) => { const browser = await browserType.launch(); const page = await browser.newPage(); diff --git a/tests/mcp/cli-session.spec.ts b/tests/mcp/cli-session.spec.ts index e5292fc48397c..11eca7547d5f4 100644 --- a/tests/mcp/cli-session.spec.ts +++ b/tests/mcp/cli-session.spec.ts @@ -314,7 +314,7 @@ workspace1: - status: open - browser-type: ${/* FIX browser._options */ mcpBrowser.replace('chrome', 'chromium')} - user-data-dir: - - headed: true`); + - headed: false`); }); test('fail to attach to browser server without contexts', async ({ cli, mcpBrowser }) => { @@ -342,7 +342,7 @@ workspace1: - status: open - browser-type: ${mcpBrowser.replace('chrome', 'chromium')} - user-data-dir: - - headed: true`); + - headed: false`); }); test('attach with session alias', async ({ cli, mcpBrowser }) => { diff --git a/utils/generate_types/overrides.d.ts b/utils/generate_types/overrides.d.ts index 35f10f96f5e8e..21bad32aa839b 100644 --- a/utils/generate_types/overrides.d.ts +++ b/utils/generate_types/overrides.d.ts @@ -148,8 +148,6 @@ export interface Browser { */ behavior?: 'wait'|'ignoreErrors'|'default' }): Promise; - - launchOptions(): LaunchOptions; } export interface Worker {