playwright-e2e-mcp 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +55 -20
  2. package/dist/cli/ci.d.ts +5 -0
  3. package/dist/cli/ci.js +97 -5
  4. package/dist/cli/ci.js.map +1 -1
  5. package/dist/cli/doctor.d.ts +31 -0
  6. package/dist/cli/doctor.js +200 -0
  7. package/dist/cli/doctor.js.map +1 -0
  8. package/dist/cli/init.js +2 -1
  9. package/dist/cli/init.js.map +1 -1
  10. package/dist/cli/review.d.ts +50 -0
  11. package/dist/cli/review.js +148 -0
  12. package/dist/cli/review.js.map +1 -0
  13. package/dist/http.d.ts +14 -1
  14. package/dist/http.js +43 -8
  15. package/dist/http.js.map +1 -1
  16. package/dist/index.js +10 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/oauth.d.ts +10 -0
  19. package/dist/oauth.js +29 -1
  20. package/dist/oauth.js.map +1 -1
  21. package/dist/server.d.ts +2 -2
  22. package/dist/server.js +65 -5
  23. package/dist/server.js.map +1 -1
  24. package/dist/tools/audit-accessibility.d.ts +24 -0
  25. package/dist/tools/audit-accessibility.js +8 -1
  26. package/dist/tools/audit-accessibility.js.map +1 -1
  27. package/dist/tools/audit-performance.d.ts +24 -0
  28. package/dist/tools/audit-performance.js +14 -2
  29. package/dist/tools/audit-performance.js.map +1 -1
  30. package/dist/tools/audit-tests.d.ts +62 -0
  31. package/dist/tools/audit-tests.js +209 -0
  32. package/dist/tools/audit-tests.js.map +1 -0
  33. package/dist/tools/bisect-failure.d.ts +42 -0
  34. package/dist/tools/bisect-failure.js +291 -0
  35. package/dist/tools/bisect-failure.js.map +1 -0
  36. package/dist/tools/compare-visual-state.d.ts +24 -0
  37. package/dist/tools/diagnose-flaky.js +20 -3
  38. package/dist/tools/diagnose-flaky.js.map +1 -1
  39. package/dist/tools/generate-e2e-test.js +1 -1
  40. package/dist/tools/generate-e2e-test.js.map +1 -1
  41. package/dist/tools/get-failure.js +11 -2
  42. package/dist/tools/get-failure.js.map +1 -1
  43. package/dist/tools/get-run-status.js +4 -3
  44. package/dist/tools/get-run-status.js.map +1 -1
  45. package/dist/tools/inspect-page.d.ts +24 -0
  46. package/dist/tools/inspect-page.js +9 -5
  47. package/dist/tools/inspect-page.js.map +1 -1
  48. package/dist/tools/list-tests.js +5 -1
  49. package/dist/tools/list-tests.js.map +1 -1
  50. package/dist/tools/probe-script.js +87 -9
  51. package/dist/tools/probe-script.js.map +1 -1
  52. package/dist/tools/run-test.js +3 -2
  53. package/dist/tools/run-test.js.map +1 -1
  54. package/dist/tools/shared.d.ts +23 -1
  55. package/dist/tools/shared.js +91 -26
  56. package/dist/tools/shared.js.map +1 -1
  57. package/dist/tools/structured.d.ts +334 -0
  58. package/dist/tools/structured.js +176 -0
  59. package/dist/tools/structured.js.map +1 -0
  60. package/dist/tools/suggest-fix.js +15 -5
  61. package/dist/tools/suggest-fix.js.map +1 -1
  62. package/dist/tools/validate-selector.d.ts +27 -0
  63. package/dist/tools/validate-selector.js +28 -5
  64. package/dist/tools/validate-selector.js.map +1 -1
  65. package/dist/types/index.d.ts +1 -1
  66. package/dist/types/index.js.map +1 -1
  67. package/dist/utils/attempt-limiter.d.ts +31 -0
  68. package/dist/utils/attempt-limiter.js +58 -0
  69. package/dist/utils/attempt-limiter.js.map +1 -0
  70. package/dist/utils/bisect.d.ts +31 -0
  71. package/dist/utils/bisect.js +47 -0
  72. package/dist/utils/bisect.js.map +1 -0
  73. package/dist/utils/flake-rules.d.ts +46 -0
  74. package/dist/utils/flake-rules.js +327 -0
  75. package/dist/utils/flake-rules.js.map +1 -0
  76. package/dist/utils/locator-expr.d.ts +3 -1
  77. package/dist/utils/locator-expr.js +25 -7
  78. package/dist/utils/locator-expr.js.map +1 -1
  79. package/package.json +5 -4
  80. package/skill/playwright-e2e-mcp/SKILL.md +19 -2
  81. package/skill/playwright-e2e-mcp/references/setup.md +2 -2
  82. package/skill/playwright-e2e-mcp/references/tools.md +34 -1
