[Bug]: Browser plugin — suite hangs silently with the websocket alive and the browser never navigating (distinct from #1801)
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 11.7k
- Forks
- 538
- Avg merge
- 4d 11h
- Merged PRs (30d)
- 8
Description
What Happened
The browser suite hangs forever with zero output — not a test name, not a header — while every
component it depends on is demonstrably healthy. The Playwright server is listening, Chromium is running
with a live renderer, and PHP's websocket to the server is ESTABLISHED. PHP simply never issues the
navigation: it blocks in poll_schedule_timeout waiting for a websocket reply that never arrives.
Filed here because issues are disabled on pestphp/pest-plugin-browser.
Related but distinct from #1801. That one is the closed-connection case: receive() returns null
immediately and execute() busy-loops at ~100% CPU in state R. This is the opposite: the connection is
alive, receive() never returns, and the process sits idle in state S at 0% CPU. Same underlying design
gap — nothing in the stack bounds the wait — reached from the other direction, so a fix for #1801's empty-read
loop would not cover this.
Process photograph taken 150s into a hang, in CI:
php pest --testsuite=Browser ← blocked in poll_schedule_timeout, 0 bytes of output
└─ sh -c ./node_modules/.bin/playwright run-server --host 127.0.0.1 --port 50049 --mode launchServer
└─ node ./node_modules/.bin/playwright run-server …
└─ chrome-headless-shell --no-sandbox --headless
├─ gpu-process, network service
└─ renderer ← a page exists
tcp LISTEN 127.0.0.1:50049 playwright server
tcp LISTEN 127.0.0.1:35837 the plugin's in-process Amp HTTP server (the app)
tcp ESTAB 127.0.0.1:50049 ↔ :36284 PHP → playwright server
tcp ESTAB 172.26.0.5 → …:32826 Postgres
(nothing connected to 35837)
Nothing ever connects to the app's own HTTP server. So the stall is after PlaywrightNpmServer::start(),
after the websocket connect, and after a page has been created — but before the browser is told to navigate.
Two things make this undiagnosable from the outside, and both look worth bounding regardless of the root cause:
PlaywrightNpmServer::start()callssetTimeout(0)and then
waitUntil(str_contains($output, 'Listening on')). If that line never appears the suite waits forever,
having printed nothing at all — no header, no test name. A bounded wait with the server's own output on
failure would turn this class of problem into a message.Client::execute()has no bound on a reply either (the other half of #1801).
For what it's worth, the plugin declares PLAYWRIGHT_VERSION = '1.54.1' while resolving playwright@1.62.1
via ^1.62.1. That is constant across my working and failing environments so it is not the cause here,
but if the run-server protocol has moved between those versions it may be worth pinning or checking.
How to Reproduce
I cannot offer a minimal reproduction, and that is the honest state of it: the same suite, same commit, same
Playwright version passes locally in ~180s and hangs indefinitely in CI. The environmental difference is
a containerised Linux runner (ubuntu:24.04, jobs run as a non-root runner user, Docker available via a
sidecar daemon) versus a Windows host.
What I eliminated by direct probe rather than by argument, in case it saves anyone time:
| Suspect | Verdict |
|---|---|
playwright run-server fails to start |
Starts and prints Listening on ws://127.0.0.1:PORT/ in 4s |
| Chromium cannot launch in a container | chromium.launch() + newPage() + render + close all succeed |
| Chromium sandbox | Playwright already passes --no-sandbox; confirmed in the live process args |
| PHP version | Hangs identically on 8.3.33 and 8.5.9 |
A stale DB lock blocking migrate:fresh |
0 sessions on the test databases, 0 ungranted locks, still hangs |
| Playwright version mismatch | 1.62.1 in both the working and failing environments |
Package Versions
pestphp/pest4.4.3,pest-plugin-browser(bundled with that release)playwright1.62.1 (npm, lockfile-pinned)- PHP 8.5.9 and 8.3.33 (identical behaviour)
- Laravel 13, Postgres 18
- Fails: containerised
ubuntu:24.04CI runner. Passes: Windows 11 host.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with PlaywrightNpmServer::start() and Client::execute(), then reproduce the Browser testsuite hang in the containerised CI environment. Inspect the wait around poll_schedule_timeout and the server startup output. Done means the relevant waits are bounded and a failure reports enough server or websocket context to diagnose the stall.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php, playwright
- Domain
- testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100