From e42499903b01b83fbdcdf9e39d09e21741f09d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Tue, 17 Feb 2026 00:56:40 +0100 Subject: [PATCH] Add documentation for connecting to external browsers --- README.md | 21 +++- docs/examples/connect_external_browser.php | 65 +++++++++++ docs/examples/connect_remote_browser.php | 71 ++++++++++++ docs/examples/launch_server.php | 41 +++++++ docs/guide/advanced-recipes.md | 13 +++ docs/guide/connect-browser.md | 123 +++++++++++++++++++++ 6 files changed, 329 insertions(+), 5 deletions(-) create mode 100644 docs/examples/connect_external_browser.php create mode 100644 docs/examples/connect_remote_browser.php create mode 100644 docs/examples/launch_server.php create mode 100644 docs/guide/connect-browser.md diff --git a/README.md b/README.md index 6d0e207..06ad1c2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,8 @@ ## About -Playwright for PHP lets you launch real browsers (Chromium, Firefox, WebKit), drive pages and locators, and write reliable end‑to‑end tests — all from PHP. +Playwright for PHP lets you launch real browsers (Chromium, Firefox, WebKit), drive pages and locators, and write +reliable end‑to‑end tests — all from PHP. - **Familiar model**: browser → context → page → locator - **Auto‑waiting** interactions reduce flakiness @@ -21,6 +22,7 @@ Playwright for PHP lets you launch real browsers (Chromium, Firefox, WebKit), dr - No separate server to manage — a lightweight Node server is started for you Requirements: + - PHP 8.2+ - Node.js 20+ (used by the bundled Playwright server and browsers) @@ -48,7 +50,6 @@ vendor/bin/playwright-install --with-deps vendor/bin/playwright-install --dry-run --with-deps ``` - ## Quick start Open a page and print its title: @@ -69,13 +70,20 @@ echo $page->title().PHP_EOL; // Example Domain $context->close(); ``` +## Documentation + +- [Quick Start Guide](docs/guide.md) +- [Playwright Inspector](docs/inspector.md) +- [Contributing: Testing](docs/contributing/testing.md) + ## Usage ### Browser - Choose a browser: `Playwright::chromium()`, `Playwright::firefox()`, or `Playwright::webkit()`. - `Playwright::safari()` is an alias of `webkit()`. -- Common launch options: `headless` (bool), `slowMo` (ms), `args` (array of CLI args), and an optional `context` array with context options. +- Common launch options: `headless` (bool), `slowMo` (ms), `args` (array of CLI args), and an optional `context` array + with context options. ```php $context = Playwright::webkit([ @@ -165,6 +173,7 @@ final class HomePageTest extends TestCase ``` Notes: + - The trait provides `$this->playwright`, `$this->browser`, `$this->context`, and `$this->page` properties. - Call `setUpPlaywright()` in `setUp()` and `tearDownPlaywright()` in `tearDown()` for proper lifecycle management. - Use `$this->expect($locator)` or `$this->expect($page)` for fluent assertions. @@ -198,12 +207,14 @@ jobs: ``` Tips: + - Cache Node and Composer if you need faster builds. - You can also cache Playwright browsers under `~/.cache/ms-playwright`. ## Contributing -Contributions are welcome. Please use Conventional Commits, include tests for behavior changes, and ensure docs/examples are updated when relevant. A typical first run inside the repository is: +Contributions are welcome. Please use Conventional Commits, include tests for behavior changes, and ensure docs/examples +are updated when relevant. A typical first run inside the repository is: ```bash composer install # installs PHP deps and the bundled Playwright server @@ -214,5 +225,5 @@ See `docs/contributing/testing.md` for more details on the local workflow. ## License -This package is released by the [Playwright PHP](https://playwright-php.dev) +This package is released by the [Playwright PHP](https://playwright-php.dev) project under the MIT License. See the [LICENSE](LICENSE) file for details. diff --git a/docs/examples/connect_external_browser.php b/docs/examples/connect_external_browser.php new file mode 100644 index 0000000..0b67eb5 --- /dev/null +++ b/docs/examples/connect_external_browser.php @@ -0,0 +1,65 @@ +launchServer('chromium', ['headless' => true]); +$wsEndpoint = $server->wsEndpoint(); +echo "Browser server started at: {$wsEndpoint}\n"; + +// Example 2: connect() uses Playwright protocol, so it must target a launchServer() endpoint. +echo "\n=== Example 2: Connect to Browser Server ===\n"; +$browser = $playwright->chromium()->connect($wsEndpoint); +$context = $browser->newContext(); +$page = $context->newPage(); +$page->goto('https://example.com'); +echo "Page title: {$page->title()}\n"; + +$browser->close(); +// Closing the client connection does not stop the server process. +$server->close(); + +// Example 3: connectOverCDP() is Chromium-only and attaches to a running Chrome instance. +// First, start Chrome with remote debugging enabled. +echo "\n=== Example 3: Connect Over CDP (Chromium only) ===\n"; +echo "To use this example:\n"; +echo "1. Start Chrome with remote debugging on port 9222\n"; +echo " macOS example:\n"; +echo " \"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\" --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-pw\n"; +echo "2. Optionally set CDP_ENDPOINT (default: http://127.0.0.1:9222)\n"; + +$cdpEndpoint = getenv('CDP_ENDPOINT') ?: 'http://127.0.0.1:9222'; + +try { + $cdpBrowser = $playwright->chromium()->connectOverCDP($cdpEndpoint); + $cdpContext = $cdpBrowser->newContext(); + $cdpPage = $cdpContext->newPage(); + $cdpPage->goto('https://playwright.dev'); + echo "Connected via CDP! Title: {$cdpPage->title()}\n"; + $cdpBrowser->close(); +} catch (PlaywrightException $e) { + echo "CDP connection failed at {$cdpEndpoint}: {$e->getMessage()}\n"; +} + +$playwright->close(); + +echo "\nDone!\n"; diff --git a/docs/examples/connect_remote_browser.php b/docs/examples/connect_remote_browser.php new file mode 100644 index 0000000..e9ffd43 --- /dev/null +++ b/docs/examples/connect_remote_browser.php @@ -0,0 +1,71 @@ +launchServer('chromium', ['headless' => true]);\n"; + echo " echo \$server->wsEndpoint();\n"; + echo " while (true) { sleep(1); }\n"; + echo "2. Run this example with:\n"; + echo " REMOTE_WS_ENDPOINT='ws://127.0.0.1:PORT/ID' php docs/examples/connect_remote_browser.php\n"; + $playwright->close(); + + exit(1); +} + +echo "Attempting to connect to remote browser at: {$remoteWsEndpoint}\n"; + +try { + $browser = $playwright->chromium()->connect($remoteWsEndpoint); + echo "Successfully connected to remote browser!\n"; + + $context = $browser->newContext(); + $page = $context->newPage(); + + $page->goto('https://example.com'); + echo "Page title: {$page->title()}\n"; + echo "URL: {$page->url()}\n"; + + // Keep remote servers alive for other clients; only close this client connection. + $browser->close(); + echo "Browser connection closed.\n"; +} catch (Exception $e) { + echo "Failed to connect: {$e->getMessage()}\n"; + echo "Tip: REMOTE_WS_ENDPOINT must be the full wsEndpoint() value, including path.\n"; + echo "\nTo set up an external Playwright browser-server instance:\n"; + echo "1. Start any PHP process with:\n"; + echo " \$server = \$playwright->launchServer('chromium', ['headless' => true]);\n"; + echo " echo \$server->wsEndpoint();\n"; + echo " while (true) { sleep(1); }\n"; + echo "2. Copy its wsEndpoint() value (ws://...)\n"; + echo "3. Set REMOTE_WS_ENDPOINT to that value and run this script again\n"; +} + +$playwright->close(); diff --git a/docs/examples/launch_server.php b/docs/examples/launch_server.php new file mode 100644 index 0000000..0ec81b2 --- /dev/null +++ b/docs/examples/launch_server.php @@ -0,0 +1,41 @@ +launchServer('chromium', [ + 'headless' => true, +]); + +$wsEndpoint = $server->wsEndpoint(); + +echo "Browser server running!\n"; +echo "WebSocket endpoint: {$wsEndpoint}\n"; +echo "\nOther processes can connect using:\n"; +echo "\$browser = \$playwright->chromium()->connect('{$wsEndpoint}');\n"; +echo "\nPress Ctrl+C to stop the server...\n"; + +// Keep serving until interrupted so clients can keep connecting to this endpoint. +while (true) { + sleep(1); +} diff --git a/docs/guide/advanced-recipes.md b/docs/guide/advanced-recipes.md index 0bf449f..fe5684d 100644 --- a/docs/guide/advanced-recipes.md +++ b/docs/guide/advanced-recipes.md @@ -3,6 +3,15 @@ This page contains recipes for common but more advanced automation scenarios. Use these examples to leverage the full power of Playwright for PHP. +## Table of Contents + +* [File Uploads](#file-uploads) +* [Network Interception](#network-interception) +* [Handling Dialogs](#handling-dialogs) +* [Working with Frames](#working-with-frames) +* [Connecting to External Browsers](#connecting-to-external-browsers) +* [Browser Configuration with `PlaywrightConfigBuilder`](#browser-configuration-with-playwrightconfigbuilder) + ## File Uploads You can upload one or more files to an `` element using the `setInputFiles()` method on a `Locator`. @@ -88,6 +97,10 @@ $frameButton = $frame->locator('button:has-text("Submit")'); $frameButton->click(); ``` +## Connecting to External Browsers + +This topic has its own page: **[Connecting to External Browsers](connect-browser.md)**. + ## Browser Configuration with `PlaywrightConfigBuilder` For advanced browser setups, such as using a proxy server or setting custom launch arguments, you can use the diff --git a/docs/guide/connect-browser.md b/docs/guide/connect-browser.md new file mode 100644 index 0000000..6498d66 --- /dev/null +++ b/docs/guide/connect-browser.md @@ -0,0 +1,123 @@ +# Connecting to External Browsers + +This guide explains how to connect Playwright PHP to a browser that is already running outside your current PHP process. + +Use one of these connection modes: + +- **Playwright protocol (`connect`)**: connect to a browser server started with `launchServer()` (recommended). +- **Chrome DevTools Protocol (`connectOverCDP`)**: connect to Chromium/Chrome with remote debugging enabled. + +## Connect with Playwright protocol (recommended) + +This mode gives the most complete Playwright behavior and works with browser server endpoints returned by +`wsEndpoint()`. + +### Step 1: Start an external browser server instance + +Run this in another PHP process: + +```php +launchServer('chromium', ['headless' => true]); + +echo $server->wsEndpoint().PHP_EOL; + +while (true) { + sleep(1); +} +``` + +Copy the printed `ws://...` value exactly as-is (including the random path segment). + +### Step 2: Connect from your script + +```php +chromium()->connect($endpoint); +$context = $browser->newContext(); +$page = $context->newPage(); +$page->goto('https://example.com'); + +echo $page->title().PHP_EOL; + +$browser->close(); +$playwright->close(); +``` + +Run: + +```bash +REMOTE_WS_ENDPOINT='ws://127.0.0.1:PORT/ID' php your-script.php +``` + +## Connect over CDP (Chromium only) + +Use this when you already have Chrome/Chromium running with remote debugging. + +### Step 1: Start Chrome with remote debugging + +macOS: + +```bash +"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-pw +``` + +### Step 2: Connect with `connectOverCDP()` + +```php +chromium()->connectOverCDP($cdpEndpoint); +$context = $browser->newContext(); +$page = $context->newPage(); +$page->goto('https://example.com'); + +echo $page->title().PHP_EOL; + +$browser->close(); +$playwright->close(); +``` + +## Troubleshooting + +### `ECONNREFUSED` when connecting + +- The target browser endpoint is not running. +- Start the server/browser first, then retry. +- Use `127.0.0.1` instead of `localhost` if your machine resolves `localhost` to IPv6 and nothing listens on `::1`. + +### `connect()` fails on a CDP endpoint + +- `connect()` requires a **Playwright WebSocket endpoint** from `launchServer()`. +- If you only have `http://127.0.0.1:9222`, use `connectOverCDP()` instead. + +## Related examples + +- `docs/examples/connect_external_browser.php` +- `docs/examples/connect_remote_browser.php` +- `docs/examples/launch_server.php`