playwright
Interact with and test local web apps using Playwright.
When & Why to Use This Skill
This Claude skill enables seamless interaction and automated testing of local web applications using Playwright. It provides a robust framework for developers to execute end-to-end tests, manage complex local server lifecycles (including multi-server setups), and perform precise DOM inspections. By following optimized patterns for dynamic web apps, it ensures efficient automation without exhausting context limits, making it an essential tool for maintaining software quality during development.
Use Cases
- Automated End-to-End (E2E) Testing: Writing and executing native Python Playwright scripts to validate user flows and UI components in a local development environment.
- Integrated Server Management: Automatically orchestrating the startup and shutdown of multiple local services, such as a React frontend and a Python backend, during the test execution process.
- Dynamic UI Debugging: Capturing screenshots and inspecting the rendered DOM of JavaScript-heavy applications to identify selectors and troubleshoot visual or functional bugs.
- Regression Testing: Running automated interaction scripts against local builds to ensure that new code changes do not break existing features or user interfaces.
| name | playwright |
|---|---|
| description | Interact with and test local web apps using Playwright. |
Web Application Testing
To test local web applications, write native Python Playwright scripts. Your goal is to extract the information you need without polluting context with huge amounts of data (the entire DOM, every selector on the page, etc).
patterns
use the decision tree
User task → Is it static HTML?
├─ Yes → Read HTML file directly to identify selectors
│ ├─ Success → Write Playwright script using selectors
│ └─ Fails/Incomplete → Treat as dynamic (below)
│
└─ No (dynamic webapp) → Is the server already running?
├─ No → Run: python scripts/with_server.py --help
│ Then use the helper + write simplified Playwright script
│
└─ Yes → Reconnaissance-then-action:
1. Navigate and wait for networkidle
2. Take screenshot or inspect DOM
3. Identify selectors from rendered state
4. Execute actions with discovered selectors
act programmatically, then search for precise information
- Inspect rendered DOM:
page.screenshot(path='/tmp/inspect.png', full_page=True) content = page.content() page.locator('button').all() - Identify selectors from inspection results
- Execute actions using discovered selectors
scripts
scripts/with_server.py- Manages server lifecycle (supports multiple servers)
with_server.py
To start a server, run --help first, then use the helper:
Single server:
python scripts/with_server.py --server "npm run dev" --port 5173 -- python your_automation.py
Multiple servers (e.g., backend + frontend):
python scripts/with_server.py \
--server "cd backend && python server.py" --port 3000 \
--server "cd frontend && npm run dev" --port 5173 \
-- python your_automation.py
To create an automation script, include only Playwright logic (servers are managed automatically):
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True) # Always launch chromium in headless mode
page = browser.new_page()
page.goto('http://localhost:5173') # Server already running and ready
page.wait_for_load_state('networkidle') # CRITICAL: Wait for JS to execute
# ... your automation logic
browser.close()
rules
- Never inspect the DOM before waiting for
networkidleon dynamic apps - Always wait for
page.wait_for_load_state('networkidle')before inspection - Never execute actions which load large amounts of data into the context. Instead, act programmatically and search for what you need (e.g. DOM elements).
- Always check the scripts available in
scripts/before doing a task. Using the scripts keeps the context window clean, which is ultra critical. - Prefer to not read the source of the bundled scripts. Instead, invoke them with
--helpto avoid polluting context. - Always invoke a script with
--helpto see usage before attempting to use. - Always use
sync_playwright()for synchronous scripts - Always close the browser when done
- Always use descriptive selectors:
text=,role=, CSS selectors, or IDs - Always add appropriate waits:
page.wait_for_selector()orpage.wait_for_timeout()
references
- examples/ - Examples showing common patterns:
element_discovery.py- Discovering buttons, links, and inputs on a pagestatic_html_automation.py- Using file:// URLs for local HTMLconsole_logging.py- Capturing console logs during automation