Skip to content

fix: SW-wait timeout + automatic dev-server warm-up (0.1.2)#3

Merged
kevinccbsg merged 4 commits into
mainfrom
fix/sw-wait-timeout
Jun 27, 2026
Merged

fix: SW-wait timeout + automatic dev-server warm-up (0.1.2)#3
kevinccbsg merged 4 commits into
mainfrom
fix/sw-wait-timeout

Conversation

@kevinccbsg

Copy link
Copy Markdown
Member

Summary

Fixes cross-browser flakiness where Firefox/WebKit time out claiming the service worker in headless CI while Chromium passes — surfaced when running a larger suite (it reproduced reliably with ~120 SW-mocked tests). Two root causes, both fixed here.

1. config.timeout was ignored for the SW wait (af1f1b5)

page.waitForFunction(fn, { timeout }) passed the options object in Playwright's arg slot (signature is waitForFunction(pageFunction, arg, options)), so the timeout was silently dropped and the wait fell back to Playwright's 30s default. That cap is too low for Firefox/WebKit to claim the SW in headless CI, so the wait timed out and no tests ran. Moved the timeout into the options slot.

Proven with a standalone Playwright repro:

buggy   form  -> threw after 30006 ms   (ignored the requested 2000ms)
correct form  -> threw after  2003 ms

2. Cold dev server races SW registration (03d8b1a)

A cold Vite dev server compiles the module graph and runs optimizeDeps on first load, forcing a full-page reload that races SW registration. Chromium shrugs it off; Firefox/WebKit lose the race. In a sequential run the first engine accidentally warms the shared server for the rest — which is why serial passed but parallel/cold runs failed.

Now, when waitForServiceWorker is set, the runner does one throwaway Chromium page load first (same readiness gates) so every engine starts against a warm server. It's:

  • Automatic — no new config key; tied entirely to waitForServiceWorker.
  • Best-effort — a warm-up that can't complete logs a warning and the run continues.
  • Resilient — falls back to a configured engine if Chromium isn't installed.

3. Docs (974e566, d95e401)

  • Lead with single-job parallel (npx twd-runner run runs engines in parallel inside one runner) as the portable, CI-agnostic pattern; the GitHub matrix is noted only as an optional per-engine-isolation extra.
  • Clarify that npm install does not fetch browser binaries (npx playwright install does), that all engines should be installed since the warm-up uses Chromium, and that the composite action installs browsers in CI.
  • Bump version to 0.1.2.

Testing

  • vitest: 42 passing (added warmUp coverage + corrected the timeout-signature assertion).
  • End-to-end on a real Vue example (124 SW-mocked tests): Firefox + WebKit go from total failure → green across 4 consecutive CI runs, single job, both engines in parallel.

Changes

  • src/runBrowser.jswaitForReady helper, timeout fix, warmUp()
  • src/index.js — warm-up pass before the run when waitForServiceWorker is set
  • src/config.js — unchanged (warm-up is internal, no new key)
  • tests/ — warmUp + timeout-signature coverage
  • README.md, package.json, package-lock.json — docs + 0.1.2

🤖 Generated with Claude Code

kevinccbsg and others added 4 commits June 27, 2026 23:28
page.waitForFunction's signature is (pageFunction, arg, options). The timeout
was passed in the second (arg) slot, so Playwright ignored it and fell back to
its 30s default. That cap is too low for Firefox/WebKit to claim the service
worker in headless CI, where they routinely need longer than 30s — the wait
timed out and no tests ran. Move the timeout into the options slot so
config.timeout actually applies.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…is set

A cold Vite dev server compiles the module graph and runs optimizeDeps on first
load, forcing a reload that races service-worker registration. Chromium tolerates
it; Firefox/WebKit time out claiming the worker — worst in parallel/matrix runs
where each job hits its own cold server. In a sequential run the first engine
warms the shared server for the rest; this makes that warm-up explicit and
automatic so every engine starts hot.

Before running the configured browsers (only when waitForServiceWorker is set),
drive one throwaway Chromium page load through the same readiness gates, falling
back to a configured engine if Chromium isn't installed. It's internal to
waitForServiceWorker with no separate option, and best-effort: a warm-up that
can't complete logs a warning and the run continues.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A single job (npx twd-runner run launches engines in parallel inside one runner)
is portable across any CI — GitLab, CircleCI, Jenkins — and needs no CI-specific
orchestration. Frame that as the default and note the GitHub Actions matrix only
as an optional per-engine-isolation extra. Also drop the matrix-centric wording
from the warm-up note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump to 0.1.2 for the SW-wait timeout fix + automatic warm-up.

README: note that `npm install` does not fetch browser binaries (npx playwright
install does), that all engines should be installed since the warm-up uses
Chromium even for Firefox/WebKit-only runs, and that the composite action
installs browsers in CI so the manual step isn't needed there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kevinccbsg kevinccbsg merged commit 08be36f into main Jun 27, 2026
2 checks passed
@kevinccbsg kevinccbsg deleted the fix/sw-wait-timeout branch June 27, 2026 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant