with one click
playwright-skill
Browser automation for web projects using playwright-cli
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Browser automation for web projects using playwright-cli
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
Architectural compliance and code quality rules for Node.js + TypeScript projects (Vue 3 frontend, Express + Socket.IO backend). Provides systematic review criteria for security, code organization, error handling, and project-specific conventions. Use when auditing code quality.
Mutation testing strategies and test-improvement patterns for TypeScript projects using Stryker Mutator with a Vitest runner. Provides guidance on interpreting mutation reports and improving tests to achieve higher kill rates. Use when analyzing mutation testing results.
Risk identification and test prioritization framework for Node.js + TypeScript projects (Vue 3 + Express + Socket.IO). Provides systematic approach to identifying potential issues and prioritizing testing efforts. Use when analyzing features for QA review.
Parses specification documents (EARS, Given-When-Then, SHALL clauses, user stories, tasks) from multiple layouts into a structured intermediate representation, then maps requirements to tests bidirectionally. Use when verifying implementation against a spec, auditing requirement coverage, or computing a traceability matrix.
Vitest testing patterns and templates for Node.js + TypeScript projects (Express backend, Vue 3 frontend). Provides comprehensive test writing guidance for unit, integration, component, and property-based tests. Use when generating or improving tests for the harness-visualizer.
Indexes, searches, and injects project spec files as agent memory. Use when starting work on a spec-driven project, searching for relevant specs, recalling past design decisions, archiving spec changes, or checking spec history. Supports both directory-style specs (specs/<name>/requirements.md|design.md|tasks.md) and flat-style specs (.claude/specs/active/<name>.md).
| name | playwright-skill |
| description | Browser automation for web projects using playwright-cli |
| version | 2.0.0 |
| allowed-tools | Bash(playwright-cli:*), Bash(bin/open), Bash(bin/close), Bash(bin/click-css), Bash(bin/fill-css), Bash(bin/upload), Bash(bin/auth-save), Bash(bin/auth-load), Bash(bin/context), Bash(bin/inject-capture), Bash(bin/cache-query) |
Browser automation using playwright-cli (Microsoft's official Playwright CLI). No daemon management required — the browser starts and stops automatically.
Always start with bin/open (not bare playwright-cli open):
bin/open --headed
playwright-cli goto <url>
bin/open derives a session name from the current directory (e.g. my-project), appends a short agent identifier when running under Claude Code, and starts the browser under that named session. All other bin/ scripts resolve the session automatically.
Session isolation: When CLAUDE_SESSION_ID is set (automatic in Claude Code), each agent gets its own session name (e.g. my-project-a1b2c3d4) and session file. Parallel agents never interfere with each other. If a session is already open for this agent, bin/open closes it first to prevent orphaned Chrome processes — other agents' sessions are unaffected.
Before opening a new session, check if you already have one:
playwright-cli list # see all open sessions
If your session is already listed and open, skip bin/open and use it directly.
At the end of a task, clean up with:
bin/close
This closes the browser and removes the session tracking file. If the browser is stuck use playwright-cli kill-all instead.
Overriding the session name:
bin/open --headed --session my-custom-name
After every command, stdout contains a link to the current accessibility tree:
### Snapshot
- [Snapshot](.playwright-cli/page-<timestamp>.yml)
Always read the snapshot file to see what's on the page:
Read .playwright-cli/page-<timestamp>.yml
The snapshot contains all interactive elements with [ref=eN] identifiers used for clicking, filling, and hovering.
playwright-cli goto <url> # navigate to URL
playwright-cli go-back # browser back
playwright-cli go-forward # browser forward
playwright-cli reload # reload page
playwright-cli click <ref> # click element
playwright-cli fill <ref> <value> # fill input (clears first)
playwright-cli type <text> # type text (appends)
playwright-cli press <key> # press key: Enter, Tab, Escape, Control+A
playwright-cli hover <ref> # hover to reveal menus/tooltips
playwright-cli select <ref> <val> # select dropdown option
playwright-cli snapshot # capture accessibility tree
playwright-cli screenshot # take screenshot
playwright-cli dialog-accept # accept alert/confirm/prompt
playwright-cli dialog-dismiss # dismiss dialog
bin/close # close browser session + clean up session file (preferred)
playwright-cli kill-all # force-kill all playwright-cli daemons (use when stuck)
playwright-cli list # list all open sessions
playwright-cli run-code '<async page => { }>' # run arbitrary Playwright JS
Use these when ARIA-ref commands fail — for example, when framework-rendered elements are outside the main ARIA tree.
Modal dialogs — often rendered as DOM portals:
bin/click-css "[data-modal-confirm]"
bin/click-css "button[data-dismiss]"
Hidden file inputs — often hidden from accessibility tree:
bin/upload "input[type=file]" /path/to/file.pdf
Framework event targets — ARIA-ref clicks don't always fire framework event handlers:
bin/fill-css "[data-field=email]" "user@example.com"
bin/click-css "[data-action=save]"
See skill/CONFIG.md for project-specific selector patterns.
Auth profile names and base URLs are defined in skill/worktrees.json (gitignored).
See skill/CONFIG.md for setup instructions.
Save after authenticating:
bin/auth-save <profile-name> # profile names from skill/worktrees.json
Restore on a new session:
bin/open --headed
playwright-cli goto <baseUrl> # baseUrl from skill/worktrees.json
bin/auth-load <profile-name>
playwright-cli goto <baseUrl>/dashboard
Profiles are stored in .playwright-skill/auth/ and gitignored.
| Problem | Solution |
|---|---|
| Browser stuck / daemon hung | playwright-cli kill-all then bin/open --headed |
| No session open (bin/context error) | bin/open --headed |
| Auth expired | bin/auth-load <profile> then reload |
| Element ref not found | playwright-cli snapshot then read the new snapshot file |
| Modal / framework component not clickable | Use bin/click-css with a CSS selector |
| Action has no visible effect | Tail your server log for a swallowed exception (see §9) |
| Page blank or error after action | Tail your server log for a swallowed exception (see §9) |
| End of task cleanup | bin/close |
# Wait for a specific element
playwright-cli run-code 'await page.waitForSelector(".loading-complete")'
# Dispatch a framework event (example: a global pub/sub or framework bus)
playwright-cli run-code 'await page.evaluate(() => window.dispatchEvent(new CustomEvent("refresh")))'
# Scroll to bottom
playwright-cli run-code 'await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight))'
# Get element count
playwright-cli run-code 'console.log(await page.locator("table tbody tr").count())'
Three tools integrate ResponseBuilder and CacheStore into the v2 skill, enabling rich page diagnostics.
| Command | Description |
|---|---|
bin/context [--screenshot] | Capture full page context → compact TrimmedResponse JSON on stdout |
bin/inject-capture | Inject browser-side console + fetch/XHR patching |
bin/cache-query <cmd> [args] | Query cached data by ID and type |
bin/contextCollects context from three sources and stores it in .playwright-skill/cache/:
playwright-cli snapshot — accessibility tree (YAML)playwright-cli console / playwright-cli network — native browser logsplaywright-cli run-code — page URL, title, HTML, cookies, injected capturesOutputs a TrimmedResponse (~200 tokens) with:
pageState — URL, title, auth status, error flagcacheRef.id — reference ID to retrieve full context latercacheRef.available — list of available data typesbin/context # text/ARIA capture only
bin/context --screenshot # also capture PNG screenshot
bin/inject-capturePatches console.*, window.fetch, and XMLHttpRequest in the browser to capture events in window.__capturedConsole and window.__capturedRequests. These are merged with playwright-layer captures by bin/context.
Idempotent — safe to run multiple times. Only captures events after injection.
bin/inject-capture
# → {"success":true,"hasCapture":true}
bin/cache-queryRetrieves full context stored by bin/context.
bin/cache-query query <id> snapshot # accessibility tree YAML
bin/cache-query query <id> html # full page HTML
bin/cache-query query <id> console # console messages JSON
bin/cache-query query <id> network # network requests JSON
bin/cache-query query <id> screenshot # base64-encoded PNG
bin/cache-query list # JSON array of all cached entries
bin/cache-query stats # entry count, total size, max entries
bin/cache-query clear # clear all entries
bin/cache-query clear <id> # clear one entry
# 1. Start browser and navigate
bin/open --headed
playwright-cli goto http://localhost:8000
bin/auth-load <profile>
# 2. Inject browser-side capture (optional but recommended)
bin/inject-capture
# 3. Perform actions (click, fill, navigate...)
playwright-cli click e5
playwright-cli fill e7 "search term"
playwright-cli press Enter
# 4. Capture full context
bin/context --screenshot
# Read cacheRef.id from the TrimmedResponse output
# 5. Diagnose issues
bin/cache-query query <id> console # check for JS errors
bin/cache-query query <id> network # check API responses
bin/cache-query query <id> snapshot # review page structure
bin/cache-query query <id> screenshot # view page visually (base64 PNG)
# 6. Clean up
bin/close
Multi-project / parallel agent note: When running under Claude Code, each agent automatically gets an isolated session via
CLAUDE_SESSION_ID. Directplaywright-clicommands (goto, click, fill, etc.) work as-is when only one session is open. If multiple sessions are active, prefix with-s=<session>— e.g.playwright-cli -s=my-project-a1b2c3d4 goto <url>. The session name is printed when you runbin/open.
bin/cache-query query <id> console | python3 -c "
import sys, json
msgs = json.load(sys.stdin)
errors = [m for m in msgs if m['type'] == 'error']
for e in errors:
print(e['text'])
"
When a page action fails silently (form doesn't submit, page goes blank, modal doesn't respond), the cause is often a server-side exception that Playwright can't see. The framework's error page often renders HTML that the accessibility tree can't meaningfully parse.
Set PLAYWRIGHT_SERVER_LOG in your environment (or per-project worktrees.json notes) to the path of your server log, then use the patterns below. The default examples assume $PLAYWRIGHT_SERVER_LOG.
Quick check — last 30 lines of the log:
tail -30 "$PLAYWRIGHT_SERVER_LOG"
Search for recent exceptions today:
grep -A 5 "$(date +'%Y-%m-%d')" "$PLAYWRIGHT_SERVER_LOG" \
| grep -A 5 "Exception\|Error\|Traceback\|SQLSTATE" \
| tail -40
Read only new lines since a known size:
# Before testing
wc -l "$PLAYWRIGHT_SERVER_LOG" # e.g., 1500 lines
# After a failure
tail -n +1501 "$PLAYWRIGHT_SERVER_LOG"
Drop a marker into the log so you can easily find new exceptions afterward:
echo "[$(date +'%Y-%m-%d %H:%M:%S')] QA-TEST-START" >> "$PLAYWRIGHT_SERVER_LOG"
# ... run tests ...
grep -A 9999 "QA-TEST-START" "$PLAYWRIGHT_SERVER_LOG" | tail -50
The patterns vary by framework — recognize the family rather than the exact string. Some recurring ones:
| Log Pattern | Likely Cause |
|---|---|
SQLSTATE[23505] / UNIQUE constraint failed | Unique constraint violation (duplicate insert) |
SQLSTATE[42703] / column ... does not exist | Missing migration |
SQLSTATE[23502] / NOT NULL constraint | Missing required field |
undefined method / NoMethodError / AttributeError | Method/attribute doesn't exist on model/class |
Class "..." not found / NameError / ImportError | Missing import or wrong namespace |
null / None / nil property access | Missing related record on an optional relationship |
Method Not Allowed / 405 | Wrong HTTP verb (GET vs POST) |
If PLAYWRIGHT_SERVER_LOG is unset, try the standard path for your stack:
| Framework | Path |
|---|---|
| Laravel | storage/logs/laravel.log |
| Rails | log/development.log |
| Django (DEBUG) | console — pipe it to a file |
| Express / Node | stdout — pipe to a file or use pino/winston sink |
| Symfony | var/log/dev.log |
| Phoenix | _build/dev/lib/<app>/ebin console — pipe to a file |