home / skills / eyadsibai / ltk / webapp-testing

This skill helps you automate end-to-end web application testing with Python Playwright, enabling reliable selectors, server management, and robust checks.

npx playbooks add skill eyadsibai/ltk --skill webapp-testing

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
4.0 KB
---
name: webapp-testing
description: Use when testing "web application", "Playwright", "browser automation", "UI testing", "frontend testing", "E2E testing", "end-to-end tests", or asking about "test local webapp", "browser screenshots", "DOM inspection"
version: 1.0.0
---

<!-- Adapted from: awesome-claude-skills/webapp-testing -->

# Web Application Testing with Playwright

Test local web applications using Python Playwright scripts.

## Decision Tree

```
Is it static HTML?
├─ Yes → Read HTML file directly to identify selectors
│         ├─ Success → Write Playwright script using selectors
│         └─ Fails → Treat as dynamic (below)
│
└─ No (dynamic webapp) → Is the server already running?
    ├─ No → Start server, then test
    └─ 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
```

## 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')  # CRITICAL: Wait for JS

    # Your automation logic here
    page.screenshot(path='screenshot.png')

    browser.close()
```

## Reconnaissance-Then-Action Pattern

### 1. Inspect Rendered DOM

```python
# Take screenshot for visual inspection
page.screenshot(path='/tmp/inspect.png', full_page=True)

# Get page content
content = page.content()

# Find all buttons
buttons = page.locator('button').all()
for btn in buttons:
    print(btn.inner_text())
```

### 2. Identify Selectors

```python
# Find elements by text
page.locator('text=Submit').click()

# Find by role
page.locator('role=button[name="Save"]').click()

# Find by CSS
page.locator('#submit-btn').click()
page.locator('.primary-action').click()
```

### 3. Execute Actions

```python
# Click
page.locator('button:has-text("Login")').click()

# Fill form
page.locator('input[name="email"]').fill('[email protected]')
page.locator('input[name="password"]').fill('password123')

# Wait and verify
page.wait_for_selector('.success-message')
assert page.locator('.success-message').is_visible()
```

## Common Pitfall

```python
# ❌ WRONG: Inspecting before page loads
page.goto('http://localhost:5173')
content = page.content()  # May be incomplete!

# ✅ CORRECT: Wait for network idle first
page.goto('http://localhost:5173')
page.wait_for_load_state('networkidle')
content = page.content()  # Now complete
```

## Capture Console Logs

```python
from playwright.sync_api import sync_playwright

def handle_console(msg):
    print(f"Console {msg.type}: {msg.text}")

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.on('console', handle_console)
    page.goto('http://localhost:5173')
    page.wait_for_load_state('networkidle')
    browser.close()
```

## Testing with Server Management

```python
import subprocess
import time
from playwright.sync_api import sync_playwright

# Start server
server = subprocess.Popen(['npm', 'run', 'dev'], cwd='./frontend')
time.sleep(5)  # Wait for server to start

try:
    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')
        # ... tests ...
        browser.close()
finally:
    server.terminate()
```

## Best Practices

1. **Always use headless mode**: `browser = p.chromium.launch(headless=True)`
2. **Always wait for networkidle**: `page.wait_for_load_state('networkidle')`
3. **Always close browser**: Use `with` statement or explicit `browser.close()`
4. **Use descriptive selectors**: `text=`, `role=`, CSS selectors, or IDs
5. **Add appropriate waits**: `page.wait_for_selector()` or `page.wait_for_timeout()`

## Required Packages

```bash
pip install playwright
playwright install chromium
```

Overview

This skill helps you test web applications using Python and Playwright for browser automation, DOM inspection, screenshots, and end-to-end flows. It provides a practical reconnaissance-then-action approach to discover selectors on rendered pages and reliably interact with dynamic frontends. Use it to run tests against local dev servers, capture console logs, and automate UI verification.

How this skill works

The skill drives a headless browser session with Playwright, navigates to the target URL, and waits for the page to reach network idle so JavaScript-rendered content is stable. It supports taking full-page screenshots, extracting page HTML, enumerating elements, and identifying robust selectors (text, role, CSS, id) before performing actions like clicks and fills. It also includes patterns for starting/stopping a local server and capturing browser console output for debugging.

When to use it

  • Running end-to-end tests for a web application in a CI or local environment
  • Testing pages that render content via JavaScript (SPA frameworks)
  • Needing reliable element selectors by inspecting the rendered DOM or screenshots
  • Automating form submissions, login flows, and UI interactions
  • Capturing browser console logs or visual regressions with screenshots

Best practices

  • Launch browsers in headless mode for CI and scripts (p.chromium.launch(headless=True))
  • Always wait for page readiness (page.wait_for_load_state('networkidle')) before inspecting or acting
  • Use descriptive, stable selectors: text=, role=, ids, or well-scoped CSS selectors
  • Take screenshots and page.content() for reconnaissance before writing actions
  • Ensure browser and server processes are closed or terminated to avoid resource leaks

Example use cases

  • Start a local dev server, wait for it to be ready, then run Playwright to test a login and assert a success message
  • Automate filling and submitting a multi-field form and verify the resulting UI state
  • Capture full-page screenshots for visual checks after navigation and interactions
  • Listen to browser console messages to detect runtime errors during test runs
  • Inspect rendered DOM to discover selectors for elements produced by client-side rendering

FAQ

Do I need to wait for network idle every time?

Yes — waiting for networkidle ensures client-side rendering is complete before inspecting DOM or performing actions.

How do I test a site served locally by npm or another server?

Start the server as a subprocess, wait for it to accept connections, run Playwright tests, then terminate the server in a finally block.

Which selectors are most reliable?

Prefer role= and text= selectors or stable IDs; fall back to scoped CSS only when necessary.