pestphp / pestphp/pest

[Bug]: Browser plugin — suite hangs silently with the websocket alive and the browser never navigating (distinct from #1801)

Open
#1,855 0 comments 0 reactions 0 assignees View on GitHub

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:

  1. PlaywrightNpmServer::start() calls setTimeout(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.
  2. 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/pest 4.4.3, pest-plugin-browser (bundled with that release)
  • playwright 1.62.1 (npm, lockfile-pinned)
  • PHP 8.5.9 and 8.3.33 (identical behaviour)
  • Laravel 13, Postgres 18
  • Fails: containerised ubuntu:24.04 CI runner. Passes: Windows 11 host.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.