You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
**Universal e2e testing skill for Claude Code.** Заменяет ad-hoc промпты с Playwright MCP на одну переиспользуемую сущность для тестирования любого web-приложения (Next.js, FastAPI, статика, Telegram WebApp, и т.д.).
**The problem:** screenshots burn Claude Code's parent-chat **image cap** (~50–100 inline image blocks per session) before they burn its text context. Standalone Playwright MCP usage hits this wall fast. Once hit, the user must `/compact` even at 20% text-context usage.
26
+
**The problem:** Claude Code has two independent context limits — text tokens (large)
27
+
and **inline-image blocks** (~50–100 per session). Screenshots returned inline burn
28
+
the image budget far faster than the text budget; once exhausted, the user must
29
+
`/compact` even at 20% text-context usage.
30
+
31
+
**Distinction that matters:**
32
+
- ❌ **Inline image returns to parent context** burn the budget. This includes
33
+
`browser_take_screenshot` default output (image returned to caller),
34
+
`Read` on a `.png/.jpg/.webp/.gif/.bmp/.svg`, markdown report with `![]()` shown
35
+
to parent.
36
+
- ✅ **On-disk artefacts that nobody Reads** are FREE. Playwright's failure
37
+
screenshots go to `test-results/`, MCP browser tools may save `.png`s to a
38
+
cache dir — none of these cost the parent context UNLESS you `Read` them.
27
39
28
40
**The hard rule, enforced by you (not by frontmatter):**
29
41
30
-
> **NEVER call `Playwright:browser_take_screenshot`, `chrome-devtools:take_screenshot`, or `Read` on `.png/.jpg/.webp` files from the parent skill context. ALWAYS dispatch a Task subagent (general-purpose) to do anything that produces or consumes images. Subagent returns ONLY text — paths, descriptions, verdicts.**
42
+
> **NEVER return screenshots to the parent skill context. ALWAYS dispatch a Task
43
+
> subagent (general-purpose) for anything that produces or consumes images.
44
+
> Subagent returns ONLY text — paths, descriptions, verdicts.**
31
45
32
46
This contract was attempted via `context: fork` frontmatter but Claude Code 2.1.x on Windows does not honor that field, so enforcement is delegated to *you reading these instructions*. Verified empirically 2026-04-28 (sub-agent isolation works; `context: fork` does not parse). See `${CLAUDE_SKILL_DIR}/.isolation-verified`.
33
47
@@ -101,12 +115,33 @@ Copy this checklist into TodoWrite at session start; tick as you go.
101
115
- First run → minimal critical-path: home + auth + one main flow
102
116
-[ ]**4. Dev server up.**`python "${CLAUDE_SKILL_DIR}/scripts/with_server.py" --help`. Use it; **do not read its source unless `--help` doesn't cover the case.**
103
117
-[ ]**5a. EXPLORATORY** (BOOTSTRAP / new flow in HYBRID): use **Playwright MCP** with `Playwright:browser_snapshot` (ARIA tree, text). Walk the flow, generate POM in `tests/pages/<Page>.ts`, generate spec in `tests/specs/<flow>.spec.ts`. **Generate locators from ARIA tree refs you actually saw** — do NOT use generic regex like `getByPlaceholder(/john doe|name|имя/i)`, they cause strict-mode violations on first run. Either use exact strings from the snapshot OR add `.first()` explicitly. Run the spec once to confirm green.
118
+
119
+
**🔴 SPEC GENERATION CONTRACT — non-negotiable.** Even if you skip the template
120
+
and write a spec from scratch (when product context is rich), every generated
121
+
`*.spec.ts` MUST contain ALL of these:
122
+
1.**Console listeners attached BEFORE `page.goto()`**: `consoleErrors[]` from
123
+
`page.on('pageerror')` and `page.on('console', m => m.type() === 'error')`.
124
+
2.**Network listeners attached BEFORE `page.goto()`**: `failedRequests[]` from
125
+
`page.on('response', r => r.status() >= 400 && ...)` and `page.on('requestfailed')`.
126
+
3.**`AxeBuilder` scan** with `withTags(['wcag2a','wcag2aa','wcag21aa','wcag22aa'])`
127
+
whose violations are pushed into `issues[]`.
128
+
4.**`issues[]` collector pattern** — every soft check pushes a structured tag
129
+
into `issues` (e.g. `a11y[serious] color-contrast: ...`, `heading-jump: ...`,
Skip ANY of these and the skill's console-audit / a11y / per-issue fingerprinting
137
+
features stop working. Use `templates/spec.ts.tmpl` as the canonical reference —
138
+
copy its skeleton into hand-written specs.
104
139
-[ ]**5b. REPLAY**: `npx playwright test --reporter=list,json,html`. **No Playwright MCP, no LLM browser actions.**
105
140
-[ ]**6. A11y** on each visited page: deterministic `@axe-core/playwright` (in spec) + qualitative checks via nested subagent if alt-text/heading/focus suspect. See `reference/a11y-patterns.md`.
106
141
-[ ]**7. Console + network.** Listeners attach BEFORE `page.goto()` (mandatory). Pipe captured logs through `python "${CLAUDE_SKILL_DIR}/scripts/triage_console.py" --help`.
107
142
-[ ]**8. Visual.** Default `toHaveScreenshot()` in spec. Diff fired → `python "${CLAUDE_SKILL_DIR}/scripts/visual_diff.py" --classify` spawns nested subagent on each failed image (text verdict only). Argos opt-in via `VISUAL_DIFF=argos`.
-[ ]**10. Report.**`python "${CLAUDE_SKILL_DIR}/scripts/generate_report.py" --run-dir reports/<run-id> [--app-name "My App"]`. Reads `bugs.json` + `diff.json` from that dir, writes `report.md` + `index.html` next to them. Print absolute path to `index.html`.
110
145
111
146
## Decision tree
112
147
@@ -155,7 +190,7 @@ detect_state.py → JSON
155
190
-`scripts/triage_console.py --input console.json` — noise filter + LLM long tail
Copy file name to clipboardExpand all lines: reference/playwright-patterns.md
+22Lines changed: 22 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -37,6 +37,28 @@ These poll automatically. Prefer them over manual loops or `waitForTimeout`.
37
37
38
38
`expect(locator).toBeVisible()` waits up to the test/expect timeout; `locator.isVisible()` returns immediately and is non-retrying — correct for branching, wrong for assertions.
39
39
40
+
## Tabs vs buttons (common a11y miss)
41
+
42
+
Many SPAs (Tailwind / headless-UI / radix without `Tabs` primitive) render
43
+
visual tab UIs using `<button>` elements WITHOUT `role="tab"`. Result:
44
+
45
+
```ts
46
+
// FAILS — locator returns 0 elements because there is no role=tab anywhere
0 commit comments