Reference for the playwright-cli command-line tool — the verify-before-coding companion for Playwright + TypeScript test development. Covers the discovery workflow (open → snapshot → click/fill → emit locator code), API response verification via run-code, named browser sessions for multi-user tests, storage state save/load, tracing, and request mocking. Use when writing tests where element testids or interactions are uncertain, when verifying API response field names before assertions, or when debugging a test by replaying it interactively.
How this skill is triggered — by the user, by Claude, or both
Slash command
/pw-kit:cli-toolWhen to use
Trigger phrases: "playwright-cli", "playwright cli", "verify testid", "discover elements", "snapshot the page", "interactive browser", "session management", "storage state", "save auth state", "trace", "verify API response". Auto-activates when user mentions the CLI tool by name or asks about live discovery / verification workflows.
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Use the `playwright-cli` tool whenever you would otherwise have to guess about an element's locator, an API response shape, or an interaction sequence. The CLI gives you a live browser, emits Playwright locator code for every action you take, and prints structured snapshots of the DOM with stable element references.
Use the playwright-cli tool whenever you would otherwise have to guess about an element's locator, an API response shape, or an interaction sequence. The CLI gives you a live browser, emits Playwright locator code for every action you take, and prints structured snapshots of the DOM with stable element references.
The single biggest source of wasted time in Playwright test authoring is assuming what's on the page instead of looking at it. The CLI eliminates that class of bug:
data-testid? Take a snapshot.fetch in browser context.Every command also emits the equivalent Playwright TypeScript locator code you can paste straight into a page object.
playwright-cli open https://app.example.com/login
playwright-cli snapshot
# Output lists every interactive element with a stable ID (e1, e2, ...) and its role, label, testid
Snapshot output looks like:
e1 [textbox "Email"]
e2 [textbox "Password"]
e3 [button "Sign In"]
Interact and let the CLI emit the locator code:
playwright-cli fill e1 "[email protected]"
# Emits: await page.getByRole('textbox', { name: 'Email' }).fill('[email protected]');
playwright-cli fill e2 "secret"
# Emits: await page.getByRole('textbox', { name: 'Password' }).fill('secret');
playwright-cli click e3
# Emits: await page.getByRole('button', { name: 'Sign In' }).click();
Paste the emitted code into your page object methods. No guessing, no copy-paste from devtools.
# Browser lifecycle
playwright-cli open <URL> # launch and navigate
playwright-cli close # close current session
playwright-cli list # list all open sessions
playwright-cli close-all # close all sessions
playwright-cli kill-all # force-kill zombie processes
# Navigation
playwright-cli goto <URL>
playwright-cli go-back
playwright-cli go-forward
playwright-cli reload
# Discovery
playwright-cli snapshot # DOM + element references
playwright-cli snapshot --filename=foo.yml # save snapshot to specific file
playwright-cli screenshot # PNG of current viewport
playwright-cli screenshot eN # element screenshot
playwright-cli screenshot --filename=foo.png
# Interaction (all emit Playwright locator code)
playwright-cli click eN
playwright-cli dblclick eN
playwright-cli fill eN "value"
playwright-cli select eN "option-value"
playwright-cli check eN / playwright-cli uncheck eN
playwright-cli hover eN
playwright-cli drag eA eB
playwright-cli press <Key> # e.g., Enter, ArrowDown, Tab
playwright-cli type "text" # type into focused element
playwright-cli upload ./path/to/file
# Dialogs
playwright-cli dialog-accept
playwright-cli dialog-accept "prompt text"
playwright-cli dialog-dismiss
# Resize / viewport
playwright-cli resize <width> <height>
run-codeFor anything the named commands don't cover, use run-code with an async page handler. This is the escape hatch for API verification, JS evaluation, permission setup, etc.
playwright-cli run-code "async page => {
return await page.evaluate(() => fetch('/api/users/42').then(r => r.json()));
}"
The JSON is printed to stdout. Always do this before writing assertions on field names — frontend interfaces and backend JSON often disagree (e.g., isPremium in TS vs IsPremium in JSON).
playwright-cli run-code "async page => {
await page.context().grantPermissions(['geolocation']);
await page.context().setGeolocation({ latitude: 51.5074, longitude: -0.1278 });
}"
playwright-cli run-code "async page => {
const frame = page.locator('iframe#payment').contentFrame();
return await frame.locator('h1').innerText();
}"
playwright-cli run-code "async page => {
await page.waitForFunction(() => window.appReady === true);
}"
After logging in via the CLI, save the full browser state and reload it in later sessions to skip the login step:
# Save state after login
playwright-cli state-save auth.json
# Restore state in a new session
playwright-cli state-load auth.json
playwright-cli open https://app.example.com/dashboard # already authenticated
This is invaluable when iterating on a test — log in once, save state, then explore the rest of the app freely without re-logging-in every cycle.
# Open two independent browser sessions
playwright-cli -s=admin open https://app.example.com
playwright-cli -s=guest open https://app.example.com
# Operate on each independently
playwright-cli -s=admin snapshot
playwright-cli -s=guest click e3
# Close each
playwright-cli -s=admin close
playwright-cli -s=guest close
Use named sessions when designing tests that involve two roles (e.g., admin creates a record, regular user views it).
# Cookies
playwright-cli cookie-list
playwright-cli cookie-set session_id abc123 --domain=example.com --httpOnly --secure
playwright-cli cookie-delete session_id
# localStorage
playwright-cli localstorage-set theme dark
playwright-cli localstorage-get token
playwright-cli localstorage-clear
# sessionStorage (same API)
playwright-cli sessionstorage-set step 3
Use for test setup when the app stores feature flags or preferences in browser storage.
Wrap an uncertain sequence in tracing to capture DOM-before/after, network, and console for every action:
playwright-cli tracing-start
playwright-cli click eN
playwright-cli fill eM "value"
playwright-cli tracing-stop
# Trace + network log written to .playwright-cli/traces/
Open the resulting trace with npx playwright show-trace <path> — same viewer as for regular test failures.
# Return a fixed JSON response for a route
playwright-cli route "**/api/users" --body='[{"id":1,"name":"Test"}]' --content-type=application/json
# Simulate a 500 error
playwright-cli route "**/api/orders" --status=500 --body='{"error":"Server error"}'
# Simulate offline
playwright-cli run-code "async page => {
await page.route('**/api/**', route => route.abort('internetdisconnected'));
}"
# Manage routes
playwright-cli route-list
playwright-cli unroute "**/api/users"
playwright-cli unroute # clear all
Use for exploring UI behavior under edge-case server responses before writing tests that depend on them. Do not mock the primary application API in actual tests — only mock external/third-party services.
| Stage of test development | Tool |
|---|---|
| Don't know what testids exist | playwright-cli open + snapshot |
| Don't know API response shape | playwright-cli run-code "...fetch..." |
| Want to try the interaction first | Manually click / fill interactively, see what emits |
| Multiple user roles in one test | Named sessions -s=role-name |
| Skip repeated logins during exploration | state-save after one login, state-load after |
| Reproduce a failing test step-by-step | Replay it interactively, take snapshots at each step |
| Verify a UI behavior under unusual server response | route to mock the response, then re-snapshot |
| Capture evidence of behavior | tracing-start / tracing-stop or screenshot |
The canonical loop for writing a new test:
1. open → navigate to the target page
2. snapshot → discover element IDs (e1, e2, ...) and DOM structure
3. run-code → verify API response field names / probe JS state
4. click/fill → perform actions; collect emitted locator code
5. route → stub endpoints for error/edge cases if needed
6. state-save → persist authenticated session for reuse
7. tracing-start/stop → wrap uncertain sequences for debugging
8. Paste emitted code → write POM methods + test steps with confidence
playwright-cli verifies the live UI behavior. Context7 MCP verifies the Playwright API signatures for the version installed in package.json. Use both:
1. Read package.json → note @playwright/test version (e.g. 1.49.0)
2. Resolve the Playwright Test library id via Context7
3. Fetch version-pinned docs for the API you need
4. Cross-check with playwright-cli's live behavior
Why both: APIs change between versions, and training-era knowledge may be stale. Context7 gives you the right API surface; playwright-cli gives you the right runtime behavior. Combined, they eliminate the two main "code looked right but failed" bug classes.
| Mistake | Fix |
|---|---|
Guessing a data-testid instead of taking a snapshot | Take the snapshot first |
| Writing code that assumes API field names | Verify with run-code "...fetch..." |
| Re-logging-in for every exploration cycle | state-save once, state-load after |
Forgetting to close sessions (zombies accumulate) | playwright-cli list and close-all periodically |
Using playwright-cli for production tests | The CLI is for exploration only; actual tests use @playwright/test |
Additional reference docs (recipes, deep-dives, edge cases) will be added based on team feedback. PRs welcome.
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub antongulin/pw-kit --plugin pw-kit