playwright-e2e-mcp 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +55 -20
  2. package/dist/cli/ci.d.ts +5 -0
  3. package/dist/cli/ci.js +97 -5
  4. package/dist/cli/ci.js.map +1 -1
  5. package/dist/cli/doctor.d.ts +31 -0
  6. package/dist/cli/doctor.js +200 -0
  7. package/dist/cli/doctor.js.map +1 -0
  8. package/dist/cli/init.js +2 -1
  9. package/dist/cli/init.js.map +1 -1
  10. package/dist/cli/review.d.ts +50 -0
  11. package/dist/cli/review.js +148 -0
  12. package/dist/cli/review.js.map +1 -0
  13. package/dist/http.d.ts +14 -1
  14. package/dist/http.js +43 -8
  15. package/dist/http.js.map +1 -1
  16. package/dist/index.js +10 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/oauth.d.ts +10 -0
  19. package/dist/oauth.js +29 -1
  20. package/dist/oauth.js.map +1 -1
  21. package/dist/server.d.ts +2 -2
  22. package/dist/server.js +35 -3
  23. package/dist/server.js.map +1 -1
  24. package/dist/tools/audit-accessibility.d.ts +21 -0
  25. package/dist/tools/audit-accessibility.js +8 -1
  26. package/dist/tools/audit-accessibility.js.map +1 -1
  27. package/dist/tools/audit-performance.d.ts +21 -0
  28. package/dist/tools/audit-performance.js +13 -1
  29. package/dist/tools/audit-performance.js.map +1 -1
  30. package/dist/tools/audit-tests.d.ts +62 -0
  31. package/dist/tools/audit-tests.js +209 -0
  32. package/dist/tools/audit-tests.js.map +1 -0
  33. package/dist/tools/bisect-failure.d.ts +42 -0
  34. package/dist/tools/bisect-failure.js +291 -0
  35. package/dist/tools/bisect-failure.js.map +1 -0
  36. package/dist/tools/compare-visual-state.d.ts +21 -0
  37. package/dist/tools/diagnose-flaky.js +20 -3
  38. package/dist/tools/diagnose-flaky.js.map +1 -1
  39. package/dist/tools/get-failure.js +11 -2
  40. package/dist/tools/get-failure.js.map +1 -1
  41. package/dist/tools/get-run-status.js +4 -3
  42. package/dist/tools/get-run-status.js.map +1 -1
  43. package/dist/tools/inspect-page.d.ts +21 -0
  44. package/dist/tools/list-tests.js +5 -1
  45. package/dist/tools/list-tests.js.map +1 -1
  46. package/dist/tools/probe-script.js +23 -1
  47. package/dist/tools/probe-script.js.map +1 -1
  48. package/dist/tools/run-test.js +3 -2
  49. package/dist/tools/run-test.js.map +1 -1
  50. package/dist/tools/shared.d.ts +17 -1
  51. package/dist/tools/shared.js +44 -3
  52. package/dist/tools/shared.js.map +1 -1
  53. package/dist/tools/structured.d.ts +326 -0
  54. package/dist/tools/structured.js +170 -0
  55. package/dist/tools/structured.js.map +1 -0
  56. package/dist/tools/suggest-fix.js +14 -4
  57. package/dist/tools/suggest-fix.js.map +1 -1
  58. package/dist/tools/validate-selector.d.ts +21 -0
  59. package/dist/utils/attempt-limiter.d.ts +31 -0
  60. package/dist/utils/attempt-limiter.js +58 -0
  61. package/dist/utils/attempt-limiter.js.map +1 -0
  62. package/dist/utils/bisect.d.ts +31 -0
  63. package/dist/utils/bisect.js +47 -0
  64. package/dist/utils/bisect.js.map +1 -0
  65. package/dist/utils/flake-rules.d.ts +46 -0
  66. package/dist/utils/flake-rules.js +327 -0
  67. package/dist/utils/flake-rules.js.map +1 -0
  68. package/package.json +5 -4
  69. package/skill/playwright-e2e-mcp/SKILL.md +14 -2
  70. package/skill/playwright-e2e-mcp/references/setup.md +2 -2
  71. package/skill/playwright-e2e-mcp/references/tools.md +32 -0
@@ -0,0 +1,327 @@
1
+ /**
2
+ * Flake-risk rules for Playwright test code: patterns that make tests
3
+ * pass or fail by timing rather than by what the app does (hard waits,
4
+ * assertions that read once instead of retrying, promises nobody awaits,
5
+ * selectors tied to layout). Each finding says why it is risky, and the
6
+ * mechanical ones carry the replacement line.
7
+ *
8
+ * The scan is line based, not a TypeScript parse: it skips comments and
9
+ * aims for few false alarms over catching every case.
10
+ */
11
+ export const SEVERITY_WEIGHT = { high: 5, medium: 2, low: 1 };
12
+ export const RULES = {
13
+ 'hard-wait': {
14
+ severity: 'high',
15
+ message: 'Fixed wait: too short on a slow run, wasted time on a fast one. Wait for the state instead (a web-first assertion, waitForURL or waitForResponse).',
16
+ },
17
+ sleep: {
18
+ severity: 'high',
19
+ message: 'setTimeout sleep: the same problem as waitForTimeout, hidden from Playwright. Wait for the state instead.',
20
+ },
21
+ 'non-retrying-assertion': {
22
+ severity: 'high',
23
+ message: 'Reads the page once and asserts on the value, so it fails if the page is a moment late. A web-first assertion retries until it holds.',
24
+ },
25
+ 'missing-await': {
26
+ severity: 'high',
27
+ message: 'Not awaited: the test moves on (or ends) before this finishes, so a failure is lost or lands in another step.',
28
+ },
29
+ 'focused-test': {
30
+ severity: 'high',
31
+ message: '.only left in: every other test in the run is skipped (and forbidOnly fails CI).',
32
+ },
33
+ 'force-action': {
34
+ severity: 'medium',
35
+ message: 'force: true skips the actionability checks, so the action can hit a covered, moving or disabled element that a user could not.',
36
+ },
37
+ networkidle: {
38
+ severity: 'medium',
39
+ message: "networkidle waits for 500 ms without traffic, which polling, analytics or websockets can stop from ever happening. Playwright discourages it; wait for what the test needs.",
40
+ },
41
+ 'element-handle': {
42
+ severity: 'medium',
43
+ message: 'ElementHandle API: the handle goes stale when the page re-renders. Locators re-resolve on every use.',
44
+ },
45
+ 'fragile-selector': {
46
+ severity: 'medium',
47
+ message: 'Selector tied to layout or generated class names: it breaks when markup moves. Prefer getByRole, getByLabel, getByText or getByTestId.',
48
+ },
49
+ 'no-timeout': {
50
+ severity: 'medium',
51
+ message: 'timeout: 0 means wait forever: a missed state hangs the run until the global timeout instead of failing at this step.',
52
+ },
53
+ 'hardcoded-url': {
54
+ severity: 'low',
55
+ message: 'Hard-coded local URL: set baseURL in the config and goto a path, so the test runs against any environment.',
56
+ },
57
+ 'serial-mode': {
58
+ severity: 'low',
59
+ message: 'Serial mode: tests depend on each other, so one failure skips the rest and retries re-run the whole group.',
60
+ },
61
+ };
62
+ /* ------------------------------------------------------------------ */
63
+ /* Small parsing helpers */
64
+ /* ------------------------------------------------------------------ */
65
+ /** Index of the bracket closing the one at `open`, skipping quoted strings; -1 if unbalanced. */
66
+ export function matchBracket(text, open) {
67
+ const pairs = { '(': ')', '[': ']', '{': '}' };
68
+ const stack = [];
69
+ let quote = '';
70
+ for (let i = open; i < text.length; i += 1) {
71
+ const ch = text[i];
72
+ if (quote) {
73
+ if (ch === '\\')
74
+ i += 1;
75
+ else if (ch === quote)
76
+ quote = '';
77
+ continue;
78
+ }
79
+ if (ch === '"' || ch === "'" || ch === '`')
80
+ quote = ch;
81
+ else if (pairs[ch])
82
+ stack.push(pairs[ch]);
83
+ else if (ch === ')' || ch === ']' || ch === '}') {
84
+ if (stack.pop() !== ch)
85
+ return -1;
86
+ if (stack.length === 0)
87
+ return i;
88
+ }
89
+ }
90
+ return -1;
91
+ }
92
+ /** Splits `target.method(args)` into its parts when `expr` ends in a call. */
93
+ function trailingCall(expr) {
94
+ const trimmed = expr.trim();
95
+ if (!trimmed.endsWith(')'))
96
+ return undefined;
97
+ // Walk back to the call's opening parenthesis.
98
+ for (let open = trimmed.lastIndexOf('('); open >= 0; open = trimmed.lastIndexOf('(', open - 1)) {
99
+ if (matchBracket(trimmed, open) !== trimmed.length - 1)
100
+ continue;
101
+ const head = /\.(\w+)\s*$/.exec(trimmed.slice(0, open));
102
+ if (!head)
103
+ return undefined;
104
+ return { target: trimmed.slice(0, head.index), method: head[1], args: trimmed.slice(open + 1, -1).trim() };
105
+ }
106
+ return undefined;
107
+ }
108
+ const STATE_MATCHERS = {
109
+ isVisible: 'toBeVisible',
110
+ isHidden: 'toBeHidden',
111
+ isEnabled: 'toBeEnabled',
112
+ isDisabled: 'toBeDisabled',
113
+ isChecked: 'toBeChecked',
114
+ isEditable: 'toBeEditable',
115
+ };
116
+ /**
117
+ * The web-first form of a one-shot assertion, e.g.
118
+ * `expect(await x.isVisible()).toBe(true)` → `await expect(x).toBeVisible()`.
119
+ * Returns the whole rewritten line, or undefined when the line is not one
120
+ * this knows how to rewrite.
121
+ */
122
+ export function webFirstRewrite(line) {
123
+ const start = /\bexpect\(/.exec(line);
124
+ if (!start)
125
+ return undefined;
126
+ const open = start.index + 'expect'.length;
127
+ const close = matchBracket(line, open);
128
+ if (close < 0)
129
+ return undefined;
130
+ const inner = line.slice(open + 1, close).trim();
131
+ const after = line.slice(close + 1);
132
+ const assertion = /^\s*\.(not\.)?(toBe|toEqual|toStrictEqual|toBeTruthy|toBeFalsy|toContain)\(/.exec(after);
133
+ if (!assertion)
134
+ return undefined;
135
+ const argsOpen = assertion[0].length - 1;
136
+ const argsClose = matchBracket(after, argsOpen);
137
+ if (argsClose < 0)
138
+ return undefined;
139
+ const expected = after.slice(argsOpen + 1, argsClose).trim();
140
+ const tail = after.slice(argsClose + 1);
141
+ let negated = Boolean(assertion[1]);
142
+ const matcher = assertion[2];
143
+ const equality = matcher === 'toBe' || matcher === 'toEqual' || matcher === 'toStrictEqual';
144
+ let target;
145
+ let web;
146
+ let webArgs = '';
147
+ if (/^page\.url\(\)$/.test(inner)) {
148
+ if (!equality)
149
+ return undefined;
150
+ target = 'page';
151
+ web = 'toHaveURL';
152
+ webArgs = expected;
153
+ }
154
+ else {
155
+ if (!inner.startsWith('await '))
156
+ return undefined;
157
+ const call = trailingCall(inner.slice('await '.length));
158
+ if (!call || call.target.trim() === '')
159
+ return undefined;
160
+ target = call.target.trim();
161
+ if (STATE_MATCHERS[call.method] && call.args === '') {
162
+ if (matcher === 'toBeTruthy' || (equality && expected === 'true'))
163
+ web = STATE_MATCHERS[call.method];
164
+ else if (matcher === 'toBeFalsy' || (equality && expected === 'false')) {
165
+ web = STATE_MATCHERS[call.method];
166
+ negated = !negated;
167
+ }
168
+ else
169
+ return undefined;
170
+ }
171
+ else if ((call.method === 'textContent' || call.method === 'innerText') && call.args === '') {
172
+ if (equality)
173
+ web = 'toHaveText';
174
+ else if (matcher === 'toContain')
175
+ web = 'toContainText';
176
+ else
177
+ return undefined;
178
+ webArgs = expected;
179
+ }
180
+ else if (call.method === 'inputValue' && call.args === '' && equality) {
181
+ web = 'toHaveValue';
182
+ webArgs = expected;
183
+ }
184
+ else if (call.method === 'count' && call.args === '' && equality) {
185
+ web = 'toHaveCount';
186
+ webArgs = expected;
187
+ }
188
+ else if (call.method === 'getAttribute' && call.args !== '' && equality) {
189
+ web = 'toHaveAttribute';
190
+ webArgs = `${call.args}, ${expected}`;
191
+ }
192
+ else if (call.method === 'title' && call.args === '' && target === 'page' && equality) {
193
+ web = 'toHaveTitle';
194
+ webArgs = expected;
195
+ }
196
+ else
197
+ return undefined;
198
+ }
199
+ const prefix = line.slice(0, start.index);
200
+ const awaited = /\bawait\s*$/.test(prefix) ? prefix : `${prefix}await `;
201
+ return `${awaited}expect(${target})${negated ? '.not' : ''}.${web}(${webArgs})${tail}`;
202
+ }
203
+ const ASYNC_MATCHERS = /\.(?:not\.)?(toBeVisible|toBeHidden|toBeEnabled|toBeDisabled|toBeChecked|toBeEditable|toBeFocused|toBeAttached|toBeInViewport|toBeEmpty|toHaveText|toContainText|toHaveValue|toHaveValues|toHaveCount|toHaveAttribute|toHaveClass|toContainClass|toHaveCSS|toHaveId|toHaveJSProperty|toHaveURL|toHaveTitle|toHaveScreenshot|toMatchAriaSnapshot|toHaveAccessibleName|toHaveAccessibleDescription|toHaveRole|toPass)\(/;
204
+ const PAGE_ACTIONS = /\.(goto|click|dblclick|fill|press|pressSequentially|type|check|uncheck|setChecked|selectOption|setInputFiles|hover|tap|focus|blur|clear|reload|goBack|goForward|waitForURL|waitForLoadState|dragTo|dragAndDrop|setViewportSize|screenshot)\(/;
205
+ const TEST_TITLE = /\btest(?:\.(?:only|fixme|skip|slow|fail))?\(\s*(['"`])((?:\\.|(?!\1).)+)\1/;
206
+ function selectorRisk(selector) {
207
+ const s = selector.trim();
208
+ if (/^(xpath=|\/\/|\(\/\/|\.\.\/)/.test(s))
209
+ return true;
210
+ if (/:nth-(child|of-type)\(/.test(s))
211
+ return true;
212
+ // Hashed class names from CSS-in-JS and CSS modules.
213
+ if (/\.(css|sc|jsx|emotion)-[a-z0-9]{5,}/i.test(s) || /\.[A-Za-z]+_[A-Za-z]+__[A-Za-z0-9]{5}/.test(s))
214
+ return true;
215
+ // A long chain of descendant or child steps.
216
+ const steps = s.replace(/\[[^\]]*\]|\([^)]*\)|"[^"]*"|'[^']*'/g, '').split(/\s*>\s*|\s+/).filter(Boolean);
217
+ return steps.length >= 4;
218
+ }
219
+ /** The statement starting at `index`: that line plus following lines until one ends it (at most six). */
220
+ function statementFrom(lines, index) {
221
+ const parts = [];
222
+ for (let i = index; i < lines.length && i < index + 6; i += 1) {
223
+ parts.push(lines[i].trim());
224
+ if (/[;{}]\s*$/.test(lines[i]) || (i > index && lines[i].trim() === ''))
225
+ break;
226
+ }
227
+ return parts.join(' ');
228
+ }
229
+ /** Scan one spec file's source. `file` is only copied into the findings. */
230
+ export function scanFlakeRisks(file, source) {
231
+ const lines = source.split(/\r?\n/);
232
+ const findings = [];
233
+ let inBlockComment = false;
234
+ let currentTest;
235
+ const add = (index, rule, fix) => {
236
+ const lineText = lines[index];
237
+ findings.push({
238
+ file,
239
+ line: index + 1,
240
+ rule,
241
+ severity: RULES[rule].severity,
242
+ message: RULES[rule].message,
243
+ code: lineText.trim(),
244
+ ...(fix !== undefined && fix !== lineText ? { fix } : {}),
245
+ ...(currentTest ? { test: currentTest } : {}),
246
+ });
247
+ };
248
+ for (let i = 0; i < lines.length; i += 1) {
249
+ const raw = lines[i];
250
+ const trimmed = raw.trim();
251
+ if (inBlockComment) {
252
+ if (trimmed.includes('*/'))
253
+ inBlockComment = false;
254
+ continue;
255
+ }
256
+ if (trimmed.startsWith('/*')) {
257
+ if (!trimmed.includes('*/'))
258
+ inBlockComment = true;
259
+ continue;
260
+ }
261
+ if (trimmed === '' || trimmed.startsWith('//') || trimmed.startsWith('*'))
262
+ continue;
263
+ // Drop a trailing line comment (not `://` inside a URL).
264
+ const code = raw.replace(/(^|[^:'"`])\/\/.*$/, '$1');
265
+ const title = TEST_TITLE.exec(code);
266
+ if (title && !/\btest\.(describe|step|use|beforeEach|afterEach|beforeAll|afterAll|extend)\b/.test(code))
267
+ currentTest = title[2];
268
+ if (/\.waitForTimeout\(/.test(code))
269
+ add(i, 'hard-wait');
270
+ if (/new Promise\(\s*\(?\s*\w*\s*\)?\s*=>\s*setTimeout\(/.test(code) || /\bsetTimeout\(\s*\w+\s*,\s*\d+\s*\)\s*\)/.test(code))
271
+ add(i, 'sleep');
272
+ if (/\bexpect\(\s*(await\s+[^;]*\.(isVisible|isHidden|isEnabled|isDisabled|isChecked|isEditable|textContent|innerText|inputValue|count|getAttribute)\(|page\.url\(\)\s*\)\s*\.(not\.)?(toBe|toEqual|toStrictEqual)\()/.test(code)) {
273
+ add(i, 'non-retrying-assertion', webFirstRewrite(raw));
274
+ }
275
+ else if (/^(expect(\.soft)?\(|expect\.poll\()/.test(trimmed)) {
276
+ const statement = statementFrom(lines, i);
277
+ if (trimmed.startsWith('expect.poll(') || ASYNC_MATCHERS.test(statement)) {
278
+ add(i, 'missing-await', raw.replace(/^(\s*)/, '$1await '));
279
+ }
280
+ }
281
+ else if (/^page\.\w/.test(trimmed)) {
282
+ const statement = statementFrom(lines, i);
283
+ if (PAGE_ACTIONS.test(statement) && !/,\s*$/.test(statement) && !/^page\.(on|once|off|route|unroute)\(/.test(trimmed)) {
284
+ add(i, 'missing-await', raw.replace(/^(\s*)/, '$1await '));
285
+ }
286
+ }
287
+ if (/\b(test|describe)(\.describe)?\.only\(/.test(code))
288
+ add(i, 'focused-test', raw.replace(/\.only\(/, '('));
289
+ if (/\bforce\s*:\s*true\b/.test(code))
290
+ add(i, 'force-action');
291
+ if (/['"`]networkidle['"`]/.test(code))
292
+ add(i, 'networkidle');
293
+ if (/\bpage\.(\$|\$\$|\$eval|\$\$eval)\(|\.waitForSelector\(|\.elementHandles?\(/.test(code))
294
+ add(i, 'element-handle');
295
+ for (const m of code.matchAll(/(?:\.locator|\.\$\$?|waitForSelector)\(\s*(['"`])((?:\\.|(?!\1).)+)\1/g)) {
296
+ if (selectorRisk(m[2])) {
297
+ add(i, 'fragile-selector');
298
+ break;
299
+ }
300
+ }
301
+ if (/\btimeout\s*:\s*0\b/.test(code) || /setTimeout\(\s*0\s*\)|setDefaultTimeout\(\s*0\s*\)/.test(code))
302
+ add(i, 'no-timeout');
303
+ if (/\.goto\(\s*['"`]https?:\/\/(localhost|127\.0\.0\.1|0\.0\.0\.0)[:/'"`]/.test(code))
304
+ add(i, 'hardcoded-url');
305
+ if (/mode\s*:\s*['"`]serial['"`]/.test(code))
306
+ add(i, 'serial-mode');
307
+ }
308
+ return findings;
309
+ }
310
+ /** Apply every finding's fix to the source, line by line. Findings must belong to this source. */
311
+ export function applyFlakeFixes(source, findings) {
312
+ const eol = source.includes('\r\n') ? '\r\n' : '\n';
313
+ const lines = source.split(/\r?\n/);
314
+ const applied = [];
315
+ const done = new Set();
316
+ for (const finding of findings) {
317
+ if (finding.fix === undefined || done.has(finding.line))
318
+ continue;
319
+ if (lines[finding.line - 1]?.trim() !== finding.code)
320
+ continue;
321
+ lines[finding.line - 1] = finding.fix;
322
+ done.add(finding.line);
323
+ applied.push(finding);
324
+ }
325
+ return { source: lines.join(eol), applied };
326
+ }
327
+ //# sourceMappingURL=flake-rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flake-rules.js","sourceRoot":"","sources":["../../src/utils/flake-rules.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.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "MCP server and agent skill that run, diagnose and fix failing Playwright tests: CI report diagnosis, trace analysis, verified locator fixes, flaky verdicts, breaking commits, tests written by walking the flow, accessibility and Web Vitals audits.",
5
5
  "author": "xsignon-secure (https://github.com/xsignon-secure)",
6
6
  "mcpName": "io.github.xsignon-secure/E2E",
@@ -60,6 +60,7 @@
60
60
  "prepare": "npm run build",
61
61
  "watch": "tsc -p tsconfig.json --watch",
62
62
  "test": "npm run build && node test/run-tests.mjs",
63
+ "coverage": "npm run build && node test/run-tests.mjs --coverage",
63
64
  "e2e": "npm run build && node e2e/run.mjs",
64
65
  "mcpb": "npm run build && node scripts/build-mcpb.mjs",
65
66
  "mcpb:smoke": "npm run mcpb && node scripts/mcpb-launch-sim.mjs && node scripts/mcpb-client-check.mjs",
@@ -73,16 +74,16 @@
73
74
  "prepublishOnly": "npm test"
74
75
  },
75
76
  "engines": {
76
- "node": ">=20"
77
+ "node": ">=22"
77
78
  },
78
79
  "dependencies": {
79
- "@modelcontextprotocol/server": "^2.3.1",
80
+ "@modelcontextprotocol/server": "^2.4.0",
80
81
  "axe-core": "^4.14.0",
81
82
  "zod": "^4.2.0"
82
83
  },
83
84
  "devDependencies": {
84
85
  "@anthropic-ai/mcpb": "^2.1.2",
85
- "@modelcontextprotocol/client": "^2.3.1",
86
+ "@modelcontextprotocol/client": "^2.4.0",
86
87
  "@playwright/test": "1.64.1",
87
88
  "@sparticuz/chromium": "153.0.0",
88
89
  "@types/node": "^26.6.5",
@@ -13,7 +13,7 @@ and concrete next steps. It can also propose and apply a verified fix for a brok
13
13
  locator, inspect pages behind a login, run long suites in the background and keep
14
14
  a local history of every run.
15
15
 
16
- This skill is written for playwright-e2e-mcp 0.5.1 and works with 0.2.0 or
16
+ This skill is written for playwright-e2e-mcp 0.6.0 and works with 0.2.0 or
17
17
  newer. If `suggest-fix`, `get-run-status` or `analyze-history` is missing, the
18
18
  server is older than 0.2.0: use the steps that do not need those tools and tell
19
19
  the user to update it. `diagnose-flaky`'s per-test table and `isolate` option
@@ -148,6 +148,16 @@ re-runs the fix locally. If it says traces were not found, pass `traceDirs` with
148
148
  the folder where `test-results` was unpacked. The run is added to the history
149
149
  with its commit.
150
150
 
151
+ ## A test that used to pass
152
+
153
+ When a test fails at HEAD but passed at some earlier commit, call
154
+ `bisect-failure` (0.6.0+) `{ "test": "tests/cart.spec.ts", "grep": "adds an item" }`.
155
+ It runs the test across git history in a temporary worktree (the checkout is not
156
+ touched) and names the first bad commit with its diff summary. Pass `good` (a
157
+ tag or `HEAD~30`) when the run history has no passing run of it; pass `repeat: 3`
158
+ when the failure is intermittent. Read that commit's change before editing the
159
+ test: the fix usually belongs in the app.
160
+
151
161
  ## Flaky or intermittent failures
152
162
 
153
163
  Start with `analyze-history` (default view `flaky`) to see which tests flip
@@ -164,6 +174,8 @@ one verdict **per test** (passes, failures, duration spread, first error):
164
174
  missing awaits, assertions without auto-waiting, shared state between tests and
165
175
  fixed `waitForTimeout` sleeps. Never "fix" flakiness by only adding retries or
166
176
  sleeps.
177
+ `audit-tests` (0.6.0+) finds these in the test code and names the ones in
178
+ tests that flaked; `fix: true` applies the mechanical rewrites and re-runs them.
167
179
  - **NOT REPRODUCING**: passed every run. Report that the failure was one-off.
168
180
 
169
181
  When a test is FLAKY and the suite runs in parallel, call `diagnose-flaky` again
@@ -227,7 +239,7 @@ with the commit it tested. `analyze-history` views:
227
239
  `selector` for one region) returns the accessibility snapshot and a
228
240
  `toMatchAriaSnapshot` assertion to paste into a spec.
229
241
  - **Set up CI:** when the user wants the same diagnosis on every pull request,
230
- point them to the GitHub Action (`uses: xsignon-secure/E2E@v0.5.1`) or the
242
+ point them to the GitHub Action (`uses: xsignon-secure/E2E@v0.6.0`) or the
231
243
  `npx -y playwright-e2e-mcp ci` command in `references/setup.md`. It writes the
232
244
  run, flaky verdicts and fix diffs to the job summary and one PR comment.
233
245
  - **Accessibility:** `audit-accessibility` with `url` runs axe-core against
@@ -12,7 +12,7 @@ This skill only gives the agent instructions. The tools come from the
12
12
  (needs Playwright 1.64+) and root-cause grouping in 0.4.0. Check with
13
13
  `npx -y playwright-e2e-mcp --version`.
14
14
 
15
- - Node.js 20 or newer.
15
+ - Node.js 22 or newer.
16
16
  - A project with `@playwright/test` installed and a browser available:
17
17
  `npx playwright install chromium`.
18
18
 
@@ -112,7 +112,7 @@ Exit code 0 means passed, 1 tests failed, 2 the run itself failed. On GitHub
112
112
  Actions it also writes to the job summary. As an Action:
113
113
 
114
114
  ```yaml
115
- - uses: xsignon-secure/E2E@v0.5.1
115
+ - uses: xsignon-secure/E2E@v0.6.0
116
116
  with:
117
117
  flaky-runs: 3
118
118
  suggest: 2
@@ -245,3 +245,35 @@ Reads `.playwright-e2e-mcp/history.jsonl`, written by every run
245
245
  passing runs and flags ones that got slower; `trend` shows failed and flaky
246
246
  executions per day; `commits` names, per failing or flaky test, the first bad
247
247
  commit after its last passing streak and the last good one.
248
+
249
+ ## audit-tests (0.6.0+)
250
+
251
+ | Argument | Type | Notes |
252
+ | --- | --- | --- |
253
+ | `testDir` / `filter` | string | Narrow the files |
254
+ | `minSeverity` | `low` \| `medium` \| `high` | Default `low` |
255
+ | `historyRuns` | number | Default 50 |
256
+ | `limit` | number | Findings listed, default 50 |
257
+ | `fix` | boolean | Rewrite mechanical findings, re-run touched files, revert on failure |
258
+ | `verify` | boolean | Default true |
259
+
260
+ Rules: `hard-wait`, `sleep`, `non-retrying-assertion`, `missing-await`,
261
+ `focused-test` (high); `force-action`, `networkidle`, `element-handle`,
262
+ `fragile-selector`, `no-timeout` (medium); `hardcoded-url`, `serial-mode` (low).
263
+ Only `non-retrying-assertion`, `missing-await` and `focused-test` are fixed
264
+ mechanically. Files rank by findings weighted by their flaky rate in the history.
265
+
266
+ ## bisect-failure (0.6.0+)
267
+
268
+ | Argument | Type | Notes |
269
+ | --- | --- | --- |
270
+ | `test` | string | Spec file (required) |
271
+ | `grep` | string | Test title; better than `:line` across commits |
272
+ | `good` / `bad` | string | Commits or refs; `good` defaults to the newest passing commit in the history, `bad` to HEAD |
273
+ | `repeat` | number | Runs per commit (1–10) for intermittent failures |
274
+ | `maxSteps` | number | Default 12 |
275
+ | `stepTimeoutMs` | number | Default 180000 |
276
+
277
+ Runs in a temporary git worktree with the current `node_modules` linked in;
278
+ untestable commits are skipped. `status` is `found`, `ambiguous`, `max-steps`,
279
+ `not-failing` (passes at bad) or `good-fails`.