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
16 changes: 0 additions & 16 deletions docs/src/api/class-browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]>
Expand Down Expand Up @@ -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]>
Expand Down
2 changes: 1 addition & 1 deletion docs/src/api/class-browsercontext.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]>

Expand Down
14 changes: 1 addition & 13 deletions packages/playwright-client/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -9761,12 +9761,6 @@ export interface Browser {
*/
behavior?: 'wait'|'ignoreErrors'|'default'
}): Promise<void>;

/**
* 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:
Expand Down Expand Up @@ -10415,12 +10409,6 @@ export interface Browser {
*/
stopTracing(): Promise<Buffer>;

/**
* 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.
*/
Expand Down
12 changes: 1 addition & 11 deletions packages/playwright-core/src/client/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> 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;
Expand Down Expand Up @@ -92,13 +91,12 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> 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);
Expand Down Expand Up @@ -153,14 +151,6 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
return this._isConnected;
}

launchOptions(): LaunchOptions {
return this._options;
}

userDataDir(): string | null {
return this._userDataDir ?? null;
}

async newBrowserCDPSession(): Promise<api.CDPSession> {
return CDPSession.from((await this._channel.newBrowserCDPSession()).session);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/playwright-core/src/client/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
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;
Expand Down Expand Up @@ -298,7 +298,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
return [...this._pages];
}

isClosedOrClosing(): boolean {
isClosed(): boolean {
return this._closingStatus !== 'none';
}

Expand Down Expand Up @@ -520,7 +520,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
}

async close(options: { reason?: string } = {}): Promise<void> {
if (this.isClosedOrClosing())
if (this.isClosed())
return;
this._closeReason = options.reason;
this._closingStatus = 'closing';
Expand Down
2 changes: 1 addition & 1 deletion packages/playwright-core/src/client/browserType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> 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;
Expand Down
2 changes: 1 addition & 1 deletion packages/playwright-core/src/client/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ export class Page extends ChannelOwner<channels.PageChannel> 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;
Expand Down
2 changes: 0 additions & 2 deletions packages/playwright-core/src/serverRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export type BrowserInfo = {

export type EndpointInfo = {
title: string;
wsEndpoint?: string;
pipeName?: string;
workspaceDir?: string;
metadata?: Record<string, any>;
Expand Down Expand Up @@ -94,7 +93,6 @@ class ServerRegistry {
playwrightLib: require.resolve('..'),
title: endpoint.title,
browser,
wsEndpoint: endpoint.wsEndpoint,
pipeName: endpoint.pipeName,
workspaceDir: endpoint.workspaceDir,
};
Expand Down
15 changes: 8 additions & 7 deletions packages/playwright-core/src/tools/cli-daemon/daemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand All @@ -53,14 +54,15 @@ async function socketExists(socketPath: string): Promise<boolean> {
export async function startCliDaemonServer(
sessionName: string,
browserContext: playwright.BrowserContext,
browserInfo: BrowserInfo,
contextConfig: ContextConfig = {},
clientInfo = createClientInfo(),
options?: {
persistent?: boolean,
exitOnClose?: boolean,
}
): Promise<string> {
const sessionConfig = createSessionConfig(clientInfo, sessionName, browserContext, options);
const sessionConfig = createSessionConfig(clientInfo, sessionName, browserInfo, options);
const { socketPath } = sessionConfig;

// Clean up existing socket file on Unix
Expand All @@ -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 => {
Expand Down Expand Up @@ -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,
Expand All @@ -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,
},
};
}
6 changes: 3 additions & 3 deletions packages/playwright-core/src/tools/cli-daemon/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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('<EOF>');
} catch (error) {
Expand Down
56 changes: 46 additions & 10 deletions packages/playwright-core/src/tools/mcp/browserFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,29 +35,55 @@ 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<playwright.Browser> {
const { browser } = await createBrowserWithInfo(config, clientInfo);
return browser;
}

export async function createBrowserWithInfo(config: FullConfig, clientInfo: ClientInfoEx): Promise<BrowserWithInfo> {
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 {
contexts(clientInfo: ClientInfo): Promise<playwright.BrowserContext[]>;
createContext(clientInfo: ClientInfo): Promise<playwright.BrowserContext>;
}

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<playwright.Browser> {
testDebug('create browser (isolated)');
await injectCdpPort(config.browser);
Expand Down Expand Up @@ -87,18 +113,28 @@ async function createCDPBrowser(config: FullConfig, clientInfo: ClientInfoEx): P
return browser;
}

async function createRemoteBrowser(config: FullConfig): Promise<playwright.Browser> {
async function createRemoteBrowser(config: FullConfig): Promise<BrowserWithInfo> {
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<playwright.Browser> {
Expand Down
14 changes: 1 addition & 13 deletions packages/playwright-core/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -9761,12 +9761,6 @@ export interface Browser {
*/
behavior?: 'wait'|'ignoreErrors'|'default'
}): Promise<void>;

/**
* 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:
Expand Down Expand Up @@ -10415,12 +10409,6 @@ export interface Browser {
*/
stopTracing(): Promise<Buffer>;

/**
* 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.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/playwright/src/mcp/test/browserBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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([
Expand Down
Loading
Loading