diff options
Diffstat (limited to 'playwright-py/SKILL.md')
| -rw-r--r-- | playwright-py/SKILL.md | 15 |
1 files changed, 8 insertions, 7 deletions
diff --git a/playwright-py/SKILL.md b/playwright-py/SKILL.md index 0ed912b..54e1cb7 100644 --- a/playwright-py/SKILL.md +++ b/playwright-py/SKILL.md @@ -26,7 +26,8 @@ User task → Is it static HTML? │ Then use the helper + write simplified Playwright script │ └─ Yes → Reconnaissance-then-action: - 1. Navigate and wait for networkidle + 1. Navigate and wait for a visible app landmark + (expect(page.get_by_role('main')).to_be_visible()) 2. Take screenshot or inspect DOM 3. Identify selectors from rendered state 4. Execute actions with discovered selectors @@ -51,13 +52,13 @@ python scripts/with_server.py \ To create an automation script, include only Playwright logic (servers are managed automatically): ```python -from playwright.sync_api import sync_playwright +from playwright.sync_api import sync_playwright, expect with sync_playwright() as p: browser = p.chromium.launch(headless=True) # headless for CI/pytest; headless=False for interactive debugging 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 + expect(page.get_by_role('main')).to_be_visible() # wait for a visible app landmark, not network quiet # ... your automation logic browser.close() ``` @@ -77,16 +78,16 @@ with sync_playwright() as p: ## Common Pitfall -❌ **Don't** inspect the DOM before waiting for `networkidle` on dynamic apps -✅ **Do** wait for `page.wait_for_load_state('networkidle')` before inspection +**Don't** inspect the DOM before the app has rendered on a dynamic page — you get stale content or an empty skeleton. +**Do** wait for a visible, app-specific landmark before inspecting: `expect(page.get_by_role('main')).to_be_visible()` or `page.get_by_text('Dashboard').wait_for()`. These auto-wait for the element to appear, which is what "ready" means. Avoid `page.wait_for_load_state('networkidle')` as the readiness check — Playwright discourages it, since a page can be interactive long before the network quiets (or never quiet at all, with polling or analytics). ## Best Practices - **Use bundled scripts as black boxes** - To accomplish a task, consider whether one of the scripts available in `scripts/` can help. These scripts handle common, complex workflows reliably without cluttering the context window. Use `--help` to see usage, then invoke directly. - Use `sync_playwright()` for synchronous scripts - Always close the browser when done -- Use descriptive selectors: `text=`, `role=`, CSS selectors, or IDs -- Add appropriate waits: `page.wait_for_selector()` or `page.wait_for_timeout()` +- Prefer user-visible locators: `page.get_by_role(...)`, `page.get_by_label(...)`, `page.get_by_text(...)`. Fall back to CSS/`text=` selectors only when those don't fit. +- For readiness, lead with web assertions and locator waits — `expect(locator).to_be_visible()`, `locator.wait_for()` — which auto-wait for a real, visible condition. Reach for `page.wait_for_selector()` only when a locator won't express the wait. Avoid `wait_for_load_state('networkidle')` as a readiness check (Playwright discourages it) and avoid fixed `page.wait_for_timeout()` delays. - **Choose headed vs headless by purpose, not habit.** This skill defaults to *headless* (`headless=True`) because it targets CI and pytest. The companion `/playwright-js` defaults to *headed* for interactive visual debugging. Pick by what you're doing, and only override when the purpose flips: | Purpose | Mode | |
