| name | cli-tool |
| description | 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. |
| when_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.
|
Playwright CLI — Verify Before Coding
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.
Why This Tool Matters
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:
- Don't know an element's
data-testid? Take a snapshot.
- Don't know what API field names the response uses? Run a
fetch in browser context.
- Don't know if a click will trigger a modal or a navigation? Click it interactively and see.
Every command also emits the equivalent Playwright TypeScript locator code you can paste straight into a page object.
Core Discovery Workflow
playwright-cli open https://app.example.com/login
playwright-cli snapshot
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 "user@example.com"
playwright-cli fill e2 "secret"
playwright-cli click e3
Paste the emitted code into your page object methods. No guessing, no copy-paste from devtools.
Core Commands
playwright-cli open <URL>
playwright-cli close
playwright-cli list
playwright-cli close-all
playwright-cli kill-all
playwright-cli goto <URL>
playwright-cli go-back
playwright-cli go-forward
playwright-cli reload
playwright-cli snapshot
playwright-cli snapshot --filename=foo.yml
playwright-cli screenshot
playwright-cli screenshot eN
playwright-cli screenshot --filename=foo.png
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>
playwright-cli type "text"
playwright-cli upload ./path/to/file
playwright-cli dialog-accept
playwright-cli dialog-accept "prompt text"
playwright-cli dialog-dismiss
playwright-cli resize <width> <height>
Running Arbitrary Playwright Code — run-code
For 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.
Verify API response field names (most common use)
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).
Set permissions / geolocation
playwright-cli run-code "async page => {
await page.context().grantPermissions(['geolocation']);
await page.context().setGeolocation({ latitude: 51.5074, longitude: -0.1278 });
}"
Inspect iframe content
playwright-cli run-code "async page => {
const frame = page.locator('iframe#payment').contentFrame();
return await frame.locator('h1').innerText();
}"
Wait for app-specific readiness flag
playwright-cli run-code "async page => {
await page.waitForFunction(() => window.appReady === true);
}"
Storage State — Save Auth, Skip Login
After logging in via the CLI, save the full browser state and reload it in later sessions to skip the login step:
playwright-cli state-save auth.json
playwright-cli state-load auth.json
playwright-cli open https://app.example.com/dashboard
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.
Named Sessions — Multi-User Tests
playwright-cli -s=admin open https://app.example.com
playwright-cli -s=guest open https://app.example.com
playwright-cli -s=admin snapshot
playwright-cli -s=guest click e3
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).
Cookie / localStorage / sessionStorage
playwright-cli cookie-list
playwright-cli cookie-set session_id abc123 --domain=example.com --httpOnly --secure
playwright-cli cookie-delete session_id
playwright-cli localstorage-set theme dark
playwright-cli localstorage-get token
playwright-cli localstorage-clear
playwright-cli sessionstorage-set step 3
Use for test setup when the app stores feature flags or preferences in browser storage.
Tracing
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
Open the resulting trace with npx playwright show-trace <path> — same viewer as for regular test failures.
Request Mocking — Test Edge Cases
playwright-cli route "**/api/users" --body='[{"id":1,"name":"Test"}]' --content-type=application/json
playwright-cli route "**/api/orders" --status=500 --body='{"error":"Server error"}'
playwright-cli run-code "async page => {
await page.route('**/api/**', route => route.abort('internetdisconnected'));
}"
playwright-cli route-list
playwright-cli unroute "**/api/users"
playwright-cli unroute
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.
When To Use Each Tool
| 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 |
Discovery → Code Loop
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
Companion: Context7 MCP for version-locked Playwright docs
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.
Common Mistakes
| 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 |
Further Reading
Additional reference docs (recipes, deep-dives, edge cases) will be added based on team feedback. PRs welcome.