Webapp Testing Smart
Powerful skill for toolkit, interacting, testing, local. Includes structured workflows, validation checks, and reusable patterns for development.
Web Application Testing Smart
A practical skill for testing web applications using Python Playwright scripts. Covers browser automation, form interaction, visual verification, network interception, and multi-page workflow testing with server lifecycle management.
When to Use This Skill
Choose this skill when:
- Testing local web applications with browser automation
- Verifying form submissions, navigation, and interactive features
- Running visual regression tests across pages
- Testing API integrations through the browser
- Automating multi-step user workflows for verification
Consider alternatives when:
- Writing unit tests for components → use a component testing skill
- Testing APIs directly → use an API testing skill
- Running performance load tests → use a performance testing skill
- Writing Playwright tests in TypeScript → use a Playwright skill
Quick Start
# Install Playwright for Python pip install playwright playwright install chromium # Basic test script from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page() # Navigate and verify page.goto('http://localhost:3000') assert page.title() == 'My App' # Fill form and submit page.fill('#email', '[email protected]') page.fill('#password', 'password123') page.click('button[type="submit"]') # Wait for navigation and verify page.wait_for_url('**/dashboard') assert page.is_visible('text=Welcome') browser.close()
Core Concepts
Testing Patterns
| Pattern | When | Example |
|---|---|---|
| Navigation test | Verify page routing | Click link → check URL and content |
| Form test | Verify form submission | Fill fields → submit → check response |
| Auth test | Verify login/logout | Login → access protected page → logout |
| CRUD test | Verify data operations | Create → read → update → delete → verify |
| Error test | Verify error handling | Submit invalid data → check error message |
| Visual test | Verify appearance | Screenshot → compare with baseline |
Server Lifecycle Management
# with_server.py — Start server, run tests, stop server import subprocess import time import sys import requests def wait_for_server(url, timeout=30): start = time.time() while time.time() - start < timeout: try: requests.get(url, timeout=2) return True except requests.ConnectionError: time.sleep(0.5) return False def run_with_server(server_cmd, test_func, port=3000): url = f'http://localhost:{port}' # Start server proc = subprocess.Popen(server_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: if not wait_for_server(url): raise TimeoutError(f'Server did not start at {url}') # Run tests test_func(url) print('All tests passed!') finally: proc.terminate() proc.wait(timeout=5)
Advanced Testing Patterns
from playwright.sync_api import sync_playwright, expect def test_full_workflow(base_url: str): with sync_playwright() as p: browser = p.chromium.launch() context = browser.new_context( viewport={'width': 1280, 'height': 720}, locale='en-US', ) page = context.new_page() # Intercept API calls api_responses = [] page.on('response', lambda r: api_responses.append(r) if '/api/' in r.url else None) # Login flow page.goto(f'{base_url}/login') page.fill('[name="email"]', '[email protected]') page.fill('[name="password"]', 'testpass') page.click('button:has-text("Sign In")') page.wait_for_url('**/dashboard') # Verify dashboard loaded expect(page.locator('h1')).to_have_text('Dashboard') expect(page.locator('.stats-card')).to_have_count(4) # Take screenshot for visual verification page.screenshot(path='screenshots/dashboard.png', full_page=True) # Test CRUD operation page.click('text=Create New') page.fill('#name', 'Test Item') page.fill('#description', 'Created by automated test') page.click('button:has-text("Save")') # Verify creation expect(page.locator('text=Test Item')).to_be_visible() browser.close()
Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
browser | string | 'chromium' | Browser: chromium, firefox, or webkit |
headless | boolean | true | Run without visible browser window |
viewport | object | {width: 1280, height: 720} | Browser viewport dimensions |
timeout | number | 30000 | Default action timeout (ms) |
screenshotOnFailure | boolean | true | Capture screenshot when test fails |
serverStartTimeout | number | 30 | Max seconds to wait for server start |
Best Practices
-
Always wait for conditions, never use sleep — Use
page.wait_for_selector(),page.wait_for_url(), orexpect().to_be_visible()instead oftime.sleep(). Hard sleeps are flaky and slow. Explicit waits are reliable and fast. -
Use
data-testidattributes for stable selectors — CSS class names and text content change frequently. Adddata-testid="submit-button"to elements and select withpage.locator('[data-testid="submit-button"]')for resilient tests. -
Manage server lifecycle automatically — Start the server before tests and stop it after, even if tests fail. Use the
with_server.pyhelper pattern with try/finally to ensure cleanup. -
Capture screenshots on failure for debugging — When a test assertion fails, take a screenshot and save page HTML before the test exits. This provides visual evidence of what the page looked like when the failure occurred.
-
Isolate tests with fresh browser contexts — Each test should create a new browser context with clean cookies and storage. Shared state between tests causes flaky failures that depend on test execution order.
Common Issues
Tests fail with "element not found" but element exists — The element might be loading asynchronously or hidden behind a modal. Use wait_for_selector with a timeout, check for iframes, and verify the element isn't covered by an overlay.
Server not ready when tests start — The test script launches the server and immediately starts testing before the server finishes starting. Use a polling health check (wait_for_server) that retries until the server responds or a timeout expires.
Tests pass locally but fail in CI — CI environments are slower and may have different screen sizes. Increase timeouts, set explicit viewport sizes, and disable animations with CSS * { animation: none !important; transition: none !important; }.
Reviews
No reviews yet. Be the first to review this template!
Similar Templates
Full-Stack Code Reviewer
Comprehensive code review skill that checks for security vulnerabilities, performance issues, accessibility, and best practices across frontend and backend code.
Test Suite Generator
Generates comprehensive test suites with unit tests, integration tests, and edge cases. Supports Jest, Vitest, Pytest, and Go testing.
Pro Architecture Workspace
Battle-tested skill for architectural, decision, making, framework. Includes structured workflows, validation checks, and reusable patterns for development.