-
Notifications
You must be signed in to change notification settings - Fork 657
Playwright Browser Server #5424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bmiddha
wants to merge
24
commits into
main
Choose a base branch
from
bmiddha/playwright-browser-server
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,045
−3
Open
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
7956637
playwright browser server
bmiddha d0d71c2
fixup server listening log message
bmiddha 3325d49
Implement playwright-on-codespaces vscode extension and impl
TheLarkInn de6a58f
DROP: rush update
TheLarkInn 234d090
fix wsEndpoint
TheLarkInn 46f7c0b
revert some browser options
TheLarkInn 9aef4a1
remove check about remote
TheLarkInn 8528353
vscode status bar icon
bmiddha 92fd7dc
demo: disable loading bundled extension
bmiddha e7a38d5
Actually use bufferutils and utf-8-validate in bundled websocket code
TheLarkInn 3b85d15
update webpack config comment
TheLarkInn 646b76b
auto start the tunnel on activation
TheLarkInn a186ab1
Add todos and update version
TheLarkInn 9db3c84
Merge branch 'bmiddha/playwright-browser-server' of https://github.co…
TheLarkInn 93a0594
Refactoring workspaceCommand fn and minor changes
TheLarkInn 4ff682a
Merge branch 'main' into bmiddha/playwright-browser-server
TheLarkInn cce4517
DROP: rush update
TheLarkInn 29a8e03
repo-toolbox readme
TheLarkInn 48408b3
add README's, api-extractor and removed unused CLI and start commands
TheLarkInn 1d849b3
Update vscode-extensions/playwright-on-codespaces-vscode-extension/LI…
TheLarkInn d03eecc
Update apps/playwright-browser-tunnel/src/tunneledBrowserConnection.ts
TheLarkInn bcd1cf8
fix spelling mistake
TheLarkInn 2e52a89
remove console.log usage for terminal
TheLarkInn e43651c
refactor: improve WebSocket connection handling and logging in Playwr…
TheLarkInn File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "servers": { | ||
| "playwright": { | ||
| "type": "stdio", | ||
| "command": "node", | ||
| "args": [ | ||
| "${workspaceFolder}/apps/playwright-browser-tunnel/lib/PlaywrightMcpBrowserTunnelClientCommandLine.js" | ||
| ] | ||
| } | ||
| }, | ||
| "inputs": [] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
|
|
||
| # @rushstack/playwright-browser-tunnel | ||
|
|
||
| Run a Playwright browser server in one environment and drive it from another environment by forwarding Playwright’s WebSocket traffic through a tunnel. | ||
|
|
||
| This package is intended for remote development / CI scenarios (for example: Codespaces, devcontainers, or a separate “browser host” machine) where you want tests to run “here” but the actual browser process to run “there”. | ||
|
|
||
| ## Relationship to the Playwright on Codespaces VS Code extension | ||
|
|
||
| This package is the core tunneling/runtime layer used by the **Playwright on Codespaces** VS Code extension (located at [vscode-extensions/playwright-on-codespaces-vscode-extension](../../vscode-extensions/playwright-on-codespaces-vscode-extension)). | ||
|
|
||
| In a typical Codespaces workflow: | ||
|
|
||
| - Your **tests** run inside the Codespace and call `tunneledBrowserConnection()`. | ||
| - `tunneledBrowserConnection()` starts a WebSocket server (by default on port `3000`) that a browser host can attach to. | ||
| - The VS Code extension runs on the **UI side** and starts a `PlaywrightTunnel` which connects to `ws://127.0.0.1:3000`. | ||
| - In Codespaces, this works when port `3000` is forwarded to your local machine (VS Code port forwarding makes the remote port reachable as `localhost:3000`). | ||
| - Once connected, the extension hosts the actual Playwright browser process locally, while your tests continue to run remotely. | ||
|
|
||
| The extension provides a UI wrapper around this library (start/stop commands, status bar state, and logs), while `@rushstack/playwright-browser-tunnel` provides the underlying protocol forwarding and browser lifecycle management. | ||
|
|
||
| ### Detecting whether the VS Code extension is present | ||
|
|
||
| Some remote test fixtures want to detect whether the **Playwright on Codespaces** extension is installed/active (for example, to skip local-browser-only scenarios when the extension isn’t available). | ||
|
|
||
| The extension writes a marker file named `.playwright-codespaces-extension-installed.txt` into the remote environment’s `os.tmpdir()` using VS Code’s remote filesystem APIs. | ||
|
|
||
| On the remote side, `extensionIsInstalled()` checks for that marker file and returns `true` if it exists: | ||
|
|
||
| ```ts | ||
| import { extensionIsInstalled } from '@rushstack/playwright-browser-tunnel'; | ||
|
|
||
| if (!(await extensionIsInstalled())) { | ||
| throw new Error('Playwright on Codespaces extension is not installed/active in this environment'); | ||
| } | ||
| ``` | ||
|
|
||
| ## Status | ||
|
|
||
| This package’s API surface is currently tagged as `@alpha`. | ||
|
|
||
| ## Requirements | ||
|
|
||
| - Node.js `>= 20` (see `engines` in `package.json`) | ||
| - A compatible Playwright version (this package is built/tested with Playwright `1.56.x`) | ||
|
|
||
| ## Exports | ||
|
|
||
| From [src/index.ts](src/index.ts): | ||
|
|
||
| - `PlaywrightTunnel` (class) | ||
| - `IPlaywrightTunnelOptions` (type) | ||
| - `TunnelStatus` (type) | ||
| - `BrowserNames` (type) | ||
| - `tunneledBrowserConnection()` (function) | ||
| - `tunneledBrowser()` (function) | ||
| - `IDisposableTunneledBrowserConnection` (type) | ||
| - `extensionIsInstalled()` (function) | ||
|
|
||
| ## Usage | ||
|
|
||
| There are two pieces: | ||
|
|
||
| 1) **Browser host**: run a `PlaywrightTunnel` to launch the real browser server and forward messages. | ||
| 2) **Test runner**: create a local endpoint via `tunneledBrowserConnection()` that your Playwright client can connect to (it forwards to the browser host). | ||
|
|
||
| ### 1) Browser host: run the tunnel | ||
|
|
||
| Use `PlaywrightTunnel` in the environment where you want the browser process to run. | ||
|
|
||
| ```ts | ||
| import { ConsoleTerminalProvider, Terminal, TerminalProviderSeverity } from '@rushstack/terminal'; | ||
| import { PlaywrightTunnel } from '@rushstack/playwright-browser-tunnel'; | ||
| import path from 'node:path'; | ||
| import os from 'node:os'; | ||
|
|
||
| const terminalProvider = new ConsoleTerminalProvider(); | ||
| const terminal = new Terminal(terminalProvider); | ||
|
|
||
| const tunnel = new PlaywrightTunnel({ | ||
| mode: 'wait-for-incoming-connection', | ||
| listenPort: 3000, | ||
| tmpPath: path.join(os.tmpdir(), 'playwright-browser-tunnel'), | ||
| terminal, | ||
| onStatusChange: (status) => terminal.writeLine(`status: ${status}`) | ||
| }); | ||
|
|
||
| await tunnel.startAsync({ keepRunning: true }); | ||
| ``` | ||
|
|
||
| Notes: | ||
|
|
||
| - `mode: 'wait-for-incoming-connection'` starts a WebSocket server and waits for the other side to connect. | ||
| - `mode: 'poll-connection'` repeatedly attempts to connect to a WebSocket endpoint you provide (`wsEndpoint`). | ||
| - `tmpPath` is used as a working directory to install the requested `playwright-core` version and run its CLI. | ||
|
|
||
| ### 2) Test runner: create a local endpoint to connect() | ||
|
|
||
| Use `tunneledBrowserConnection()` in the environment where your tests run. | ||
|
|
||
| It starts: | ||
|
|
||
| - a **remote** WebSocket server (port `3000`) that the browser host connects to | ||
| - a **local** WebSocket endpoint (random port) that your Playwright client connects to | ||
|
|
||
| ```ts | ||
| import { tunneledBrowserConnection } from '@rushstack/playwright-browser-tunnel'; | ||
| import playwright from 'playwright-core'; | ||
|
|
||
| using connection = await tunneledBrowserConnection(); | ||
|
|
||
| // Build the connect URL with query parameters consumed by the local proxy. | ||
| const url = new URL(connection.remoteEndpoint); | ||
| url.searchParams.set('browser', 'chromium'); | ||
| url.searchParams.set('launchOptions', JSON.stringify({ headless: true })); | ||
|
|
||
| const browser = await playwright.chromium.connect(url.toString()); | ||
| // ...run tests... | ||
| await browser.close(); | ||
| ``` | ||
|
|
||
| ## Development | ||
|
|
||
| - Build: `rush build --to playwright-browser-tunnel` | ||
| - Demo script (if configured): `rushx demo` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| - If the tunnel is stuck in `waiting-for-connection`, ensure the counterpart process is reachable and ports are forwarded correctly. | ||
| - If browser installation is slow/repeated, ensure `tmpPath` is stable and writable for the host environment. | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| { | ||
| "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", | ||
|
|
||
| "mainEntryPointFilePath": "<projectFolder>/lib/index.d.ts", | ||
|
|
||
| "apiReport": { | ||
| "enabled": true, | ||
| "reportFolder": "../../../common/reviews/api" | ||
| }, | ||
|
|
||
| "docModel": { | ||
| "enabled": true, | ||
| "apiJsonFilePath": "../../../common/temp/api/<unscopedPackageName>.api.json" | ||
| }, | ||
|
|
||
| "dtsRollup": { | ||
| "enabled": true | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| // The "rig.json" file directs tools to look for their config files in an external package. | ||
| // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package | ||
| "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", | ||
|
|
||
| "rigPackageName": "local-node-rig" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. | ||
| // See LICENSE in the project root for license information. | ||
|
|
||
| const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); | ||
| const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); | ||
|
|
||
| module.exports = [ | ||
| ...nodeTrustedToolProfile, | ||
| ...friendlyLocalsMixin, | ||
| { | ||
| files: ['**/*.ts', '**/*.tsx'], | ||
| languageOptions: { | ||
| parserOptions: { | ||
| tsconfigRootDir: __dirname | ||
| } | ||
| }, | ||
| rules: { | ||
| 'no-console': 'off' | ||
| } | ||
| } | ||
| ]; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,44 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "name": "@rushstack/playwright-browser-tunnel", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "version": "0.0.1", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "description": "Run a remote Playwright Browser Tunnel. Useful in remote development environments.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "repository": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "type": "git", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "url": "https://github.com/microsoft/rushstack.git", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "directory": "apps/playwright-browser-tunnel" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "main": "lib/index.js", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "engines": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "node": ">=20.0.0" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "engineStrict": true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "homepage": "https://rushstack.io", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "scripts": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "build": "heft build --clean", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "_phase:build": "heft run --only build -- --clean", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "demo": "playwright test --config=playwright.config.ts" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "license": "MIT", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+5
to
+21
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "dependencies": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "@rushstack/node-core-library": "workspace:*", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "@rushstack/terminal": "workspace:*", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "@rushstack/ts-command-line": "workspace:*", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "string-argv": "~0.3.1", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "semver": "~7.5.4", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "ws": "~8.14.1", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "playwright": "1.56.1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "devDependencies": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "@rushstack/heft": "workspace:*", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "eslint": "~9.37.0", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "local-node-rig": "workspace:*", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "@types/semver": "7.5.0", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "@types/ws": "8.5.5", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "playwright-core": "~1.56.1", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "@playwright/test": "~1.56.1", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "@types/node": "20.17.19" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "peerDependencies": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "playwright-core": "~1.56.1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+22
to
+43
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import { defineConfig, devices } from '@playwright/test'; | ||
|
|
||
| export default defineConfig({ | ||
| testDir: './tests', | ||
| /* Run tests in files in parallel */ | ||
| fullyParallel: true, | ||
| /* Retry on CI only */ | ||
| retries: 0, | ||
| /* Opt out of parallel tests on CI. */ | ||
| workers: 1, | ||
| /* Reporter to use. See https://playwright.dev/docs/test-reporters */ | ||
| reporter: 'html', | ||
| /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ | ||
| use: { | ||
| /* Base URL to use in actions like `await page.goto('/')`. */ | ||
| // baseURL: 'http://localhost:3000', | ||
|
|
||
| /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ | ||
| trace: 'on' | ||
| }, | ||
|
|
||
| /* Configure projects for major browsers */ | ||
| projects: [ | ||
| { | ||
| name: 'chromium', | ||
| use: { ...devices['Desktop Chrome'] } | ||
| }, | ||
| { | ||
| name: 'firefox', | ||
| use: { ...devices['Desktop Firefox'] } | ||
| }, | ||
| { | ||
| name: 'webkit', | ||
| use: { ...devices['Desktop Safari'] } | ||
| }, | ||
| { | ||
| name: 'Google Chrome', | ||
| use: { ...devices['Desktop Chrome'], channel: 'chrome' } // or 'chrome-beta' | ||
| }, | ||
| { | ||
| name: 'Microsoft Edge', | ||
| use: { ...devices['Desktop Edge'], channel: 'msedge' } // or "msedge-beta" or 'msedge-dev' | ||
| } | ||
| ] | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally use
ITerminal.