Fix doctor reporting false failures on valid setups - #66
Conversation
`webwright doctor` reported 3/6 on a correctly provisioned machine. All three failures were wrong. Browsers (was "Chromium"): - invoked the bare `playwright` console script, which Windows cannot resolve, leaking a raw `[WinError 2]` instead of an actionable message - only inspected the return code of `playwright install --dry-run`, which is 0 even when no browser is installed, so the check could never fail for the right reason Now runs the driver via `sys.executable -m playwright` and stats the install locations it reports. Screenshot: - hard-coded Chromium, so a Firefox-only setup failed even though skills/webwright/reference/playwright_patterns.md pins Firefox because Akamai-fronted sites reject Chromium on TLS/H2 fingerprinting - wrote doctor_test.png into the caller's working directory Now tries Firefox first, falls back to Chromium, and uses a temp dir. Model Backend (was "OpenAI Key"): - required OPENAI_API_KEY specifically, so an Anthropic or OpenRouter run reported FAIL, as did the Claude Code / Codex plugin path, which needs no key at all because the host agent drives the loop Now accepts any backend shipped under webwright/models/ and explains that plugin mode is keyless when none is set. Plugins: - resolved the manifests against the process working directory, so doctor failed from any subdirectory of the repo Now walks upward to locate the repo root. Tests went from 9 tautological assertions (`assert isinstance(ok, bool)`) to 22 that cover each regression. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes webwright doctor reporting false failures on valid setups (notably Windows + Firefox-first configurations) by making checks both more accurate and more aligned with the project’s documented provisioning paths.
Changes:
- Replaces the old Chromium-only install check with a browser-engine check that invokes
sys.executable -m playwright install --dry-run, parses reported install locations, and verifies they exist on disk. - Updates the screenshot validation to try Firefox first (then Chromium) and to write the temporary screenshot into a
TemporaryDirectoryinstead of the caller’s cwd. - Broadens the “model backend” check to accept OpenAI/Anthropic/OpenRouter env vars and improves plugin manifest resolution by walking upward to find the repo root; expands unit tests to assert real behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/webwright/run/doctor.py |
Fixes doctor’s browser detection, screenshot validation, model backend key acceptance, and plugin manifest root detection; updates check labels. |
tests/unit/test_doctor.py |
Replaces weak type-only assertions with behavior-focused tests covering parsing, browser reporting, model backend env var acceptance, plugin root discovery, and screenshot cwd cleanliness. |
Suppressed comments (2)
src/webwright/run/doctor.py:120
- Same as above: this fix hint uses the bare
playwrightscript, which the PR notes is unreliable on Windows. Suggest switching the hint topython -m playwright install firefoxso users can actually follow it on Windows.
return False, (
"no Playwright browsers installed\nFix: playwright install firefox"
)
src/webwright/run/doctor.py:171
- The screenshot check’s fix hint also uses the bare
playwrightscript; given the PR motivation (Windows launcher resolution), the hint should be the cross-platformpython -m playwright install firefox.
return False, (
f"unable to capture a screenshot with any installed browser{detail}\n"
"Fix: playwright install firefox"
)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return False, ( | ||
| "could not parse 'playwright install --dry-run' output\n" | ||
| "Fix: playwright install firefox" | ||
| ) |
|
@microsoft-github-policy-service agree |
|
Correction to my previous comment on this PR. I entered
I do not have, and did not intend to claim, authority to bind Microsoft |
Problem
On a correctly provisioned machine,
webwright doctorreports failures for things thatwork. Running it on Windows with Firefox installed per
skills/webwright/reference/playwright_patterns.md:Firefox launches and screenshots fine on that machine. All three failures are wrong.
What was wrong
Chromium → Browsers
Two independent bugs in one check:
playwrightconsole script. That resolves on POSIX but not reliablyon Windows, so the failure surfaced as a raw
[WinError 2]telling the user nothing.playwright install --dry-run. That commandexits
0whether or not a browser is installed, so on POSIX the check passesunconditionally. It could never detect a missing browser — only a missing launcher.
Now invokes
sys.executable -m playwright, parses theInstall location:lines that--dry-runprints per engine, and stats them. An engine counts as present only if itsdirectory exists. Firefox and Chromium are both reported.
Screenshot
reject Chromium on TLS/H2 fingerprinting, so a setup provisioned by following the
project's own docs fails this check.
doctor_test.pnginto the caller's working directory and left it behind.Now tries Firefox first, falls back to Chromium, and writes into a
TemporaryDirectory.OpenAI Key → Model Backend
Required
OPENAI_API_KEYspecifically. An Anthropic or OpenRouter setup reported FAIL,and so did the Claude Code / Codex plugin path, which needs no key at all because the
host agent drives the loop. Now accepts any backend shipped under
webwright/models/,and when none is set it says so while noting plugin mode does not require one.
Plugins
Resolved the manifest paths against the process working directory, so the check passes
from the repo root and fails from anywhere else. This does not show in the table above
because that run was from the repo root:
Now walks upward from the working directory to locate the repo root.
After
Same machine, no configuration changed:
The remaining failure is correct: that machine genuinely has no API key set.
Tests
tests/unit/test_doctor.pyassertedisinstance(ok, bool)on each check, which holdsregardless of what the check does. Replaced with tests that pin actual behaviour:
test_parse_install_locations/_empty— the--dry-runoutput parsertest_check_browsers_reports_an_installed_enginetest_check_model_backend_accepts_anthropic_only/_accepts_openrouter_onlytest_check_model_backend_missing_mentions_plugin_modetest_plugin_manifests_found_from_subdirectorytest_screenshot_does_not_pollute_cwd9 tests → 22, all passing.
Notes
run/doctor.pyand its tests is touched.Chromium→Browsers,OpenAI Key→Model Backend)because both now verify something broader than their old name. Glad to keep the
original labels if you would rather not change the output.
check_browsersdraft usedsync_playwright()just to readexecutable_path; that leaves a pending driver task and printsTask was destroyed but it is pending!to stderr. The subprocess approach avoidsconnecting to the driver at all, which is why it is written this way.