playwright-e2e-mcp 0.3.0 → 0.3.2
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 +36 -12
- 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.js +10 -0
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
- 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
package/README.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
[](https://github.com/xsignon-secure/E2E/actions/workflows/ci.yml) [](https://github.com/xsignon-secure/E2E/releases) [](https://registry.modelcontextprotocol.io/)
|
|
4
4
|
[](https://m8ven.ai/mcp/trajectiq-ai/e2e?s=readme)
|
|
5
5
|
|
|
6
|
+
[](https://cursor.com/en/install-mcp?name=playwright-e2e&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInBsYXl3cmlnaHQtZTJlLW1jcCJdfQ==)
|
|
7
|
+
[](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522playwright-e2e%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522playwright-e2e-mcp%2522%255D%257D)
|
|
8
|
+
[](https://github.com/xsignon-secure/E2E/releases/latest)
|
|
9
|
+
|
|
6
10
|
An [MCP](https://modelcontextprotocol.io) server that **diagnoses and fixes failing Playwright
|
|
7
11
|
tests**. It is the layer that sits next to a browser-driving MCP: Playwright MCP gives an agent
|
|
8
12
|
hands in the browser; this server gives it a test runner, a failure analyst and a verified fixer.
|
|
@@ -62,16 +66,36 @@ against the bundled `examples/sample-test.spec.ts` (actual output, unedited):
|
|
|
62
66
|
Images are rendered with `node scripts/gen-demo-images.mjs`: the run-test card is real
|
|
63
67
|
captured output; the endpoint card is an illustration of the authenticated listing.
|
|
64
68
|
|
|
69
|
+
> If this saves you a debugging session, a ⭐ on the repo helps other Playwright users find it.
|
|
70
|
+
|
|
65
71
|
## Install
|
|
66
72
|
|
|
67
73
|
Works with Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Gemini CLI, Freebuff
|
|
68
74
|
and every other MCP client — pick whichever route fits:
|
|
69
75
|
|
|
76
|
+
**Let your agent do it.** Paste this into Claude Code, Cursor, Codex, Gemini CLI or any
|
|
77
|
+
other coding agent:
|
|
78
|
+
|
|
79
|
+
> Install the playwright-e2e-mcp server and skill by following
|
|
80
|
+
> https://raw.githubusercontent.com/xsignon-secure/E2E/main/llms-install.md
|
|
81
|
+
|
|
82
|
+
or run the installer yourself from the project root. It merges the server into each
|
|
83
|
+
client's project config it finds (Claude Code, Cursor, VS Code, Gemini CLI, Codex) and
|
|
84
|
+
installs the agent skill, leaving your other servers alone:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx -y playwright-e2e-mcp init # --client all | cursor,vscode … · --dry-run
|
|
88
|
+
```
|
|
89
|
+
|
|
70
90
|
| Route | How |
|
|
71
91
|
| --- | --- |
|
|
92
|
+
| **One command, any project** | `npx -y playwright-e2e-mcp init` |
|
|
93
|
+
| **Claude Code plugin (server + skill)** | `/plugin marketplace add xsignon-secure/E2E` then `/plugin install playwright-e2e-mcp@xsignon-secure` |
|
|
94
|
+
| **Gemini CLI extension (server + skill)** | `gemini extensions install https://github.com/xsignon-secure/E2E` |
|
|
95
|
+
| **Skill only, any agent** | `npx skills add xsignon-secure/E2E` |
|
|
72
96
|
| **npm (canonical, fastest)** | `npx -y playwright-e2e-mcp` |
|
|
73
97
|
| **MCP Registry** (registry-aware clients discover it automatically) | `io.github.xsignon-secure/E2E` — [listing](https://registry.modelcontextprotocol.io/) |
|
|
74
|
-
| **Any client, no npm account needed** | `npx -y github:xsignon-secure/E2E#v0.3.
|
|
98
|
+
| **Any client, no npm account needed** | `npx -y github:xsignon-secure/E2E#v0.3.2` (pin a release tag) |
|
|
75
99
|
| **Claude Desktop, zero Node setup** | double-click the [`.mcpb` extension](https://github.com/xsignon-secure/E2E/releases) |
|
|
76
100
|
| **Remote-only clients (ChatGPT connectors)** | `https://playwright-e2e-mcp.vercel.app/api/mcp` |
|
|
77
101
|
|
|
@@ -394,8 +418,8 @@ builds `dist/` automatically on install). Pin a release tag: an unpinned
|
|
|
394
418
|
`github:xsignon-secure/E2E` runs whatever is on the default branch at that moment.
|
|
395
419
|
|
|
396
420
|
```bash
|
|
397
|
-
npx -y github:xsignon-secure/E2E#v0.3.
|
|
398
|
-
npm install -D github:xsignon-secure/E2E#v0.3.
|
|
421
|
+
npx -y github:xsignon-secure/E2E#v0.3.2
|
|
422
|
+
npm install -D github:xsignon-secure/E2E#v0.3.2 @playwright/test # or as a project dependency
|
|
399
423
|
npx playwright install chromium
|
|
400
424
|
```
|
|
401
425
|
|
|
@@ -403,7 +427,7 @@ Or grab the packaged tarball from the repo's **GitHub Releases** page and instal
|
|
|
403
427
|
it locally:
|
|
404
428
|
|
|
405
429
|
```bash
|
|
406
|
-
npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.3.
|
|
430
|
+
npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.3.2/playwright-e2e-mcp-0.3.2.tgz
|
|
407
431
|
```
|
|
408
432
|
|
|
409
433
|
Listed in the **official [MCP Registry](https://registry.modelcontextprotocol.io/)** as
|
|
@@ -419,7 +443,7 @@ Listed in the **official [MCP Registry](https://registry.modelcontextprotocol.io
|
|
|
419
443
|
"mcpServers": {
|
|
420
444
|
"playwright-e2e": {
|
|
421
445
|
"command": "npx",
|
|
422
|
-
"args": ["-y", "github:xsignon-secure/E2E#v0.3.
|
|
446
|
+
"args": ["-y", "github:xsignon-secure/E2E#v0.3.2"],
|
|
423
447
|
"env": { "PW_MCP_PROJECT_ROOT": "/absolute/path/to/your/project" }
|
|
424
448
|
}
|
|
425
449
|
}
|
|
@@ -433,8 +457,8 @@ when the client launches it somewhere else (e.g. your home directory).
|
|
|
433
457
|
**Codex / VS Code / Copilot CLIs:**
|
|
434
458
|
|
|
435
459
|
```bash
|
|
436
|
-
codex mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.3.
|
|
437
|
-
code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","github:xsignon-secure/E2E#v0.3.
|
|
460
|
+
codex mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.3.2
|
|
461
|
+
code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","github:xsignon-secure/E2E#v0.3.2"]}'
|
|
438
462
|
```
|
|
439
463
|
|
|
440
464
|
Codex's defaults fight this server: the first launch clones the repo and runs
|
|
@@ -445,7 +469,7 @@ Codex's defaults fight this server: the first launch clones the repo and runs
|
|
|
445
469
|
```toml
|
|
446
470
|
[mcp_servers.playwright-e2e]
|
|
447
471
|
command = "npx"
|
|
448
|
-
args = ["-y", "github:xsignon-secure/E2E#v0.3.
|
|
472
|
+
args = ["-y", "github:xsignon-secure/E2E#v0.3.2"]
|
|
449
473
|
startup_timeout_sec = 60
|
|
450
474
|
tool_timeout_sec = 600
|
|
451
475
|
```
|
|
@@ -460,7 +484,7 @@ into `PW_MCP_PROJECT_ROOT`, so the tools point at a real project from the first
|
|
|
460
484
|
**Claude Code:**
|
|
461
485
|
|
|
462
486
|
```bash
|
|
463
|
-
claude mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.3.
|
|
487
|
+
claude mcp add playwright-e2e -- npx -y github:xsignon-secure/E2E#v0.3.2
|
|
464
488
|
```
|
|
465
489
|
|
|
466
490
|
**Gemini CLI / Qwen Code:** paste the `mcpServers` block above into
|
|
@@ -595,7 +619,7 @@ steps:
|
|
|
595
619
|
- uses: actions/setup-node@v6
|
|
596
620
|
with: { node-version: 24 }
|
|
597
621
|
- run: npm ci && npx playwright install --with-deps chromium
|
|
598
|
-
- uses: xsignon-secure/E2E@v0.3.
|
|
622
|
+
- uses: xsignon-secure/E2E@v0.3.2
|
|
599
623
|
with:
|
|
600
624
|
flaky-runs: 3 # 0 skips the flaky verdict
|
|
601
625
|
suggest: 2 # suggest-fix diffs for the first 2 failures
|
|
@@ -892,8 +916,8 @@ job requests for itself; if it is refused, the run names the setting to change.
|
|
|
892
916
|
### Verifying a published release
|
|
893
917
|
|
|
894
918
|
```bash
|
|
895
|
-
git checkout v0.3.
|
|
896
|
-
npm run release:verify -- v0.3.
|
|
919
|
+
git checkout v0.3.2 && npm ci && npm run mcpb
|
|
920
|
+
npm run release:verify -- v0.3.2
|
|
897
921
|
```
|
|
898
922
|
|
|
899
923
|
The release notes promise that the tag rebuilds the published bundle byte for
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `playwright-e2e-mcp init`: one command an agent (or a person) runs to wire
|
|
3
|
+
* the server and the agent skill into a project, for whichever clients the
|
|
4
|
+
* project uses. Config files are merged, never replaced: other servers and
|
|
5
|
+
* settings stay as they are, an existing playwright-e2e entry is updated in
|
|
6
|
+
* place, and a file that is not valid JSON is left untouched and reported.
|
|
7
|
+
*
|
|
8
|
+
* Exit codes: 0 done (or nothing to do), 1 a file could not be updated,
|
|
9
|
+
* 2 bad arguments.
|
|
10
|
+
*/
|
|
11
|
+
export declare const SERVER_NAME = "playwright-e2e";
|
|
12
|
+
export declare const SKILL_NAME = "playwright-e2e-mcp";
|
|
13
|
+
export declare const CLIENTS: readonly ["claude", "cursor", "vscode", "gemini", "codex", "windsurf"];
|
|
14
|
+
export type Client = (typeof CLIENTS)[number];
|
|
15
|
+
export declare const INIT_USAGE: string;
|
|
16
|
+
export interface InitOptions {
|
|
17
|
+
projectRoot: string;
|
|
18
|
+
clients?: Client[];
|
|
19
|
+
tools?: string;
|
|
20
|
+
skill: boolean;
|
|
21
|
+
dryRun: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function parseInitArgs(argv: string[], cwd?: string): InitOptions;
|
|
24
|
+
/** Clients whose project folder or config file already exists. */
|
|
25
|
+
export declare function detectClients(root: string): Client[];
|
|
26
|
+
export interface PlannedChange {
|
|
27
|
+
client: Client | 'skill';
|
|
28
|
+
file: string;
|
|
29
|
+
action: 'create' | 'update' | 'unchanged' | 'error';
|
|
30
|
+
content?: string;
|
|
31
|
+
error?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function planInit(options: InitOptions, home?: string): {
|
|
34
|
+
clients: Client[];
|
|
35
|
+
changes: PlannedChange[];
|
|
36
|
+
};
|
|
37
|
+
/** The skill folder shipped in the npm package (dist/cli → ../../skill). */
|
|
38
|
+
export declare function bundledSkillDir(): string;
|
|
39
|
+
export declare function applyInit(changes: PlannedChange[], skillSource?: string): void;
|
|
40
|
+
export declare function runInit(argv: string[], out?: (line: string) => void): number;
|
package/dist/cli/init.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `playwright-e2e-mcp init`: one command an agent (or a person) runs to wire
|
|
3
|
+
* the server and the agent skill into a project, for whichever clients the
|
|
4
|
+
* project uses. Config files are merged, never replaced: other servers and
|
|
5
|
+
* settings stay as they are, an existing playwright-e2e entry is updated in
|
|
6
|
+
* place, and a file that is not valid JSON is left untouched and reported.
|
|
7
|
+
*
|
|
8
|
+
* Exit codes: 0 done (or nothing to do), 1 a file could not be updated,
|
|
9
|
+
* 2 bad arguments.
|
|
10
|
+
*/
|
|
11
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
12
|
+
import os from 'node:os';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
import { parseArgs } from 'node:util';
|
|
16
|
+
export const SERVER_NAME = 'playwright-e2e';
|
|
17
|
+
export const SKILL_NAME = 'playwright-e2e-mcp';
|
|
18
|
+
export const CLIENTS = ['claude', 'cursor', 'vscode', 'gemini', 'codex', 'windsurf'];
|
|
19
|
+
export const INIT_USAGE = [
|
|
20
|
+
'Usage: playwright-e2e-mcp init [options]',
|
|
21
|
+
'',
|
|
22
|
+
'Adds the playwright-e2e MCP server and the playwright-e2e-mcp agent skill to a',
|
|
23
|
+
'project. Existing config files are merged, never overwritten.',
|
|
24
|
+
'',
|
|
25
|
+
' --client <list> comma separated: claude, cursor, vscode, gemini, codex,',
|
|
26
|
+
' windsurf, or all (default: the clients the project already',
|
|
27
|
+
' uses, or claude,cursor,vscode when none is found)',
|
|
28
|
+
' --project-root <dir> project directory (default: cwd)',
|
|
29
|
+
' --tools <list> expose only these tools/profiles (e.g. core), see --help',
|
|
30
|
+
' --no-skill do not install the agent skill',
|
|
31
|
+
' --dry-run print what would change without writing',
|
|
32
|
+
'',
|
|
33
|
+
'Files (project scope): claude .mcp.json · cursor .cursor/mcp.json ·',
|
|
34
|
+
'vscode .vscode/mcp.json · gemini .gemini/settings.json · codex .codex/config.toml.',
|
|
35
|
+
'windsurf has no project file; it writes ~/.codeium/windsurf/mcp_config.json.',
|
|
36
|
+
'Skill: .agents/skills/ (read by Codex, Gemini, Cursor and others) and',
|
|
37
|
+
'.claude/skills/ when claude is selected.',
|
|
38
|
+
'',
|
|
39
|
+
].join('\n');
|
|
40
|
+
export function parseInitArgs(argv, cwd = process.cwd()) {
|
|
41
|
+
const { values } = parseArgs({
|
|
42
|
+
args: argv,
|
|
43
|
+
strict: true,
|
|
44
|
+
options: {
|
|
45
|
+
client: { type: 'string' },
|
|
46
|
+
'project-root': { type: 'string' },
|
|
47
|
+
tools: { type: 'string' },
|
|
48
|
+
'no-skill': { type: 'boolean' },
|
|
49
|
+
'dry-run': { type: 'boolean' },
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
let clients;
|
|
53
|
+
if (values.client !== undefined) {
|
|
54
|
+
const names = values.client.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
55
|
+
if (names.includes('all'))
|
|
56
|
+
clients = [...CLIENTS];
|
|
57
|
+
else {
|
|
58
|
+
const unknown = names.filter((n) => !CLIENTS.includes(n));
|
|
59
|
+
if (unknown.length || !names.length) {
|
|
60
|
+
throw new Error(`--client must list ${CLIENTS.join(', ')} or all (got: ${unknown.join(', ') || 'nothing'})`);
|
|
61
|
+
}
|
|
62
|
+
clients = [...new Set(names)];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
projectRoot: path.resolve(cwd, values['project-root'] ?? '.'),
|
|
67
|
+
clients,
|
|
68
|
+
tools: values.tools,
|
|
69
|
+
skill: !values['no-skill'],
|
|
70
|
+
dryRun: Boolean(values['dry-run']),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Clients whose project folder or config file already exists. */
|
|
74
|
+
export function detectClients(root) {
|
|
75
|
+
const has = (p) => existsSync(path.join(root, p));
|
|
76
|
+
const found = [];
|
|
77
|
+
if (has('.mcp.json') || has('.claude') || has('CLAUDE.md'))
|
|
78
|
+
found.push('claude');
|
|
79
|
+
if (has('.cursor'))
|
|
80
|
+
found.push('cursor');
|
|
81
|
+
if (has('.vscode'))
|
|
82
|
+
found.push('vscode');
|
|
83
|
+
if (has('.gemini') || has('GEMINI.md'))
|
|
84
|
+
found.push('gemini');
|
|
85
|
+
if (has('.codex'))
|
|
86
|
+
found.push('codex');
|
|
87
|
+
return found;
|
|
88
|
+
}
|
|
89
|
+
function serverArgs(tools) {
|
|
90
|
+
return tools ? ['-y', 'playwright-e2e-mcp', `--tools=${tools}`] : ['-y', 'playwright-e2e-mcp'];
|
|
91
|
+
}
|
|
92
|
+
/** Merges our entry into a JSON config under `key`, keeping everything else. */
|
|
93
|
+
function planJson(file, key, entry, client) {
|
|
94
|
+
let data = {};
|
|
95
|
+
let existed = false;
|
|
96
|
+
if (existsSync(file)) {
|
|
97
|
+
existed = true;
|
|
98
|
+
const raw = readFileSync(file, 'utf8');
|
|
99
|
+
if (raw.trim()) {
|
|
100
|
+
try {
|
|
101
|
+
const parsed = JSON.parse(raw);
|
|
102
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
103
|
+
throw new Error('not a JSON object');
|
|
104
|
+
data = parsed;
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
return { client, file, action: 'error', error: `not valid JSON (${err.message}); left unchanged` };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const current = data[key];
|
|
112
|
+
const servers = current && typeof current === 'object' && !Array.isArray(current) ? { ...current } : {};
|
|
113
|
+
const before = JSON.stringify(servers[SERVER_NAME]);
|
|
114
|
+
servers[SERVER_NAME] = entry;
|
|
115
|
+
if (existed && before === JSON.stringify(entry))
|
|
116
|
+
return { client, file, action: 'unchanged' };
|
|
117
|
+
return { client, file, action: existed ? 'update' : 'create', content: `${JSON.stringify({ ...data, [key]: servers }, null, 2)}\n` };
|
|
118
|
+
}
|
|
119
|
+
/** Codex reads TOML; append our table unless one is already there. */
|
|
120
|
+
function planCodex(file, args) {
|
|
121
|
+
const table = `[mcp_servers.${SERVER_NAME}]`;
|
|
122
|
+
const block = `${table}\ncommand = "npx"\nargs = [${args.map((a) => JSON.stringify(a)).join(', ')}]\n`;
|
|
123
|
+
if (!existsSync(file))
|
|
124
|
+
return { client: 'codex', file, action: 'create', content: block };
|
|
125
|
+
const raw = readFileSync(file, 'utf8');
|
|
126
|
+
if (raw.includes(table))
|
|
127
|
+
return { client: 'codex', file, action: 'unchanged' };
|
|
128
|
+
const sep = raw.length === 0 || raw.endsWith('\n\n') ? '' : raw.endsWith('\n') ? '\n' : '\n\n';
|
|
129
|
+
return { client: 'codex', file, action: 'update', content: `${raw}${sep}${block}` };
|
|
130
|
+
}
|
|
131
|
+
export function planInit(options, home = os.homedir()) {
|
|
132
|
+
const root = options.projectRoot;
|
|
133
|
+
let clients = options.clients ?? detectClients(root);
|
|
134
|
+
if (!clients.length)
|
|
135
|
+
clients = ['claude', 'cursor', 'vscode'];
|
|
136
|
+
const args = serverArgs(options.tools);
|
|
137
|
+
const stdio = { command: 'npx', args };
|
|
138
|
+
const changes = [];
|
|
139
|
+
for (const client of clients) {
|
|
140
|
+
switch (client) {
|
|
141
|
+
case 'claude':
|
|
142
|
+
changes.push(planJson(path.join(root, '.mcp.json'), 'mcpServers', { type: 'stdio', ...stdio }, client));
|
|
143
|
+
break;
|
|
144
|
+
case 'cursor':
|
|
145
|
+
changes.push(planJson(path.join(root, '.cursor', 'mcp.json'), 'mcpServers', stdio, client));
|
|
146
|
+
break;
|
|
147
|
+
case 'vscode':
|
|
148
|
+
changes.push(planJson(path.join(root, '.vscode', 'mcp.json'), 'servers', { type: 'stdio', ...stdio }, client));
|
|
149
|
+
break;
|
|
150
|
+
case 'gemini':
|
|
151
|
+
changes.push(planJson(path.join(root, '.gemini', 'settings.json'), 'mcpServers', stdio, client));
|
|
152
|
+
break;
|
|
153
|
+
case 'codex':
|
|
154
|
+
changes.push(planCodex(path.join(root, '.codex', 'config.toml'), args));
|
|
155
|
+
break;
|
|
156
|
+
case 'windsurf':
|
|
157
|
+
changes.push(planJson(path.join(home, '.codeium', 'windsurf', 'mcp_config.json'), 'mcpServers', stdio, client));
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (options.skill) {
|
|
162
|
+
const targets = [path.join(root, '.agents', 'skills', SKILL_NAME)];
|
|
163
|
+
if (clients.includes('claude'))
|
|
164
|
+
targets.push(path.join(root, '.claude', 'skills', SKILL_NAME));
|
|
165
|
+
for (const dir of targets) {
|
|
166
|
+
changes.push({ client: 'skill', file: dir, action: existsSync(path.join(dir, 'SKILL.md')) ? 'update' : 'create' });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return { clients, changes };
|
|
170
|
+
}
|
|
171
|
+
/** The skill folder shipped in the npm package (dist/cli → ../../skill). */
|
|
172
|
+
export function bundledSkillDir() {
|
|
173
|
+
return fileURLToPath(new URL(`../../skill/${SKILL_NAME}/`, import.meta.url));
|
|
174
|
+
}
|
|
175
|
+
export function applyInit(changes, skillSource = bundledSkillDir()) {
|
|
176
|
+
for (const change of changes) {
|
|
177
|
+
if (change.action === 'error' || change.action === 'unchanged')
|
|
178
|
+
continue;
|
|
179
|
+
if (change.client === 'skill') {
|
|
180
|
+
mkdirSync(change.file, { recursive: true });
|
|
181
|
+
cpSync(skillSource, change.file, { recursive: true, force: true });
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
mkdirSync(path.dirname(change.file), { recursive: true });
|
|
185
|
+
writeFileSync(change.file, change.content ?? '');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
export function runInit(argv, out = (l) => process.stdout.write(`${l}\n`)) {
|
|
189
|
+
let options;
|
|
190
|
+
try {
|
|
191
|
+
options = parseInitArgs(argv);
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
out(`init: ${err.message}\n`);
|
|
195
|
+
out(INIT_USAGE);
|
|
196
|
+
return 2;
|
|
197
|
+
}
|
|
198
|
+
const { clients, changes } = planInit(options);
|
|
199
|
+
if (options.skill && !existsSync(path.join(bundledSkillDir(), 'SKILL.md'))) {
|
|
200
|
+
out('init: the skill files are missing from this install; skipping the skill.');
|
|
201
|
+
for (const c of changes)
|
|
202
|
+
if (c.client === 'skill')
|
|
203
|
+
c.action = 'unchanged';
|
|
204
|
+
}
|
|
205
|
+
if (!options.dryRun)
|
|
206
|
+
applyInit(changes);
|
|
207
|
+
const rel = (p) => (p.startsWith(options.projectRoot) ? path.relative(options.projectRoot, p) || '.' : p);
|
|
208
|
+
out(`${options.dryRun ? 'Would set up' : 'Set up'} playwright-e2e for: ${clients.join(', ')}`);
|
|
209
|
+
for (const c of changes) {
|
|
210
|
+
const what = c.client === 'skill' ? 'skill' : c.client;
|
|
211
|
+
out(` ${c.action.padEnd(9)} ${rel(c.file)} (${what})${c.error ? `: ${c.error}` : ''}`);
|
|
212
|
+
}
|
|
213
|
+
out('');
|
|
214
|
+
out('Next: make sure browsers are installed (npx playwright install chromium), then');
|
|
215
|
+
out('restart or reload the agent so it picks up the new server.');
|
|
216
|
+
return changes.some((c) => c.action === 'error') ? 1 : 0;
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,15 @@ async function main() {
|
|
|
31
31
|
process.exitCode = await runCi(process.argv.slice(3));
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
|
+
if (process.argv[2] === 'init') {
|
|
35
|
+
const { runInit, INIT_USAGE } = await import('./cli/init.js');
|
|
36
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
37
|
+
process.stdout.write(INIT_USAGE);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
process.exitCode = runInit(process.argv.slice(3));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
34
43
|
if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
|
35
44
|
process.stdout.write(`${SERVER_VERSION}\n`);
|
|
36
45
|
return;
|
|
@@ -41,6 +50,7 @@ async function main() {
|
|
|
41
50
|
'',
|
|
42
51
|
'Usage: playwright-e2e-mcp [--tools=<list>] [--version] [--help]',
|
|
43
52
|
' playwright-e2e-mcp ci [options] run the suite and print a Markdown diagnosis (ci --help)',
|
|
53
|
+
' playwright-e2e-mcp init [options] add the server + agent skill to a project (init --help)',
|
|
44
54
|
'',
|
|
45
55
|
'Connects over stdio (MCP). Configuration via environment:',
|
|
46
56
|
' PW_MCP_PROJECT_ROOT default project root (default: cwd)',
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "playwright-e2e-mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "MCP server that runs, diagnoses and fixes failing Playwright end-to-end tests: trace analysis, verified locator fixes, flaky ranking",
|
|
5
5
|
"author": "xsignon-secure (https://github.com/xsignon-secure)",
|
|
6
6
|
"mcpName": "io.github.xsignon-secure/E2E",
|
|
@@ -26,7 +26,10 @@
|
|
|
26
26
|
"selectors",
|
|
27
27
|
"flaky-tests",
|
|
28
28
|
"github-action",
|
|
29
|
-
"ci"
|
|
29
|
+
"ci",
|
|
30
|
+
"agent-skills",
|
|
31
|
+
"claude-code-plugin",
|
|
32
|
+
"gemini-cli-extension"
|
|
30
33
|
],
|
|
31
34
|
"main": "./dist/index.js",
|
|
32
35
|
"types": "./dist/index.d.ts",
|
|
@@ -42,6 +45,7 @@
|
|
|
42
45
|
"files": [
|
|
43
46
|
"dist",
|
|
44
47
|
"examples",
|
|
48
|
+
"skill/playwright-e2e-mcp",
|
|
45
49
|
"README.md",
|
|
46
50
|
"LICENSE"
|
|
47
51
|
],
|
package/skill/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Agent skill: playwright-e2e-mcp
|
|
2
|
+
|
|
3
|
+
`playwright-e2e-mcp/` is an [Agent Skill](https://agentskills.io/specification)
|
|
4
|
+
that teaches an agent when and how to use this repo's MCP server: the run, read
|
|
5
|
+
the failure, inspect, validate, fix and re-run loop, self-healing fixes with
|
|
6
|
+
`suggest-fix`, signed-in page inspection, background runs, run-history triage,
|
|
7
|
+
flaky-test diagnosis, test generation and visual comparison. It targets
|
|
8
|
+
playwright-e2e-mcp 0.3.0 (and works with 0.2.0 or newer). It works with any agent that reads
|
|
9
|
+
`SKILL.md` skills (Claude Code, Codex CLI, OpenClaw and others) once the MCP
|
|
10
|
+
server is connected.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
playwright-e2e-mcp/
|
|
14
|
+
├── SKILL.md # when to use the skill and the step-by-step workflow
|
|
15
|
+
└── references/
|
|
16
|
+
├── setup.md # server install per client, env vars, skill install
|
|
17
|
+
├── tools.md # every tool's arguments
|
|
18
|
+
├── failure-kinds.md # failure kinds, error codes and what to do
|
|
19
|
+
└── example-session.md # a worked fix-a-failing-test session
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The skill contains only Markdown: no scripts, binaries or symlinks, and no
|
|
23
|
+
credentials.
|
|
24
|
+
|
|
25
|
+
## Packaging for a marketplace (Agensi)
|
|
26
|
+
|
|
27
|
+
Agensi expects one top-level folder named after the skill, with `SKILL.md` at
|
|
28
|
+
its root, text files only and no OS junk files. From this `skill/` directory:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
zip -r playwright-e2e-mcp.zip playwright-e2e-mcp -x "*.DS_Store" "*Thumbs.db"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Keep the skill's `name` in `SKILL.md` equal to the folder name.
|
|
@@ -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).
|