Summary
The recommended GitHub Actions workflow in docs/src/ci.md sets a job-level timeout-minutes but never mentions globalTimeout, which defaults to no timeout. When a suite grows past the job timeout, the runner kills the job, the run's conclusion is cancelled rather than failure, and the report upload step in that same example is skipped by its own if: ${{ !cancelled() }} guard. So you get no report on precisely the runs where you most need one, and nothing in the run distinguishes it from a job somebody cancelled by hand.
I would like to add a short note about this to ci.md, and I am filing this first per CONTRIBUTING.
The current state of the docs
docs/src/ci.md, "On push/pull_request":
jobs:
test:
timeout-minutes: 60
...
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v5
if: ${{ !cancelled() }}
globalTimeout appears zero times in ci.md. It is documented in test-timeouts-js.md, where the default is listed as "no timeout", but that page does not connect it to a CI job timeout.
So a reader who follows the CI guide exactly ends up with a hard runner kill as the only bound on their run, and nothing tells them what that costs.
What actually happens
Some numbers from a repository where this ran unnoticed for two months, with a 20 minute job timeout and a suite that had grown past it:
- 164 nightly runs. 7 succeeded, 76 failed, 81 ended
cancelled, the last 60-plus consecutively.
- Every cancelled run produced zero artifacts. The upload step reported
success in the ones that were not guarded by !cancelled(), because there was simply nothing on disk to upload.
- After setting
globalTimeout below the job timeout, the same suite completed in 29 minutes, reported failure with 12 of 147 tests failing, and produced an 83 MB report.
The suite had needed 29 minutes for a while. The 20 minute limit had been killing it nightly, and because a kill is not a failure, nothing said so.
Why it seems worth a line in the docs
GitHub code search reports roughly 163,000 playwright.config.ts files, of which about 1,700 set globalTimeout. That is around one percent. Around 3,200 workflows run npx playwright test on a cron schedule, which is the case where nobody is watching the run live and the missing report matters most.
The ordering is the useful part, and it is not obvious: globalTimeout set below the job's timeout-minutes makes Playwright stop itself first. It exits non-zero, the reporters finish, the HTML report and results.json are written, and the run reads as an ordinary test failure. The runner timeout then only has to cover the install and upload steps around the run.
Proposed change
A short note in ci.md near the GitHub Actions example, along the lines of:
The timeout-minutes above is a hard kill, not a test failure. If your suite outgrows it, the runner stops the process mid-run, the job's conclusion is cancelled, and no report is written. Setting globalTimeout below it lets Playwright stop itself first, so an over-running suite fails with a full report instead.
Happy to open the PR if this is something you would take, in ci.md alone or in both pages. I have no preference on wording and will follow whatever the team prefers.
Summary
The recommended GitHub Actions workflow in
docs/src/ci.mdsets a job-leveltimeout-minutesbut never mentionsglobalTimeout, which defaults to no timeout. When a suite grows past the job timeout, the runner kills the job, the run's conclusion iscancelledrather thanfailure, and the report upload step in that same example is skipped by its ownif: ${{ !cancelled() }}guard. So you get no report on precisely the runs where you most need one, and nothing in the run distinguishes it from a job somebody cancelled by hand.I would like to add a short note about this to
ci.md, and I am filing this first per CONTRIBUTING.The current state of the docs
docs/src/ci.md, "On push/pull_request":globalTimeoutappears zero times inci.md. It is documented intest-timeouts-js.md, where the default is listed as "no timeout", but that page does not connect it to a CI job timeout.So a reader who follows the CI guide exactly ends up with a hard runner kill as the only bound on their run, and nothing tells them what that costs.
What actually happens
Some numbers from a repository where this ran unnoticed for two months, with a 20 minute job timeout and a suite that had grown past it:
cancelled, the last 60-plus consecutively.successin the ones that were not guarded by!cancelled(), because there was simply nothing on disk to upload.globalTimeoutbelow the job timeout, the same suite completed in 29 minutes, reportedfailurewith 12 of 147 tests failing, and produced an 83 MB report.The suite had needed 29 minutes for a while. The 20 minute limit had been killing it nightly, and because a kill is not a failure, nothing said so.
Why it seems worth a line in the docs
GitHub code search reports roughly 163,000
playwright.config.tsfiles, of which about 1,700 setglobalTimeout. That is around one percent. Around 3,200 workflows runnpx playwright teston a cron schedule, which is the case where nobody is watching the run live and the missing report matters most.The ordering is the useful part, and it is not obvious:
globalTimeoutset below the job'stimeout-minutesmakes Playwright stop itself first. It exits non-zero, the reporters finish, the HTML report andresults.jsonare written, and the run reads as an ordinary test failure. The runner timeout then only has to cover the install and upload steps around the run.Proposed change
A short note in
ci.mdnear the GitHub Actions example, along the lines of:Happy to open the PR if this is something you would take, in
ci.mdalone or in both pages. I have no preference on wording and will follow whatever the team prefers.