microsoft / playwright

Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://playwright.dev
Apache License 2.0
66.07k stars 3.61k forks source link

[Feature]: Expose `BrowserServer` contexts for hooking lifecycle methods #31220

Open mikestopcontinues opened 3 months ago

mikestopcontinues commented 3 months ago

🚀 Feature Request

export interface BrowserServer extends api.BrowserServer {
  // NEW METHODS
  serverContexts(): ServerBrowserContext[];
  newServerContext(options?: channels.BrowserNewContextParams): Promise<ServerBrowserContext>;

  process(): ChildProcess;
  wsEndpoint(): string;
  close(): Promise<void>;
  kill(): Promise<void>;
}

Per the recommendations in CONTRIBUTING.md, this is (roughly) the minimal surface area that will support the functionality described below. Many of the methods on ./server/browserContext.ts > BrowserContext can perhaps be hidden with a wrapper class.

Example

No response

Motivation

This will enable user's hosting Playwright browser servers to hook into the lifecycle of connected clients. Puppeteer supports this out-of-the-box because there is no difference between .launch() and .launchServer(). So you can currently hook the client in both libraries, but you cannot hook the server lifecycle in Playwright.

This reduces the usefulness of packages like playwright-extra, because the adjustments cannot be applied across all browsers connected to a server, but must be applied by clients. Hooking server methods would enable the following functionality:

I would be happy to provide a PR with some direction on the strategy you'd like to see employed.

yury-s commented 3 months ago

This will enable user's hosting Playwright browser servers to hook into the lifecycle of connected clients.

Can you elaborate on what kind of lifecycle events you want to hook into and why? Each client is supposed to work with their own instance(s) of the remote browser, so the existing API provides a way to launch the server and listen to when it's closed. Since the server controls access to the launch method and connected clients, these should be sufficient.

mikestopcontinues commented 3 months ago

I have a headless browser hosting company (BrowserCat), and I would like to offer built-in stealth mode and an adblocker, as my users have repeated requested them. This probably comes as no surprise to you, but many headless browser users want as much of the complexity taken off their plate as possible. And some features (especially around stealth) can only be implemented effectively on the server.

Since the (puppeteer|playwright)-extra project hasn't been updated in a year, I would like to offer an open source alternative with fully cross-compatible plugins and up-to-date versions of the aforementioned features I'm building for users. However, only Puppeteer allows hooking the lifecycle on the server-side. I think Playwright should support this as well.

The APIs I need access to are .contexts() and newContext(), because these grant access to the default context, any new contexts created, and any new pages created. Though I wonder if it would be better to expose the server's Browser instance via an undocumented ._browserForTest(), because this would offer a perfect escape hatch for any future user needing this access.