playwright-e2e-mcp 0.2.2 → 0.3.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.
- package/README.md +255 -35
- package/dist/cli/ci.d.ts +29 -0
- package/dist/cli/ci.js +145 -0
- package/dist/cli/ci.js.map +1 -0
- package/dist/cli/init.d.ts +40 -0
- package/dist/cli/init.js +218 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +27 -2
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +15 -0
- package/dist/server.js +54 -2
- package/dist/server.js.map +1 -1
- package/dist/tools/diagnose-flaky.d.ts +42 -4
- package/dist/tools/diagnose-flaky.js +342 -98
- package/dist/tools/diagnose-flaky.js.map +1 -1
- package/dist/types/index.d.ts +29 -0
- package/dist/utils/attempts-reporter.d.ts +19 -0
- package/dist/utils/attempts-reporter.js +96 -0
- package/dist/utils/attempts-reporter.js.map +1 -0
- package/dist/utils/playwright-runner.js +16 -1
- package/dist/utils/playwright-runner.js.map +1 -1
- package/dist/utils/report-parser.d.ts +1 -0
- package/dist/utils/report-parser.js +1 -1
- package/dist/utils/report-parser.js.map +1 -1
- package/package.json +18 -6
- package/skill/README.md +34 -0
- package/skill/playwright-e2e-mcp/SKILL.md +196 -0
- package/skill/playwright-e2e-mcp/references/example-session.md +53 -0
- package/skill/playwright-e2e-mcp/references/failure-kinds.md +32 -0
- package/skill/playwright-e2e-mcp/references/setup.md +120 -0
- package/skill/playwright-e2e-mcp/references/tools.md +161 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: playwright-e2e-mcp
|
|
3
|
+
description: Runs, debugs and fixes Playwright end-to-end tests through the playwright-e2e-mcp server, using structured run results, trace-based failure diagnostics, verified locators, self-healing fixes that re-run and revert if still red, per-test flaky verdicts that separate parallelism bugs from races, signed-in page inspection and local run history. Use when the user asks to run Playwright tests, fix a failing or broken e2e test, find out why a test is flaky or which tests are unstable, repair a selector that no longer matches, write a new Playwright test, or check a page for visual regressions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Playwright E2E with playwright-e2e-mcp
|
|
7
|
+
|
|
8
|
+
This skill drives the `playwright-e2e-mcp` MCP server. The server runs Playwright
|
|
9
|
+
for you and returns structured results instead of raw terminal output: pass/fail
|
|
10
|
+
stats, each failure with `file:line`, a failure kind, the DOM at the moment of
|
|
11
|
+
failure (read from the Playwright trace), failed network requests, console errors
|
|
12
|
+
and concrete next steps. It can also propose and apply a verified fix for a broken
|
|
13
|
+
locator, inspect pages behind a login, run long suites in the background and keep
|
|
14
|
+
a local history of every run.
|
|
15
|
+
|
|
16
|
+
This skill is written for playwright-e2e-mcp 0.3.0 and works with 0.2.0 or
|
|
17
|
+
newer. If `suggest-fix`, `get-run-status` or `analyze-history` is missing, the
|
|
18
|
+
server is older than 0.2.0: use the steps that do not need those tools and tell
|
|
19
|
+
the user to update it. `diagnose-flaky`'s per-test table and `isolate` option
|
|
20
|
+
arrived in 0.3.0.
|
|
21
|
+
|
|
22
|
+
## Before you start
|
|
23
|
+
|
|
24
|
+
1. Check that the server's tools are available. They are named `run-test`,
|
|
25
|
+
`get-run-status`, `get-failure`, `suggest-fix`, `inspect-page`,
|
|
26
|
+
`validate-selector`, `list-tests`, `generate-e2e-test`,
|
|
27
|
+
`compare-visual-state`, `diagnose-flaky` and `analyze-history` (your client
|
|
28
|
+
may prefix them, e.g. `mcp__playwright-e2e__run-test`).
|
|
29
|
+
2. If they are all missing, stop and tell the user the MCP server is not
|
|
30
|
+
connected. Point them to `references/setup.md` for the one-line install for
|
|
31
|
+
their client. Do not fall back to shelling out to `npx playwright test` unless
|
|
32
|
+
the user asks. If only some are missing, the server may run a smaller tool
|
|
33
|
+
profile (`--tools=core` exposes `run-test`, `get-run-status`, `get-failure`,
|
|
34
|
+
`suggest-fix`, `diagnose-flaky` and `list-tests`); work with what is there and
|
|
35
|
+
mention the profile when a task needs a page tool.
|
|
36
|
+
3. Every tool except `get-run-status` takes an optional `projectRoot`. Leave it
|
|
37
|
+
out unless the user works in a sub-project; the server defaults to `PW_MCP_PROJECT_ROOT` or its working
|
|
38
|
+
directory, and rejects any root outside its allowed roots.
|
|
39
|
+
4. If the client offers the server's prompts as slash commands,
|
|
40
|
+
`/fix-failing-test` and `/triage-flaky-tests` start the two main workflows
|
|
41
|
+
below.
|
|
42
|
+
|
|
43
|
+
## The core loop: fix a failing test
|
|
44
|
+
|
|
45
|
+
Follow these steps in order. Do not edit code before step 3.
|
|
46
|
+
|
|
47
|
+
1. **Run.** Call `run-test` with the narrowest scope you know:
|
|
48
|
+
`{ "testFiles": ["tests/checkout.spec.ts"] }`, or `file:line`, or `grep`.
|
|
49
|
+
Omit `testFiles` only when the user asks for the whole suite. Failing tests are
|
|
50
|
+
retried once by default, so a test that passes on retry is reported as
|
|
51
|
+
**flaky**, not failed. For a long suite pass `background: true` and poll
|
|
52
|
+
`get-run-status` with `waitSeconds: 30`.
|
|
53
|
+
2. **Read the failure.** For each failure, call `get-failure` with its 1-based
|
|
54
|
+
`index`. Read the message and code frame, expected vs actual, the failure kind,
|
|
55
|
+
the DOM snapshot at failure, the failed action and its selector, failed network
|
|
56
|
+
requests and console errors.
|
|
57
|
+
3. **Decide what is wrong** using the failure kind (see
|
|
58
|
+
`references/failure-kinds.md`):
|
|
59
|
+
- `server-unreachable` / `SERVER_NOT_RUNNING`: the app is not running. Tell the
|
|
60
|
+
user to start the dev server, or suggest `webServer` in the Playwright config.
|
|
61
|
+
Do not edit tests.
|
|
62
|
+
- A locator or selector in the message, or "0 elements": call `suggest-fix`
|
|
63
|
+
with the same `index`. If it returns a diff with `high` confidence, call it
|
|
64
|
+
again with `apply: true`; it re-runs the test and reverts if still red. If it
|
|
65
|
+
says the element is missing, treat it as an app bug and report the evidence.
|
|
66
|
+
Otherwise go to the selector loop below.
|
|
67
|
+
- `assertion` with a sensible selector: compare expected vs actual and the DOM
|
|
68
|
+
snapshot. Decide whether the app regressed or the test expectation is stale,
|
|
69
|
+
and say which before changing anything.
|
|
70
|
+
- `timeout`: check the DOM snapshot and failed requests for a slow or failed
|
|
71
|
+
API call before raising any timeout.
|
|
72
|
+
- Failed network request (4xx/5xx/no response) right before the failure: the
|
|
73
|
+
backend is the likely cause; report it.
|
|
74
|
+
4. **Fix** the spec or the app code, the smallest change that addresses the cause.
|
|
75
|
+
5. **Re-run only what failed:** `run-test` with `{ "lastFailed": true }`. Repeat
|
|
76
|
+
from step 2 until green.
|
|
77
|
+
|
|
78
|
+
## Selector loop: a locator no longer matches
|
|
79
|
+
|
|
80
|
+
1. `inspect-page` with the page URL and `view: "locators"`
|
|
81
|
+
(e.g. `{ "url": "http://localhost:3000/checkout", "view": "locators" }`).
|
|
82
|
+
Behind a login, pass `storageState` (the project's saved auth file); to reach a
|
|
83
|
+
modal or later step, pass `actions`. Every locator listed was checked to match
|
|
84
|
+
exactly one element.
|
|
85
|
+
2. Pick a replacement. Prefer, in order: role + accessible name (`getByRole`),
|
|
86
|
+
`getByTestId`, label/placeholder, then a short stable CSS selector. Avoid
|
|
87
|
+
positional selectors such as `:nth-child` and generated class names.
|
|
88
|
+
3. `validate-selector` with `{ "url": ..., "selector": ... }` before editing the
|
|
89
|
+
spec. It accepts locator expressions as written in the spec. Only use one that
|
|
90
|
+
comes back `✅ VALID` with exactly 1 match.
|
|
91
|
+
4. Update the spec and re-run with `lastFailed: true`.
|
|
92
|
+
|
|
93
|
+
## Pages behind a login
|
|
94
|
+
|
|
95
|
+
`inspect-page`, `validate-selector` and `compare-visual-state` open the page in a
|
|
96
|
+
fresh browser, so a signed-in page shows the login screen unless you pass state:
|
|
97
|
+
|
|
98
|
+
- `storageState`: path inside the project to a Playwright storageState JSON, such
|
|
99
|
+
as `playwright/.auth/user.json` written by the project's setup project. Look for
|
|
100
|
+
it in `playwright.config.*` before asking the user. The server can default to
|
|
101
|
+
`PW_MCP_STORAGE_STATE`.
|
|
102
|
+
- `headers`: extra HTTP headers, e.g. an API token the user gave you. Never invent
|
|
103
|
+
or log credentials.
|
|
104
|
+
- `actions`: up to 20 steps after load (`click`, `fill`, `press`, `check`,
|
|
105
|
+
`select`, `hover`, `wait`, `goto`, ...) to open a modal or reach a later step.
|
|
106
|
+
- `viewport`: `{ "width": 390, "height": 844 }` for mobile layouts.
|
|
107
|
+
|
|
108
|
+
When a response says the page landed on a login screen, retry with
|
|
109
|
+
`storageState`. `suggest-fix` takes `storageState` and `headers` too when you heal
|
|
110
|
+
against a live `url`.
|
|
111
|
+
|
|
112
|
+
## Flaky or intermittent failures
|
|
113
|
+
|
|
114
|
+
Start with `analyze-history` (default view `flaky`) to see which tests flip
|
|
115
|
+
between pass and fail across recorded runs, which regressed, and which are simply
|
|
116
|
+
broken; `view: "patterns"` groups failures that share a cause. Then call
|
|
117
|
+
`diagnose-flaky` on the worst ones (optionally `{ "testFiles": [...], "runs": 5 }`;
|
|
118
|
+
with no `testFiles` it takes the tests that failed in the last run). It repeats
|
|
119
|
+
them with retries disabled, in one Playwright process, and returns a table with
|
|
120
|
+
one verdict **per test** (passes, failures, duration spread, first error):
|
|
121
|
+
|
|
122
|
+
- **CONSISTENTLY FAILING**: not flaky; treat it as a real failure (core loop).
|
|
123
|
+
- **FLAKY**: some runs passed. Same error signature each time points to a real
|
|
124
|
+
race in the app or test; varying errors point to timing or environment. Look for
|
|
125
|
+
missing awaits, assertions without auto-waiting, shared state between tests and
|
|
126
|
+
fixed `waitForTimeout` sleeps. Never "fix" flakiness by only adding retries or
|
|
127
|
+
sleeps.
|
|
128
|
+
- **NOT REPRODUCING**: passed every run. Report that the failure was one-off.
|
|
129
|
+
|
|
130
|
+
When a test is FLAKY and the suite runs in parallel, call `diagnose-flaky` again
|
|
131
|
+
with `isolate: true`. It repeats the tests fully parallel, then repeats the
|
|
132
|
+
failing ones with one worker, and reads each one:
|
|
133
|
+
|
|
134
|
+
- **fails only in parallel**: the test shares state with others (same user or
|
|
135
|
+
account, DB rows, files, ports, a global fixture). Fix the data isolation, for
|
|
136
|
+
example per-worker data from `testInfo.workerIndex`; do not just serialize the
|
|
137
|
+
whole suite.
|
|
138
|
+
- **flaky even alone**: the race is inside the test or the app.
|
|
139
|
+
- **fails alone too**: a real bug, not parallelism.
|
|
140
|
+
|
|
141
|
+
Pass `separateProcesses: true` only when the flake seems tied to global setup or
|
|
142
|
+
a cold start, since one process per run is slower. `get-failure` works on the
|
|
143
|
+
last failing diagnose run straight after, and each repetition is recorded in the
|
|
144
|
+
history, so `diagnose-flaky` with `runs: 5` is also the quickest way to seed
|
|
145
|
+
history for `analyze-history`.
|
|
146
|
+
|
|
147
|
+
Every `run-test`, `diagnose-flaky` and `suggest-fix` run is recorded in
|
|
148
|
+
`<project>/.playwright-e2e-mcp/history.jsonl` on the user's machine;
|
|
149
|
+
`analyze-history` with `view: "test"` and a `test` filter shows one test's
|
|
150
|
+
pass/fail timeline.
|
|
151
|
+
|
|
152
|
+
## Other tasks
|
|
153
|
+
|
|
154
|
+
- **List tests:** `list-tests`, with `filter` for a substring of `file › title`.
|
|
155
|
+
- **Write a new test:** `generate-e2e-test` with a `description` (and `pageUrl` if
|
|
156
|
+
there is no `baseURL`). It scaffolds a spec from selectors the project actually
|
|
157
|
+
declares, from recent git changes, and reports each selector's source. Review the
|
|
158
|
+
file it writes, then `run-test` it. Pass `write: false` to preview without
|
|
159
|
+
writing.
|
|
160
|
+
- **Set up CI:** when the user wants the same diagnosis on every pull request,
|
|
161
|
+
point them to the GitHub Action (`uses: xsignon-secure/E2E@v0.3.0`) or the
|
|
162
|
+
`npx -y playwright-e2e-mcp ci` command in `references/setup.md`. It writes the
|
|
163
|
+
run, flaky verdicts and fix diffs to the job summary and one PR comment.
|
|
164
|
+
- **Visual regression:** `compare-visual-state` with `url` and a `name`. The first
|
|
165
|
+
call saves a baseline under `.pw-mcp/visual/`; later calls report changed
|
|
166
|
+
regions and color shifts and write a diff image. Use `action: "baseline"` only
|
|
167
|
+
when the user confirms the new look is intended.
|
|
168
|
+
|
|
169
|
+
## Reporting back
|
|
170
|
+
|
|
171
|
+
When you finish, tell the user, in this order:
|
|
172
|
+
|
|
173
|
+
1. The result: which tests now pass, fail or are flaky (counts from the last
|
|
174
|
+
`run-test`).
|
|
175
|
+
2. The cause of each failure you fixed, with the `file:line` you changed.
|
|
176
|
+
3. Anything you did not fix and why (app bug, server down, needs a decision).
|
|
177
|
+
|
|
178
|
+
## Things to avoid
|
|
179
|
+
|
|
180
|
+
- Do not raise timeouts, add retries, add `waitForTimeout`, or delete or
|
|
181
|
+
`test.skip` a test to make a run green, unless the user explicitly asks.
|
|
182
|
+
- Do not accept a new visual baseline without the user's confirmation.
|
|
183
|
+
- Do not pass `allowExpectationUpdate: true` to `suggest-fix` unless the user
|
|
184
|
+
confirms the new text is intended; a changed expected value can be a real bug.
|
|
185
|
+
- Do not point `inspect-page` or `validate-selector` at sites the user did not
|
|
186
|
+
name; they open real pages in a headless browser.
|
|
187
|
+
- `run-test` executes the project's own test code. Run it only in projects the
|
|
188
|
+
user has asked you to work on.
|
|
189
|
+
|
|
190
|
+
## References
|
|
191
|
+
|
|
192
|
+
- `references/setup.md`: install and client configuration, environment variables.
|
|
193
|
+
- `references/tools.md`: every tool's arguments.
|
|
194
|
+
- `references/failure-kinds.md`: failure kinds and error codes, and what to do.
|
|
195
|
+
- `references/example-session.md`: a worked fix-a-failing-test session with
|
|
196
|
+
`suggest-fix`.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Example session: fixing a failing checkout test
|
|
2
|
+
|
|
3
|
+
**User:** The checkout test started failing after the redesign. Can you fix it?
|
|
4
|
+
|
|
5
|
+
1. Agent calls `run-test` with `{ "testFiles": ["tests/checkout.spec.ts"] }`.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
## Playwright run — ❌ FAILED
|
|
9
|
+
| passed | failed | flaky | skipped |
|
|
10
|
+
| 2 | 1 | 0 | 0 |
|
|
11
|
+
### 1 of 1. checkout.spec.ts › pays with card
|
|
12
|
+
File: checkout.spec.ts:18 | failed · timeout
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
2. Agent calls `get-failure` with `{ "index": 1 }`. The failed action is
|
|
16
|
+
`locator('#pay-now').click()`. The DOM snapshot at failure has no `#pay-now`,
|
|
17
|
+
but it does have a `Pay now` button. No network requests failed and the console
|
|
18
|
+
is clean, so the app itself looks healthy.
|
|
19
|
+
|
|
20
|
+
3. The failure kind is `timeout`, but the cause is a locator that no longer
|
|
21
|
+
matches, so the agent calls `suggest-fix` with `{ "index": 1 }`:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
### Proposed locator fix — confidence **high**
|
|
25
|
+
The button's accessible name matches "pay", and
|
|
26
|
+
`getByRole('button', { name: 'Pay now' })` is proven to resolve to exactly
|
|
27
|
+
that element.
|
|
28
|
+
- await page.locator('#pay-now').click();
|
|
29
|
+
+ await page.getByRole('button', { name: 'Pay now' }).click();
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
4. Confidence is high, so the agent calls `suggest-fix` with
|
|
33
|
+
`{ "index": 1, "apply": true }`. The server writes the change, re-runs the test
|
|
34
|
+
with retries off, and reports `✅ Verified — the test passes with the fix`.
|
|
35
|
+
Had the test still failed, the server would have restored the original file.
|
|
36
|
+
|
|
37
|
+
5. Agent calls `run-test` with `{ "lastFailed": true }` to confirm, then
|
|
38
|
+
`{ "testFiles": ["tests/checkout.spec.ts"] }` for the whole file: 3 passed.
|
|
39
|
+
|
|
40
|
+
**Agent's reply:**
|
|
41
|
+
|
|
42
|
+
> All 3 checkout tests pass now. "pays with card" failed because the redesign
|
|
43
|
+
> removed the `#pay-now` id from the pay button. I changed the locator at
|
|
44
|
+
> `tests/checkout.spec.ts:18` to `getByRole('button', { name: 'Pay now' })`,
|
|
45
|
+
> which matches exactly one element, and the server re-ran the test to confirm
|
|
46
|
+
> the fix.
|
|
47
|
+
|
|
48
|
+
## When suggest-fix refuses
|
|
49
|
+
|
|
50
|
+
If `suggest-fix` says the element is most likely missing, do not weaken the test.
|
|
51
|
+
Read `get-failure` again for failed network requests and console errors, check the
|
|
52
|
+
page with `inspect-page` (with `storageState` if it needs a login), and report it
|
|
53
|
+
to the user as a probable app bug with that evidence.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Failure kinds and error codes
|
|
2
|
+
|
|
3
|
+
## Per-test failure kinds (from `run-test` and `get-failure`)
|
|
4
|
+
|
|
5
|
+
| Kind | Meaning | What to do |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| `assertion` | An `expect` did not hold | Compare expected vs actual and the DOM snapshot; decide whether the app regressed or the expectation is stale, and say which before editing |
|
|
8
|
+
| `timeout` | An action or the test ran out of time | Check the DOM snapshot and failed network requests for the real cause (element never appeared, API failed) before touching timeouts |
|
|
9
|
+
| `server-unreachable` | The app under test did not respond | Ask the user to start the dev server, or configure `webServer` in the Playwright config; do not edit tests |
|
|
10
|
+
| `browser-crash` | The browser or page closed unexpectedly | Re-run once; if it repeats, suggest `npx playwright install` to repair browsers |
|
|
11
|
+
| `syntax` | The spec or config does not compile | Fix the reported `file:line` first; nothing else will run until it does |
|
|
12
|
+
| `config` | The Playwright config is invalid | Read the message and fix the config |
|
|
13
|
+
| `unknown` | Not classified | Read the message, stack and DOM snapshot directly |
|
|
14
|
+
|
|
15
|
+
A test reported as **flaky** passed on the automatic retry. Run
|
|
16
|
+
`diagnose-flaky` before deciding how to treat it.
|
|
17
|
+
|
|
18
|
+
## Tool error codes
|
|
19
|
+
|
|
20
|
+
| Code | Meaning | What to do |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| `NO_PLAYWRIGHT` | `@playwright/test` is not installed in the project | Show the user the install command the error includes |
|
|
23
|
+
| `NO_CONFIG` | No `playwright.config.*` found | Ask where the config is, or pass `projectRoot` / `config` |
|
|
24
|
+
| `MULTIPLE_CONFIGS` | Several configs found; the error lists them numbered | Ask the user which one, or pick the obvious one, and pass `config: "2"` or its path |
|
|
25
|
+
| `INVALID_PATH` | A path or `projectRoot` leaves the allowed roots | Use a path inside the project; to allow another root the user must set `PW_MCP_ALLOWED_ROOTS` |
|
|
26
|
+
| `SERVER_NOT_RUNNING` | The app is not reachable | As `server-unreachable` above |
|
|
27
|
+
| `TIMEOUT` | The whole run hit `timeoutMs`; results are partial | Narrow the run (`testFiles`, `grep`) or raise `timeoutMs` for this call |
|
|
28
|
+
| `BROWSER_CRASH` | Browser failed | As `browser-crash` above |
|
|
29
|
+
| `SYNTAX_ERROR` | A spec has a syntax error | Fix the reported file; `list-tests` still works via a source scan |
|
|
30
|
+
| `DISK_FULL` | No space left on device | Ask the user to free disk space |
|
|
31
|
+
| `SPAWN_FAILED` / `REPORT_MISSING` | Playwright could not start or wrote no report | Check Node and Playwright are installed; re-run with `LOG_LEVEL=debug` |
|
|
32
|
+
| `CLIENT_DISCONNECT` | The run was cancelled | Re-run if still needed |
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Setup: connecting the playwright-e2e-mcp server
|
|
2
|
+
|
|
3
|
+
This skill only gives the agent instructions. The tools come from the
|
|
4
|
+
`playwright-e2e-mcp` MCP server, which must be connected to the agent.
|
|
5
|
+
|
|
6
|
+
## Requirements
|
|
7
|
+
|
|
8
|
+
- playwright-e2e-mcp **0.2.0 or newer**, 0.3.0 recommended. `suggest-fix`,
|
|
9
|
+
`get-run-status`, `analyze-history`, verified locators and signed-in page
|
|
10
|
+
inspection arrived in 0.2.0; per-test flaky verdicts, `isolate`, tool profiles
|
|
11
|
+
and the `ci` command in 0.3.0. Check with
|
|
12
|
+
`npx -y playwright-e2e-mcp --version`.
|
|
13
|
+
|
|
14
|
+
- Node.js 20 or newer.
|
|
15
|
+
- A project with `@playwright/test` installed and a browser available:
|
|
16
|
+
`npx playwright install chromium`.
|
|
17
|
+
|
|
18
|
+
## Install the server
|
|
19
|
+
|
|
20
|
+
The server is published on npm as `playwright-e2e-mcp` and in the official MCP
|
|
21
|
+
Registry as `io.github.xsignon-secure/E2E`. Pin a version in shared configs
|
|
22
|
+
(`playwright-e2e-mcp@<version>`) so every machine runs the same build.
|
|
23
|
+
|
|
24
|
+
**Claude Code**
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
claude mcp add playwright-e2e -- npx -y playwright-e2e-mcp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Claude Desktop, Cursor, Windsurf, Gemini CLI, Qwen Code and other JSON-config clients**
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"playwright-e2e": {
|
|
36
|
+
"command": "npx",
|
|
37
|
+
"args": ["-y", "playwright-e2e-mcp"],
|
|
38
|
+
"env": { "PW_MCP_PROJECT_ROOT": "/absolute/path/to/your/project" }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Claude Desktop also has a one-click `.mcpb` extension on the project's
|
|
45
|
+
[GitHub releases](https://github.com/xsignon-secure/E2E/releases); it asks for the
|
|
46
|
+
project root on install.
|
|
47
|
+
|
|
48
|
+
**Codex CLI**
|
|
49
|
+
|
|
50
|
+
```toml
|
|
51
|
+
# ~/.codex/config.toml
|
|
52
|
+
[mcp_servers.playwright-e2e]
|
|
53
|
+
command = "npx"
|
|
54
|
+
args = ["-y", "playwright-e2e-mcp"]
|
|
55
|
+
startup_timeout_sec = 60
|
|
56
|
+
tool_timeout_sec = 600
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Raise the timeouts as shown: a Playwright run with retries takes longer than
|
|
60
|
+
Codex's 60-second default tool timeout.
|
|
61
|
+
|
|
62
|
+
## Install the skill
|
|
63
|
+
|
|
64
|
+
Copy the `playwright-e2e-mcp/` folder (the one holding `SKILL.md`) into your
|
|
65
|
+
agent's skills directory, for example:
|
|
66
|
+
|
|
67
|
+
- Claude Code: `~/.claude/skills/` (personal) or `.claude/skills/` (project)
|
|
68
|
+
- Codex CLI: `~/.codex/skills/`
|
|
69
|
+
- Other agents: their documented skills folder
|
|
70
|
+
|
|
71
|
+
## Environment variables
|
|
72
|
+
|
|
73
|
+
Set these in the server's `env` block. None of them are secrets except
|
|
74
|
+
`PW_MCP_HTTP_TOKEN`; never put a token in a committed config file.
|
|
75
|
+
|
|
76
|
+
| Variable | Default | Purpose |
|
|
77
|
+
| --- | --- | --- |
|
|
78
|
+
| `PW_MCP_PROJECT_ROOT` | server working directory | Default project root for every tool |
|
|
79
|
+
| `PW_MCP_TOOLS` | all | Tools to expose: names and/or profiles `core`, `triage`, `inspect`, `author` (same as the `--tools=` flag). `core` halves the tool-definition context |
|
|
80
|
+
| `PW_MCP_ALLOWED_ROOTS` | none | Extra directories allowed as `projectRoot` (`:`-separated, `;` on Windows) |
|
|
81
|
+
| `PW_MCP_BLOCK_PRIVATE_URLS` | off for stdio | `1` makes the URL tools refuse loopback, private-network and cloud-metadata addresses |
|
|
82
|
+
| `PW_MCP_STORAGE_STATE` | none | Default Playwright storageState JSON (inside the project) for the page tools, so signed-in pages open logged in |
|
|
83
|
+
| `PW_MCP_HISTORY` | on | `0` stops recording runs to `<project>/.playwright-e2e-mcp/history.jsonl` (this turns off `analyze-history`) |
|
|
84
|
+
| `LOG_LEVEL` | `info` | `debug`, `info`, `warn`, `error` or `silent` |
|
|
85
|
+
| `PW_MCP_HTTP_TOKEN` | none | HTTP bridge only: bearer token that unlocks all tools |
|
|
86
|
+
|
|
87
|
+
## Hosted endpoint
|
|
88
|
+
|
|
89
|
+
Clients that only accept remote MCP servers can use the Streamable HTTP bridge
|
|
90
|
+
(`https://playwright-e2e-mcp.vercel.app/api/mcp`, or your own deployment of the
|
|
91
|
+
repo). Without a bearer token the bridge serves only `list-tests`,
|
|
92
|
+
`get-failure` and `analyze-history`, so the core loop in `SKILL.md` needs a local install or a token.
|
|
93
|
+
|
|
94
|
+
## Check it works
|
|
95
|
+
|
|
96
|
+
Ask the agent to "list my Playwright tests". It should call `list-tests` and
|
|
97
|
+
return files and titles. Clients that show MCP prompts also list
|
|
98
|
+
`/fix-failing-test` and `/triage-flaky-tests`. If it says the tools are missing, the server is not
|
|
99
|
+
connected: restart the client after editing its config.
|
|
100
|
+
|
|
101
|
+
## CI (0.3.0+)
|
|
102
|
+
|
|
103
|
+
The same diagnosis runs without an agent:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npx -y playwright-e2e-mcp ci --flaky-runs 3 --suggest 2 --output report.md
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Exit code 0 means passed, 1 tests failed, 2 the run itself failed. On GitHub
|
|
110
|
+
Actions it also writes to the job summary. As an Action:
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
- uses: xsignon-secure/E2E@v0.3.0
|
|
114
|
+
with:
|
|
115
|
+
flaky-runs: 3
|
|
116
|
+
suggest: 2
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
It keeps one PR comment up to date when the run fails (needs
|
|
120
|
+
`pull-requests: write`).
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Tool reference
|
|
2
|
+
|
|
3
|
+
All paths are relative to the project root. Every tool except `get-run-status`
|
|
4
|
+
accepts an optional `projectRoot`, which must sit inside the server's allowed roots.
|
|
5
|
+
|
|
6
|
+
## run-test
|
|
7
|
+
|
|
8
|
+
Runs Playwright and returns stats, failures, failure kinds and fix hints.
|
|
9
|
+
|
|
10
|
+
| Argument | Type | Notes |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| `testFiles` | string[] | Files or directories; `file:line` supported. Omit to run everything |
|
|
13
|
+
| `grep` | string | Only tests whose title matches this regex |
|
|
14
|
+
| `browser` | `chromium` \| `firefox` \| `webkit` | Matched against config project names |
|
|
15
|
+
| `background` | boolean | Return a run id at once and keep running; follow it with `get-run-status` |
|
|
16
|
+
| `headed` | boolean | Visible browser window |
|
|
17
|
+
| `timeoutMs` | number | Wall-clock limit for the run (default 120000); partial results are returned past it |
|
|
18
|
+
| `testTimeoutMs` | number | Per-test timeout |
|
|
19
|
+
| `workers`, `retries` | number | Passed to Playwright |
|
|
20
|
+
| `config` | string | Config path, or 1-based index when there are several |
|
|
21
|
+
| `retryOnFailure` | boolean | Retry failures once before reporting (default true; ignored when `retries` is set) |
|
|
22
|
+
| `lastFailed` | boolean | Re-run only the tests that failed last time |
|
|
23
|
+
| `args` | string[] | Allowlisted Playwright flags such as `--repeat-each=N`, `--max-failures=N`, `--update-snapshots`, `--shard=1/3`, `--trace=on`; path-taking flags are rejected |
|
|
24
|
+
|
|
25
|
+
Traces are captured on failure automatically so `get-failure` can show the DOM.
|
|
26
|
+
Clients that send a progress token get live progress while the run goes.
|
|
27
|
+
|
|
28
|
+
## get-failure
|
|
29
|
+
|
|
30
|
+
| Argument | Type | Notes |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| `index` | number | 1-based failure index from the last run (default 1) |
|
|
33
|
+
|
|
34
|
+
Returns the message and code frame, expected vs actual, stack, failure kind and
|
|
35
|
+
diagnosis, console output, the DOM snapshot at failure with the failed action and
|
|
36
|
+
its selector, failed network requests, console errors and warnings, and next steps.
|
|
37
|
+
|
|
38
|
+
## inspect-page
|
|
39
|
+
|
|
40
|
+
| Argument | Type | Notes |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| `url` | string | Required, full http(s) URL |
|
|
43
|
+
| `selector` | string | Inspect only matches of this CSS selector |
|
|
44
|
+
| `waitFor` | string | Wait for a selector (CSS or `text=...`) first |
|
|
45
|
+
| `waitUntil` | `load` \| `domcontentloaded` \| `networkidle` | Navigation wait |
|
|
46
|
+
| `includeHtml` | boolean | Include rendered HTML (capped by `maxHtmlChars`, default 20000) |
|
|
47
|
+
| `timeoutMs` | number | Default 45000 |
|
|
48
|
+
| `view` | `elements` \| `locators` | `locators`: compact map of interactive elements with verified locators |
|
|
49
|
+
| `storageState` | string | Playwright storageState JSON inside the project (signed-in session); defaults to `PW_MCP_STORAGE_STATE` |
|
|
50
|
+
| `headers` | object | Extra HTTP headers |
|
|
51
|
+
| `actions` | array | Up to 20 steps after load: `{ type: click\|dblclick\|fill\|press\|check\|uncheck\|select\|hover\|wait\|goto, locator?, value?, url?, ms? }` |
|
|
52
|
+
| `viewport` | object | `{ width, height }` |
|
|
53
|
+
|
|
54
|
+
Returns each element's Playwright locators proven unique on the page (role +
|
|
55
|
+
name first), unique CSS selector, tag, visibility, box, text and attributes,
|
|
56
|
+
plus console messages. `validate-selector` and `compare-visual-state` take the
|
|
57
|
+
same `storageState`, `headers`, `actions` and `viewport`.
|
|
58
|
+
|
|
59
|
+
## validate-selector
|
|
60
|
+
|
|
61
|
+
| Argument | Type | Notes |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| `url` | string | Required |
|
|
64
|
+
| `selector` | string | Required: CSS, a Playwright selector, or a locator such as `getByRole('button', { name: 'Save' })` |
|
|
65
|
+
| `timeoutMs` | number | Default 45000 |
|
|
66
|
+
|
|
67
|
+
Verdicts: `✅ VALID — N matches` with samples and a unique locator for each,
|
|
68
|
+
a strict-mode warning when more than one matches, `✅ VALID — 0 matches` with
|
|
69
|
+
advice, or `❌ INVALID` with the parse error.
|
|
70
|
+
|
|
71
|
+
## list-tests
|
|
72
|
+
|
|
73
|
+
| Argument | Type | Notes |
|
|
74
|
+
| --- | --- | --- |
|
|
75
|
+
| `config` | string | Config path or index |
|
|
76
|
+
| `testDir` | string | Restrict to a directory |
|
|
77
|
+
| `filter` | string | Case-insensitive substring of `file › title` |
|
|
78
|
+
| `limit` | number | Default 500 |
|
|
79
|
+
|
|
80
|
+
Falls back to a source scan when Playwright cannot list (broken install or spec).
|
|
81
|
+
|
|
82
|
+
## generate-e2e-test
|
|
83
|
+
|
|
84
|
+
| Argument | Type | Notes |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| `description` | string | Required: what the test should cover |
|
|
87
|
+
| `pageUrl` | string | Start page (default: `baseURL` / `webServer.url`) |
|
|
88
|
+
| `testDir`, `file` | string | Where to write; `file` must end in `.spec.*` or `.test.*` |
|
|
89
|
+
| `write` | boolean | Write to disk (default true) |
|
|
90
|
+
| `overwrite` | boolean | Replace a spec this tool generated earlier |
|
|
91
|
+
| `liveInspect` | boolean | Cross-check selectors on the live page |
|
|
92
|
+
| `config` | string | As above |
|
|
93
|
+
|
|
94
|
+
## compare-visual-state
|
|
95
|
+
|
|
96
|
+
| Argument | Type | Notes |
|
|
97
|
+
| --- | --- | --- |
|
|
98
|
+
| `url` | string | Required |
|
|
99
|
+
| `name` | string | Baseline id, e.g. `checkout-page` |
|
|
100
|
+
| `action` | `compare` \| `baseline` | Default `compare`; `baseline` re-captures the reference |
|
|
101
|
+
| `selector` | string | Capture one element |
|
|
102
|
+
| `fullPage` | boolean | Full scrollable page |
|
|
103
|
+
| `tolerance` | number | Percent of pixels allowed to differ (default 0.1) |
|
|
104
|
+
| `pixelThreshold` | number | Per-pixel channel delta (default 60) |
|
|
105
|
+
| `waitUntil`, `waitFor`, `timeoutMs` | | As `inspect-page` |
|
|
106
|
+
|
|
107
|
+
Baselines live in `.pw-mcp/visual/`.
|
|
108
|
+
|
|
109
|
+
## diagnose-flaky
|
|
110
|
+
|
|
111
|
+
| Argument | Type | Notes |
|
|
112
|
+
| --- | --- | --- |
|
|
113
|
+
| `testFiles` | string[] | Default: tests that failed in the last run |
|
|
114
|
+
| `runs` | number | 2 to 10 (default 3) |
|
|
115
|
+
| `isolate` | boolean | Repeat fully parallel (`workers` default 4), then repeat the failing tests with one worker (0.3.0+) |
|
|
116
|
+
| `separateProcesses` | boolean | One Playwright process per run instead of one `--repeat-each` process; slower (0.3.0+) |
|
|
117
|
+
| `browser`, `headed`, `workers`, `config` | | As `run-test` |
|
|
118
|
+
| `timeoutMs` | number | Per run (default 120000); the single `--repeat-each` process gets this × `runs` |
|
|
119
|
+
|
|
120
|
+
Runs with retries disabled and returns, per test, passes, failures, duration
|
|
121
|
+
spread, first error and `CONSISTENTLY FAILING`, `FLAKY` or `NOT REPRODUCING`,
|
|
122
|
+
plus the verdict block for the worst test. With `isolate`, a second table reads
|
|
123
|
+
each failing test as "fails only in parallel", "flaky even alone" or "fails
|
|
124
|
+
alone too". Versions before 0.3.0 return one run-level verdict and a per-run
|
|
125
|
+
table instead.
|
|
126
|
+
|
|
127
|
+
## suggest-fix
|
|
128
|
+
|
|
129
|
+
| Argument | Type | Notes |
|
|
130
|
+
| --- | --- | --- |
|
|
131
|
+
| `index` | number | 1-based failure index from the last run (default 1) |
|
|
132
|
+
| `apply` | boolean | Write the fix (default false: diff only) |
|
|
133
|
+
| `verify` | boolean | After applying, re-run and revert if still failing (default true) |
|
|
134
|
+
| `allowExpectationUpdate` | boolean | Allow applying a changed expected text (default false) |
|
|
135
|
+
| `url`, `storageState`, `headers` | | Heal against a live page instead of the trace snapshot |
|
|
136
|
+
| `config`, `timeoutMs` | | As `run-test` |
|
|
137
|
+
|
|
138
|
+
Returns a unified diff: a locator fix rated `high` or `medium` confidence, or an
|
|
139
|
+
expectation update rated `low` that is applied only with
|
|
140
|
+
`allowExpectationUpdate: true`. Otherwise it refuses and says the element is most
|
|
141
|
+
likely missing.
|
|
142
|
+
|
|
143
|
+
## get-run-status
|
|
144
|
+
|
|
145
|
+
| Argument | Type | Notes |
|
|
146
|
+
| --- | --- | --- |
|
|
147
|
+
| `runId` | string | From `run-test` with `background: true` (default: latest) |
|
|
148
|
+
| `waitSeconds` | number | Wait up to this long (max 55) |
|
|
149
|
+
| `cancel` | boolean | Stop the run |
|
|
150
|
+
|
|
151
|
+
## analyze-history
|
|
152
|
+
|
|
153
|
+
| Argument | Type | Notes |
|
|
154
|
+
| --- | --- | --- |
|
|
155
|
+
| `view` | `flaky` \| `patterns` \| `test` | Default `flaky` |
|
|
156
|
+
| `test` | string | Substring of a test's file or title |
|
|
157
|
+
| `lastRuns` | number | Default 30 |
|
|
158
|
+
| `limit` | number | Default 15 |
|
|
159
|
+
|
|
160
|
+
Reads `.playwright-e2e-mcp/history.jsonl`, written by every run
|
|
161
|
+
(`PW_MCP_HISTORY=0` disables it).
|