Skill Library

intermediate Code Development

Web App Testing with Playwright

Test and interact with local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.

When to Use This Skill

  • Verifying frontend functionality works as expected
  • Debugging UI behavior and visual issues
  • Capturing browser screenshots for documentation
  • Viewing and analyzing browser console logs
  • E2E testing of web applications
  • Automating repetitive browser tasks

How to use this skill

1. Copy the AI Core Logic from the Instructions tab below.

2. Paste it into your AI's System Instructions or as your first message.

3. Provide your raw data or requirements as requested by the AI.

#testing#playwright#browser-automation#e2e#qa#debugging

System Directives

## Decision Tree: Choosing Your Approach ``` 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 → Use server management helper │ Then 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 ``` ## Core Testing Patterns ### Basic Playwright Script ```python from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page() page.goto('http://localhost:5173') page.wait_for_load_state('networkidle') browser.close() ``` ### Server Lifecycle Management For applications where you need to start the server: **Single Server:** ```bash python scripts/with_server.py --server "npm run dev" --port 5173 -- python your_automation.py ``` **Multiple Servers (Backend + Frontend):** ```bash 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 ``` ### Reconnaissance-Then-Action Pattern When testing dynamic applications, always inspect first: ```python from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page() page.goto('http://localhost:5173') page.wait_for_load_state('networkidle') page.screenshot(path='/tmp/inspect.png', full_page=True) content = page.content() buttons = page.locator('button').all() print(f"Found {len(buttons)} buttons:") for btn in buttons: print(f" - {btn.inner_text()}") page.click('button:has-text("Submit")') browser.close() ``` ## Advanced Techniques ### Element Discovery ```python def discover_interactive_elements(page): """Find all interactive elements on the page""" elements = { 'buttons': page.locator('button').all(), 'links': page.locator('a').all(), 'inputs': page.locator('input').all(), 'selects': page.locator('select').all(), 'textareas': page.locator('textarea').all() } report = [] for element_type, items in elements.items(): report.append(f"\n{element_type.upper()} ({len(items)} found):") for item in items[:10]: # Limit output try: text = item.inner_text() or item.get_attribute('placeholder') or item.get_attribute('aria-label') report.append(f" - {text[:50] if text else '[no text]'}") except: report.append(" - [element not accessible]") return "\n".join(report) ``` ### Console Log Capture ```python def capture_console_logs(page): """Capture browser console logs during automation""" logs = [] def handle_console(msg): logs.append({ 'type': msg.type, 'text': msg.text, 'location': msg.location }) page.on('console', handle_console) return logs ``` ### Form Interaction ```python def fill_form(page, form_data: dict): """Fill a form with provided data""" for field_name, value in form_data.items(): selectors = [ f'input[name="{field_name}"]', f'input[id="{field_name}"]', f'textarea[name="{field_name}"]', f'select[name="{field_name}"]' ] for selector in selectors: try: element = page.locator(selector) if element.count() > 0: if element.get_attribute('type') == 'checkbox': if value: element.check() else: element.uncheck() elif selector.startswith('select'): element.select_option(value) else: element.fill(value) break except: continue ``` ### Visual Testing ```python def visual_comparison(page, baseline_path: str, threshold: float = 0.1): """Compare current page to baseline screenshot""" import cv2 import numpy as np from pathlib import Path current_path = '/tmp/current_screenshot.png' page.screenshot(path=current_path, full_page=True) baseline = cv2.imread(baseline_path) current = cv2.imread(current_path) if baseline.shape != current.shape: return {'match': False, 'reason': 'Different dimensions'} diff = cv2.absdiff(baseline, current) diff_ratio = np.sum(diff) / (baseline.shape[0] * baseline.shape[1] * baseline.shape[2] * 255) return { 'match': diff_ratio < threshold, 'difference_ratio': diff_ratio, 'diff_image': '/tmp/diff.png' if diff_ratio >= threshold else None } ``` ## Common Pitfalls ### ❌ Don't Do This ```python page.goto('http://localhost:5173') content = page.content() # May get incomplete HTML! ``` ### ✅ Do This Instead ```python page.goto('http://localhost:5173') page.wait_for_load_state('networkidle') # Wait for JS to execute content = page.content() # Now we get the complete DOM ``` ## Selector Best Practices ```python page.locator('text=Submit') # Text content page.locator('role=button[name="Submit"]') # ARIA role page.locator('#submit-button') # ID page.locator('[data-testid="submit"]') # Test ID page.locator('button.primary') # CSS class page.locator('div > div > button') # Structure-dependent page.locator('.css-1a2b3c') # Generated class names ``` ## Best Practices 1. **Always Use sync_playwright()** for synchronous scripts 2. **Wait for networkidle** before inspecting dynamic apps 3. **Close browser** when automation completes 4. **Use descriptive selectors**: text=, role=, CSS, or IDs 5. **Add appropriate waits**: wait_for_selector() or wait_for_timeout() 6. **Capture screenshots** at key points for debugging 7. **Handle errors gracefully** with try/except blocks ## Example: Full E2E Test ```python from playwright.sync_api import sync_playwright def test_user_registration(): """Complete E2E test for user registration flow""" with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page() try: page.goto('http://localhost:5173/register') page.wait_for_load_state('networkidle') page.fill('input[name="email"]', 'test@example.com') page.fill('input[name="password"]', 'SecurePass123!') page.fill('input[name="confirmPassword"]', 'SecurePass123!') page.screenshot(path='/tmp/before-submit.png') page.click('button[type="submit"]') page.wait_for_url('**/dashboard**', timeout=10000) welcome = page.locator('text=Welcome') assert welcome.is_visible() page.screenshot(path='/tmp/success.png') print("✅ Registration test passed!") except Exception as e: page.screenshot(path='/tmp/failure.png') print(f"❌ Test failed: {e}") raise finally: browser.close() if __name__ == "__main__": test_user_registration() ``` ## Related Resources - [Playwright Python Docs](https://playwright.dev/python/) - [Playwright Selectors](https://playwright.dev/python/docs/selectors) - [Playwright Best Practices](https://playwright.dev/python/docs/best-practices) - [Testing Library](https://testing-library.com/)

Procedural Integration

This skill is formatted as a set of persistent system instructions. When integrated, it provides the AI model with specialized workflows and knowledge constraints for Code Development.

Skill Actions


Model Compatibility
🤖 Claude Opus🤖 Claude 3.5 Sonnet🤖 GPT-4
Code Execution: Required
MCP Tools: Optional
Footprint ~2,392 tokens