package/README.md CHANGED
@@ -47,6 +47,8 @@ load-report ───┴─▶ get-failure ──▶ suggest-fix (apply + re-run
47
47
  (CI job report) │ └─ refuses when the element is really gone (app bug)
48
48
  └─ DOM at failure, failed requests, console errors
49
49
  every run ──▶ analyze-history (flaky / broken / slow / which commit broke it)
50
+ test code ──▶ audit-tests (flake risks, ranked by history, verified rewrites)
51
+ red at HEAD ─▶ bisect-failure (runs it across git history, names the breaking commit)
50
52
  ```
51
53
 
52
54
  ## Key features
@@ -59,6 +61,26 @@ every run ──▶ analyze-history (flaky / broken / slow / which commit broke
59
61
  with Playwright MCP plus a shell ([benchmark](#benchmark)).
60
62
  - **Free and open source.** MIT, no account, no API key, no telemetry, no paid tier.
61
63
 
64
+ ## 🚀 What only this MCP does
65
+
66
+ Most testing MCPs let an AI drive a browser: Microsoft's Playwright MCP, Chrome DevTools MCP,
67
+ ExecuteAutomation's mcp-playwright and the Selenium MCP. They're great for clicking through a
68
+ page. None of them, as of October 2026, does the following. This one does:
69
+
70
+ | Capability | What you get |
71
+ | --- | --- |
72
+ | 🎯 **Find the commit that broke a test** | `bisect-failure` runs the test across your git history, in a temporary worktree that leaves your checkout alone, and names the first bad commit with its diff and the failure |
73
+ | 🧪 **Flake-risk audit of your test code** | `audit-tests` finds hard waits, one-shot assertions, missing `await`s and fragile selectors. It ranks them by how flaky those tests really were, then applies the safe rewrites and re-runs them to prove them |
74
+ | ✅ **Fixes that prove themselves** | `suggest-fix` swaps in a locator proven unique on the DOM at failure, re-runs the test and reverts if it's still red. It refuses to patch over a real app bug |
75
+ | 🔬 **Flaky-test verdicts with evidence** | `diagnose-flaky` repeats tests with retries off and tells a race from shared state from **test order**, naming the test it depends on and the seed that reproduces it |
76
+ | 📈 **Memory of every run** | `analyze-history` ranks flaky, regressed and broken tests, groups failures by cause, tracks slow tests and names the commit where each one went bad |
77
+ | 🏗️ **Diagnose CI failures locally** | `load-report` loads a CI job's report and traces (sharded too), so the same diagnosis and verified fixes work on failures from CI |
78
+ | 💬 **One-click fixes on pull requests** | The GitHub Action verifies each fix in CI and posts it as a **suggested change** reviewers apply with one click |
79
+ | ♿⚡ **Audits that hand back tests** | Accessibility (axe-core) and Web Vitals audits return verified locators for each problem plus a ready regression or budget test |
80
+
81
+ It works alongside a browser MCP rather than replacing it: that one drives the page, and this one
82
+ keeps your suite green.
83
+
62
84
  ## What you can ask
63
85
 
64
86
  | | You ask your AI… | It does this |
@@ -78,7 +100,7 @@ every run ──▶ analyze-history (flaky / broken / slow / which commit broke
78
100
 
79
101
  ## Requirements
80
102
 
81
- - Node.js 20 or newer
103
+ - Node.js 22 or newer
82
104
  - A project that uses `@playwright/test`, with a browser installed (`npx playwright install chromium`)
83
105
  - Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, Codex, Gemini CLI or any other MCP client
84
106
 
@@ -90,6 +112,7 @@ other servers alone:
90
112
 
91
113
  ```bash
92
114
  npx -y playwright-e2e-mcp init # --client all | cursor,vscode … · --dry-run
115
+ npx -y playwright-e2e-mcp doctor # checks Node, Playwright, browsers and client setup
93
116
  ```
94
117
 
95
118
  **Or let your agent do it.** Paste this into any coding agent:
@@ -230,9 +253,9 @@ Running and fixing your own tests needs your project, so use the local install f
230
253
  | --- | --- |
231
254
  | Skill only, any agent | `npx skills add xsignon-secure/E2E` |
232
255
  | MCP Registry | `io.github.xsignon-secure/E2E` ([listing](https://registry.modelcontextprotocol.io/)); registry-aware clients find it there |
233
- | Straight from GitHub, no npm | `npx -y github:xsignon-secure/E2E#v0.5.1` (pin a release tag) |
234
- | Release tarball | `npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.5.1/playwright-e2e-mcp-0.5.1.tgz` |
235
- | Docker | `docker run -i --rm -v "$PWD:/work" playwright-e2e-mcp` (see [Development](docs/development.md#docker)) |
256
+ | Straight from GitHub, no npm | `npx -y github:xsignon-secure/E2E#v0.6.1` (pin a release tag) |
257
+ | Release tarball | `npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.6.1/playwright-e2e-mcp-0.6.1.tgz` |
258
+ | Docker | `docker run -i --rm -v "$PWD:/work" ghcr.io/xsignon-secure/playwright-e2e-mcp` (published on each release; see [Development](docs/development.md#docker)) |
236
259
  | Local checkout | `"command": "node", "args": ["/path/to/E2E/dist/index.js"]` |
237
260
 
238
261
  </details>
@@ -248,16 +271,19 @@ Run my Playwright tests and fix whatever fails.
248
271
  Your agent should run the suite, read the failure, and propose a fix it has re-run. To check the
249
272
  setup without your own tests, ask it to run `examples/sample-test.spec.ts` from this repo.
250
273
 
251
- ## What's new in 0.5.0
274
+ ## What's new in 0.6
252
275
 
253
- - **Diagnose CI failures:** `load-report` reads a CI job's report (or sharded blob reports)
254
- and its traces, so the same diagnosis and verified fixes work on failures from CI.
255
- - **Know which commit broke a test:** `analyze-history` adds `commits`, `slow` and `trend` views.
256
- - **Write tests by walking the flow:** `generate-e2e-test` with `steps` runs them on the live
257
- page, writes the spec with end-state assertions, and runs it once to prove it passes.
258
- - **Performance audits:** `audit-performance` measures Web Vitals and hands back a budget test.
259
- - **More page control:** aria snapshots with ready `toMatchAriaSnapshot` assertions, network
260
- mocks, HAR record/replay, and Chromium, Firefox or WebKit.
276
+ - **Find the commit that broke a test:** `bisect-failure` runs the test across git history in a
277
+ temporary worktree and names the first bad commit, its changes and the failure there.
278
+ - **Flake-risk audit:** `audit-tests` finds hard waits, one-shot assertions, missing `await`s and
279
+ fragile selectors, ranked by real flakiness, and applies the safe rewrites with a verifying run.
280
+ - **One-click fixes on pull requests:** the GitHub Action proves each fix in CI and posts it as a
281
+ suggested change.
282
+ - **`doctor`:** `npx playwright-e2e-mcp doctor` checks Node, Playwright, browsers and client setup.
283
+ - **Structured results:** every tool returns JSON next to its Markdown, with output schemas.
284
+ - **Phones, tablets, Chrome and Edge:** `device` presets and `channel` for every page tool, and a
285
+ Docker image on `ghcr.io`.
286
+ - **Node 22 or newer** is now required, and the hosted endpoint limits guessing of its key.
261
287
 
262
288
  [All release notes](https://github.com/xsignon-secure/E2E/releases)
263
289
 
@@ -279,6 +305,8 @@ setup without your own tests, ask it to run `examples/sample-test.spec.ts` from
279
305
  | `audit-performance` | Measure lab **Web Vitals** (LCP, CLS, TBT, FCP, TTFB, INP during steps), optionally as a throttled phone and the median of several runs; rate them or check budgets, name the LCP and shifting elements as verified locators, list heavy and render-blocking requests, and return a budget test |
280
306
  | `diagnose-flaky` | Run a failing test 2–10 times **with retries disabled** and return an evidence verdict: `CONSISTENTLY FAILING`, `FLAKY` or `NOT REPRODUCING`; tells parallelism and **test-order** bugs from races |
281
307
  | `analyze-history` | Rank flaky, regressed and broken tests from the local run history, group failures by cause, list the slowest tests, show stability by day, name **the commit where each test went bad**, or show one test's timeline |
308
+ | `audit-tests` | Audit the **test code** for flake risks (hard waits, one-shot assertions instead of web-first ones, missing `await`s, `.only`, force clicks, `networkidle`, element handles, layout selectors), ranked by how flaky those tests have been in the run history; `fix: true` rewrites the mechanical ones, re-runs the files and reverts if they fail |
309
+ | `bisect-failure` | **Find the commit that broke a test**: binary-search git history between a good and a bad commit, running the test at each step in a temporary worktree (your checkout is untouched), and report the first bad commit, what it changed and how the test failed |
282
310
 
283
311
  Two **prompts** package the main workflows for clients that show them as slash commands:
284
312
  `fix-failing-test` and `triage-flaky-tests`.
@@ -333,26 +361,29 @@ npx -y playwright-e2e-mcp ci --help
333
361
  ```
334
362
 
335
363
  As a GitHub Action, it adds the report to the job summary and keeps one PR
336
- comment up to date when the run fails:
364
+ comment up to date when the run fails. On a pull request it also re-runs each
365
+ failing test with its suggested fix and posts the fixes that pass as **suggested
366
+ changes** on the failing lines, so a reviewer applies one with the **Commit
367
+ suggestion** button (only on lines the PR changed; the rest stay in the report):
337
368
 
338
369
  ```yaml
339
370
  permissions:
340
371
  contents: read
341
- pull-requests: write # only for the PR comment
372
+ pull-requests: write # for the PR comment and the suggested fixes
342
373
  steps:
343
374
  - uses: actions/checkout@v6
344
375
  - uses: actions/setup-node@v6
345
376
  with: { node-version: 24 }
346
377
  - run: npm ci && npx playwright install --with-deps chromium
347
- - uses: xsignon-secure/E2E@v0.5.1
378
+ - uses: xsignon-secure/E2E@v0.6.1
348
379
  with:
349
380
  flaky-runs: 3 # 0 skips the flaky verdict
350
381
  suggest: 2 # suggest-fix diffs for the first 2 failures
351
382
  # args: --browser chromium tests/checkout
352
383
  ```
353
384
 
354
- Inputs: `project-root`, `args`, `flaky-runs`, `suggest`, `comment`,
355
- `fail-on-failure`, `version`, `github-token`. Outputs: `exit-code`, `report`.
385
+ Inputs: `project-root`, `args`, `flaky-runs`, `suggest`, `comment`, `review`,
386
+ `verify-fixes`, `fail-on-failure`, `version`, `github-token`. Outputs: `exit-code`, `report`.
356
387
 
357
388
  ## Configuration
358
389
 
@@ -362,13 +393,17 @@ Inputs: `project-root`, `args`, `flaky-runs`, `suggest`, `comment`,
362
393
  | Environment variable | Default | Purpose |
363
394
  | --- | --- | --- |
364
395
  | `PW_MCP_PROJECT_ROOT` | server cwd | Default project root for every tool |
365
- | `PW_MCP_TOOLS` | all | Which tools to expose, as tool names and/or profiles, comma separated (same as the `--tools=` flag). Profiles: `core` (run, status, failure, fix, flaky, list), `triage` (run, status, failure, CI report, flaky, history, list), `inspect` (page, selector, accessibility, performance, visual), `author` (list, page, selector, generate, run). All fourteen tool definitions cost about 9k tokens of context per request; `core` costs about 2.3k |
396
+ | `PW_MCP_TOOLS` | all | Which tools to expose, as tool names and/or profiles, comma separated (same as the `--tools=` flag). Profiles: `core` (run, status, failure, fix, flaky, list), `triage` (run, status, failure, CI report, flaky, history, test audit, bisect, list), `inspect` (page, selector, accessibility, performance, visual), `author` (list, page, selector, generate, run). All sixteen tool definitions cost about 12k tokens of context per request; `core` costs about 4k (10k and 2.3k with `PW_MCP_OUTPUT_SCHEMAS=0`) |
397
+ | `PW_MCP_OUTPUT_SCHEMAS` | on | `0` leaves the output schemas out of the tool list to save context. Results still carry `structuredContent` (see [Structured results](docs/tools.md#structured-results)) |
366
398
  | `PW_MCP_STORAGE_STATE` | — | Default `storageState` file (inside the project) for the page tools |
367
399
  | `PW_MCP_SHUFFLE_SEEDS` | random | Comma-separated seeds for `diagnose-flaky`'s `order` pass, to replay the orders a diagnosis reported |
368
400
  | `PW_MCP_HISTORY` | on | `0` stops recording runs to `.playwright-e2e-mcp/history.jsonl` |
369
401
  | `PW_MCP_ALLOWED_ROOTS` | — | Extra directories a caller may pass as `projectRoot` (`:`-separated, `;` on Windows). Anything outside these and the default root is rejected |
370
- | `PW_MCP_HTTP_TOKEN` | — | HTTP bridge only: bearer token (16+ characters) that unlocks all tools (see [Hosted endpoint](docs/hosted-endpoint.md)) |
402
+ | `PW_MCP_HTTP_TOKEN` | — | HTTP bridge only: bearer token that unlocks all tools: 16+ characters, 32+ recommended (see [Hosted endpoint](docs/hosted-endpoint.md)) |
371
403
  | `PW_MCP_ALLOWED_HOSTS` | localhost + Vercel hostnames when there is no token | HTTP bridge only: comma-separated `Host` allowlist; `*` accepts any |
404
+ | `PW_MCP_MAX_FAILED_AUTH` | `20` | HTTP bridge only: wrong tokens or access keys one client address may send in 15 minutes before it gets `429` |
405
+ | `PW_MCP_OAUTH_REDIRECT_HOSTS` | any https host | HTTP bridge only: comma-separated hosts OAuth apps may return to, e.g. `claude.ai,chatgpt.com`; `.example.com` covers subdomains; localhost always works |
406
+ | `PW_MCP_TRUST_PROXY` | off (on for Vercel) | HTTP bridge only: `1` trusts `X-Real-IP` / `X-Forwarded-For` from a reverse proxy in front, so the sign-in limit counts per client, not per proxy |
372
407
  | `PW_MCP_PASSTHROUGH_ENV` | — | HTTP bridge only: comma-separated extra variables passed to test runs (e.g. `BASE_URL`) |
373
408
  | `PW_MCP_MAX_CHILDREN` | `4` | HTTP bridge only: how many test runs and browser probes may run at once |
374
409
  | `PW_MCP_BLOCK_PRIVATE_URLS` | off (on for the HTTP bridge) | `1` makes the URL tools refuse loopback, private-network and cloud-metadata addresses, including redirects and subresources |
package/dist/cli/ci.d.ts CHANGED
@@ -21,9 +21,14 @@ export interface CiOptions {
21
21
  flakyRuns?: number;
22
22
  suggest: number;
23
23
  output?: string;
24
+ verifyFixes: boolean;
25
+ suggestions?: string;
26
+ review: boolean;
24
27
  testFiles: string[];
25
28
  }
26
29
  /** Parse `ci` arguments (everything after the subcommand). Throws on bad input. */
27
30
  export declare function parseCiArgs(argv: string[]): CiOptions;
31
+ /** A project-relative file as a repository-relative posix path, or undefined outside the repository. */
32
+ export declare function repoPath(projectRoot: string, file: string, repoRoot: string): string | undefined;
28
33
  /** Run the CI flow; returns the exit code. */
29
34
  export declare function runCi(argv: string[]): Promise<number>;
package/dist/cli/ci.js CHANGED
@@ -9,13 +9,15 @@
9
9
  * Exit codes: 0 all passed (flaky allowed), 1 tests failed, 2 the run
10
10
  * itself failed (no Playwright, config error, timeout) or bad arguments.
11
11
  */
12
- import { appendFile, writeFile } from 'node:fs/promises';
12
+ import { appendFile, readFile, writeFile } from 'node:fs/promises';
13
+ import path from 'node:path';
13
14
  import { parseArgs } from 'node:util';
14
15
  import { createLogger } from '../utils/logger.js';
15
16
  import { createToolStore } from '../tools/shared.js';
16
17
  import { runTestTool } from '../tools/run-test.js';
17
18
  import { diagnoseFlakyTool } from '../tools/diagnose-flaky.js';
18
19
  import { suggestFixTool } from '../tools/suggest-fix.js';
20
+ import { postSuggestionReview, pullRequestFromEnv } from './review.js';
19
21
  export const CI_USAGE = [
20
22
  'Usage: playwright-e2e-mcp ci [options] [test files…]',
21
23
  '',
@@ -32,6 +34,10 @@ export const CI_USAGE = [
32
34
  ' --flaky-runs <n> repeat failing tests n times (2-10) for a flaky verdict',
33
35
  ' --suggest <n> draft suggest-fix diffs for the first n failures (max 5)',
34
36
  ' --output <file> also write the report to this file (for a PR comment)',
37
+ ' --verify-fixes apply each suggested fix, re-run its test, then restore the file',
38
+ ' --suggestions <file> write the suggested fixes as JSON (repository-relative paths)',
39
+ ' --review on a GitHub pull request, post the fixes as suggested changes',
40
+ ' (needs GITHUB_TOKEN or GH_TOKEN with pull-requests: write)',
35
41
  '',
36
42
  ].join('\n');
37
43
  function intOption(value, name, min, max) {
@@ -59,6 +65,9 @@ export function parseCiArgs(argv) {
59
65
  'flaky-runs': { type: 'string' },
60
66
  suggest: { type: 'string' },
61
67
  output: { type: 'string' },
68
+ 'verify-fixes': { type: 'boolean' },
69
+ suggestions: { type: 'string' },
70
+ review: { type: 'boolean' },
62
71
  },
63
72
  });
64
73
  const browser = values.browser;
@@ -76,12 +85,35 @@ export function parseCiArgs(argv) {
76
85
  flakyRuns: intOption(values['flaky-runs'], 'flaky-runs', 2, 10),
77
86
  suggest: intOption(values.suggest, 'suggest', 0, 5) ?? 0,
78
87
  output: values.output,
88
+ verifyFixes: values['verify-fixes'] === true,
89
+ suggestions: values.suggestions,
90
+ review: values.review === true,
79
91
  testFiles: positionals,
80
92
  };
81
93
  }
82
94
  function text(response) {
83
95
  return response.content.map((block) => block.text).join('\n');
84
96
  }
97
+ function structured(response) {
98
+ return response.structuredContent;
99
+ }
100
+ /** Put the original line back after a verification run applied a fix. */
101
+ async function restoreLine(file, line, before, after) {
102
+ const source = await readFile(file, 'utf8');
103
+ const eol = source.includes('\r\n') ? '\r\n' : '\n';
104
+ const lines = source.split(/\r?\n/);
105
+ if (lines[line - 1] !== after)
106
+ return;
107
+ lines[line - 1] = before;
108
+ await writeFile(file, lines.join(eol), 'utf8');
109
+ }
110
+ /** A project-relative file as a repository-relative posix path, or undefined outside the repository. */
111
+ export function repoPath(projectRoot, file, repoRoot) {
112
+ const relative = path.relative(path.resolve(repoRoot), path.resolve(projectRoot, file));
113
+ if (relative === '' || relative.startsWith('..') || path.isAbsolute(relative))
114
+ return undefined;
115
+ return relative.split(path.sep).join('/');
116
+ }
85
117
  /** Run the CI flow; returns the exit code. */
86
118
  export async function runCi(argv) {
87
119
  let options;
@@ -116,12 +148,72 @@ export async function runCi(argv) {
116
148
  const result = ctx.store.lastRun?.result;
117
149
  const failures = result?.failures ?? [];
118
150
  let code = result === undefined || run.isError ? 2 : result.ok ? 0 : failures.length > 0 ? 1 : 2;
119
- if (code === 1 && options.suggest > 0) {
151
+ const fixes = [];
152
+ const suggest = options.review || options.suggestions ? Math.max(options.suggest, 1) : options.suggest;
153
+ if (code === 1 && suggest > 0 && ctx.store.lastRun) {
120
154
  // Before diagnose-flaky, which replaces the last run suggest-fix indexes into.
121
- const count = Math.min(options.suggest, ctx.store.lastRun?.result.failures.length ?? 0);
155
+ // A verification run replaces it too, so each fix starts from the suite run.
156
+ const suiteRun = ctx.store.lastRun;
157
+ const count = Math.min(suggest, suiteRun.result.failures.length);
122
158
  for (let index = 1; index <= count; index += 1) {
123
- const fix = await suggestFixTool.handler({ index, config: options.config }, ctx);
124
- sections.push(text(fix).replace(/^## /m, '### '));
159
+ ctx.store.setLastRun(suiteRun);
160
+ const response = await suggestFixTool.handler({ index, config: options.config }, ctx);
161
+ let section = text(response).replace(/^## /m, '### ');
162
+ const fix = structured(response)?.fix;
163
+ let verified = false;
164
+ if (fix && options.verifyFixes) {
165
+ ctx.store.setLastRun(suiteRun);
166
+ const trial = await suggestFixTool.handler({ index, config: options.config, apply: true, allowExpectationUpdate: true }, ctx);
167
+ verified = structured(trial)?.verified === true;
168
+ // A passing fix stays written by suggest-fix; CI only reports it.
169
+ if (verified)
170
+ await restoreLine(path.resolve(projectRoot, fix.file), fix.line, fix.before, fix.after);
171
+ section += verified
172
+ ? '\n\n✅ **Verified in CI:** the test passes with this change.'
173
+ : '\n\n⚠️ **Not verified:** the test still failed with this change in CI.';
174
+ }
175
+ sections.push(section);
176
+ const failure = suiteRun.result.failures[index - 1];
177
+ const target = fix ? repoPath(projectRoot, fix.file, process.env.GITHUB_WORKSPACE ?? projectRoot) : undefined;
178
+ if (fix && target && (verified || !options.verifyFixes)) {
179
+ fixes.push({
180
+ path: target,
181
+ line: fix.line,
182
+ before: fix.before,
183
+ after: fix.after,
184
+ kind: fix.kind,
185
+ confidence: fix.confidence,
186
+ why: fix.why,
187
+ verified,
188
+ test: failure?.title ?? fix.file,
189
+ });
190
+ }
191
+ }
192
+ ctx.store.setLastRun(suiteRun);
193
+ }
194
+ if (options.suggestions) {
195
+ try {
196
+ await writeFile(options.suggestions, `${JSON.stringify(fixes, null, 2)}\n`, 'utf8');
197
+ }
198
+ catch (err) {
199
+ process.stderr.write(`could not write the suggestions: ${err.message}\n`);
200
+ }
201
+ }
202
+ if (options.review && fixes.length > 0) {
203
+ const pr = await pullRequestFromEnv();
204
+ if (!pr) {
205
+ process.stderr.write('--review: not a pull_request run, or no GITHUB_TOKEN/GH_TOKEN; fixes stay in the report.\n');
206
+ }
207
+ else {
208
+ const review = await postSuggestionReview(fixes, pr);
209
+ if (review.error)
210
+ process.stderr.write(`::warning::Could not post suggested fixes: ${review.error}\n`);
211
+ else if (review.posted.length > 0) {
212
+ sections.push(`💡 Posted ${review.posted.length === 1 ? 'a suggested change' : `${review.posted.length} suggested changes`} on this PR: use **Commit suggestion** to apply.`);
213
+ }
214
+ if (review.outsideDiff.length > 0) {
215
+ process.stderr.write(`${review.outsideDiff.length} fix(es) are on lines this PR did not change, so they are only in the report.\n`);
216
+ }
125
217
  }
126
218
  }
127
219
  if (code === 1 && options.flakyRuns) {
@@ -1 +1 @@
1
- {"version":3,"file":"ci.js","sourceRoot":"","sources":["../../src/cli/ci.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ci.js","sourceRoot":"","sources":["../../src/cli/ci.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `playwright-e2e-mcp doctor`: checks the things a first run usually trips
3
+ * on and says how to fix each one: Node version, the Playwright config and
4
+ * install, installed browsers, test files, and whether the server and the
5
+ * agent skill are wired into the project's MCP clients.
6
+ *
7
+ * It only reads: nothing is installed or written.
8
+ *
9
+ * Exit codes: 0 nothing failed (warnings allowed), 1 a check failed,
10
+ * 2 bad arguments.
11
+ */
12
+ export declare const DOCTOR_USAGE: string;
13
+ /** Oldest Node major the server supports. */
14
+ export declare const MIN_NODE_MAJOR = 22;
15
+ export type CheckStatus = 'ok' | 'warn' | 'fail';
16
+ export interface DoctorCheck {
17
+ name: string;
18
+ status: CheckStatus;
19
+ detail: string;
20
+ /** What to run or change; present for warn and fail. */
21
+ fix?: string;
22
+ }
23
+ export interface DoctorReport {
24
+ version: string;
25
+ projectRoot: string;
26
+ checks: DoctorCheck[];
27
+ ok: boolean;
28
+ }
29
+ export declare function runDoctorChecks(projectRoot: string, home?: string): Promise<DoctorReport>;
30
+ export declare function renderDoctorReport(report: DoctorReport): string;
31
+ export declare function runDoctor(argv: string[], out?: (text: string) => void): Promise<number>;
@@ -0,0 +1,200 @@
1
+ /**
2
+ * `playwright-e2e-mcp doctor`: checks the things a first run usually trips
3
+ * on and says how to fix each one: Node version, the Playwright config and
4
+ * install, installed browsers, test files, and whether the server and the
5
+ * agent skill are wired into the project's MCP clients.
6
+ *
7
+ * It only reads: nothing is installed or written.
8
+ *
9
+ * Exit codes: 0 nothing failed (warnings allowed), 1 a check failed,
10
+ * 2 bad arguments.
11
+ */
12
+ import { existsSync, readFileSync } from 'node:fs';
13
+ import { createRequire } from 'node:module';
14
+ import os from 'node:os';
15
+ import path from 'node:path';
16
+ import { parseArgs } from 'node:util';
17
+ import { detectProject, findTestFiles } from '../utils/project-detector.js';
18
+ import { SERVER_VERSION } from '../server.js';
19
+ import { SERVER_NAME, SKILL_NAME } from './init.js';
20
+ export const DOCTOR_USAGE = [
21
+ 'Usage: playwright-e2e-mcp doctor [options]',
22
+ '',
23
+ 'Checks Node, the Playwright config and install, browsers, test files and the',
24
+ 'MCP client setup, and says how to fix anything missing. Reads only.',
25
+ '',
26
+ ' --project-root <dir> project directory (default: cwd)',
27
+ ' --json print the checks as JSON',
28
+ '',
29
+ ].join('\n');
30
+ /** Oldest Node major the server supports. */
31
+ export const MIN_NODE_MAJOR = 22;
32
+ /** Where each client keeps its project-scoped MCP config (see init). */
33
+ function clientConfigs(root, home) {
34
+ return [
35
+ { client: 'Claude Code', file: path.join(root, '.mcp.json') },
36
+ { client: 'Cursor', file: path.join(root, '.cursor', 'mcp.json') },
37
+ { client: 'VS Code', file: path.join(root, '.vscode', 'mcp.json') },
38
+ { client: 'Gemini CLI', file: path.join(root, '.gemini', 'settings.json') },
39
+ { client: 'Codex', file: path.join(root, '.codex', 'config.toml') },
40
+ { client: 'Windsurf', file: path.join(home, '.codeium', 'windsurf', 'mcp_config.json') },
41
+ ];
42
+ }
43
+ function mentionsServer(file) {
44
+ try {
45
+ const text = readFileSync(file, 'utf8');
46
+ return text.includes(`"${SERVER_NAME}"`) || text.includes(`mcp_servers.${SERVER_NAME}`) || text.includes('playwright-e2e-mcp');
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ }
52
+ function nodeCheck(version = process.versions.node) {
53
+ const major = Number(version.split('.')[0]);
54
+ if (major >= MIN_NODE_MAJOR)
55
+ return { name: 'Node.js', status: 'ok', detail: `v${version}` };
56
+ return {
57
+ name: 'Node.js',
58
+ status: 'fail',
59
+ detail: `v${version} is older than the supported ${MIN_NODE_MAJOR}`,
60
+ fix: `Install Node.js ${MIN_NODE_MAJOR} or newer (https://nodejs.org)`,
61
+ };
62
+ }
63
+ /** Each browser's install state, read through the project's own Playwright. */
64
+ function browserChecks(root, playwrightPackage) {
65
+ let pw;
66
+ try {
67
+ pw = createRequire(path.join(root, 'package.json'))(playwrightPackage);
68
+ }
69
+ catch (err) {
70
+ return [
71
+ {
72
+ name: 'Browsers',
73
+ status: 'fail',
74
+ detail: `could not load ${playwrightPackage}: ${err.message.split('\n')[0]}`,
75
+ fix: 'Reinstall dependencies (npm install), then npx playwright install chromium',
76
+ },
77
+ ];
78
+ }
79
+ const installed = [];
80
+ const missing = [];
81
+ for (const name of ['chromium', 'firefox', 'webkit']) {
82
+ let executable = '';
83
+ try {
84
+ executable = pw[name]?.executablePath() ?? '';
85
+ }
86
+ catch {
87
+ executable = '';
88
+ }
89
+ (executable && existsSync(executable) ? installed : missing).push(name);
90
+ }
91
+ if (!installed.includes('chromium')) {
92
+ return [
93
+ {
94
+ name: 'Browsers',
95
+ status: 'fail',
96
+ detail: installed.length ? `Chromium is missing (installed: ${installed.join(', ')})` : 'no browsers installed for this Playwright version',
97
+ fix: 'npx playwright install chromium',
98
+ },
99
+ ];
100
+ }
101
+ return [{ name: 'Browsers', status: 'ok', detail: `installed: ${installed.join(', ')}${missing.length ? ` (not installed: ${missing.join(', ')})` : ''}` }];
102
+ }
103
+ export async function runDoctorChecks(projectRoot, home = os.homedir()) {
104
+ const checks = [nodeCheck()];
105
+ const detection = await detectProject(projectRoot);
106
+ const root = detection.root;
107
+ if (!detection.configPath) {
108
+ checks.push({
109
+ name: 'Playwright config',
110
+ status: 'fail',
111
+ detail: `no playwright.config.* in ${projectRoot} or its parents`,
112
+ fix: 'Run this in your Playwright project, or create one with npm init playwright@latest',
113
+ });
114
+ }
115
+ else if (detection.configCandidates.length > 1) {
116
+ checks.push({
117
+ name: 'Playwright config',
118
+ status: 'warn',
119
+ detail: `${detection.configCandidates.length} configs in ${root}; tools use ${path.basename(detection.configPath)} unless told otherwise`,
120
+ fix: 'Pass the config you mean to run-test, or keep one config per folder',
121
+ });
122
+ }
123
+ else {
124
+ checks.push({ name: 'Playwright config', status: 'ok', detail: path.relative(projectRoot, detection.configPath) || detection.configPath });
125
+ }
126
+ if (!detection.hasPlaywright || !detection.playwrightPackage) {
127
+ checks.push({
128
+ name: 'Playwright',
129
+ status: 'fail',
130
+ detail: 'neither @playwright/test nor playwright is installed in node_modules',
131
+ fix: 'npm install -D @playwright/test',
132
+ });
133
+ }
134
+ else {
135
+ checks.push({ name: 'Playwright', status: 'ok', detail: `${detection.playwrightPackage} ${detection.playwrightVersion ?? '(unknown version)'}` });
136
+ checks.push(...browserChecks(root, detection.playwrightPackage));
137
+ }
138
+ if (detection.configPath) {
139
+ const files = await findTestFiles(root, { testDir: detection.testDir, limit: 1000 });
140
+ checks.push(files.length
141
+ ? { name: 'Test files', status: 'ok', detail: `${files.length}${files.length >= 1000 ? '+' : ''} found` }
142
+ : {
143
+ name: 'Test files',
144
+ status: 'warn',
145
+ detail: `none found under ${detection.testDir ? path.relative(root, detection.testDir) || '.' : 'the project'}`,
146
+ fix: 'Add a *.spec.ts file, or ask your agent to write one with generate-e2e-test',
147
+ });
148
+ }
149
+ const configured = clientConfigs(projectRoot, home).filter(({ file }) => mentionsServer(file));
150
+ checks.push(configured.length
151
+ ? { name: 'MCP clients', status: 'ok', detail: `set up for ${configured.map((c) => c.client).join(', ')}` }
152
+ : {
153
+ name: 'MCP clients',
154
+ status: 'warn',
155
+ detail: 'no project config for Claude Code, Cursor, VS Code, Gemini CLI, Codex or Windsurf mentions the server',
156
+ fix: 'npx -y playwright-e2e-mcp init (or add it in your client by hand; see the README)',
157
+ });
158
+ const skill = [path.join(projectRoot, '.agents', 'skills', SKILL_NAME), path.join(projectRoot, '.claude', 'skills', SKILL_NAME)].find((dir) => existsSync(path.join(dir, 'SKILL.md')));
159
+ checks.push(skill
160
+ ? { name: 'Agent skill', status: 'ok', detail: path.relative(projectRoot, skill) }
161
+ : { name: 'Agent skill', status: 'warn', detail: 'not installed in this project', fix: 'npx -y playwright-e2e-mcp init' });
162
+ return { version: SERVER_VERSION, projectRoot, checks, ok: !checks.some((c) => c.status === 'fail') };
163
+ }
164
+ const MARK = { ok: '✓', warn: '!', fail: '✗' };
165
+ export function renderDoctorReport(report) {
166
+ const width = Math.max(...report.checks.map((c) => c.name.length));
167
+ const lines = [`playwright-e2e-mcp ${report.version} doctor: ${report.projectRoot}`, ''];
168
+ for (const check of report.checks) {
169
+ lines.push(`${MARK[check.status]} ${check.name.padEnd(width)} ${check.detail}`);
170
+ if (check.fix)
171
+ lines.push(` ${' '.repeat(width)} fix: ${check.fix}`);
172
+ }
173
+ const failed = report.checks.filter((c) => c.status === 'fail').length;
174
+ const warned = report.checks.filter((c) => c.status === 'warn').length;
175
+ lines.push('');
176
+ lines.push(failed
177
+ ? `${failed} problem${failed === 1 ? '' : 's'} to fix before the tools can run your tests.`
178
+ : warned
179
+ ? `Ready, with ${warned} suggestion${warned === 1 ? '' : 's'} above.`
180
+ : 'Everything is ready.');
181
+ return `${lines.join('\n')}\n`;
182
+ }
183
+ export async function runDoctor(argv, out = (t) => process.stdout.write(t)) {
184
+ let values;
185
+ try {
186
+ ({ values } = parseArgs({
187
+ args: argv,
188
+ strict: true,
189
+ options: { 'project-root': { type: 'string' }, json: { type: 'boolean' } },
190
+ }));
191
+ }
192
+ catch (err) {
193
+ out(`doctor: ${err.message}\n\n${DOCTOR_USAGE}`);
194
+ return 2;
195
+ }
196
+ const report = await runDoctorChecks(path.resolve(values['project-root'] ?? '.'));
197
+ out(values.json ? `${JSON.stringify(report, null, 2)}\n` : renderDoctorReport(report));
198
+ return report.ok ? 0 : 1;
199
+ }
200
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"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"}
package/dist/cli/init.js CHANGED
@@ -213,7 +213,8 @@ export function runInit(argv, out = (l) => process.stdout.write(`${l}\n`)) {
213
213
  }
214
214
  out('');
215
215
  out('Next: make sure browsers are installed (npx playwright install chromium), then');
216
- out('restart or reload the agent so it picks up the new server.');
216
+ out('restart or reload the agent so it picks up the new server. Check the setup any');
217
+ out('time with: npx -y playwright-e2e-mcp doctor');
217
218
  return changes.some((c) => c.action === 'error') ? 1 : 0;
218
219
  }
219
220
  //# sourceMappingURL=init.js.map