Ultimate Playwright Browser Automation Studio
Professional-grade skill designed for automated browser testing for web applications. Built for Claude Code with best practices and real-world patterns.
Playwright Browser Automation Studio
A comprehensive browser automation skill for building end-to-end test suites, web scraping pipelines, and automated browser workflows using Playwright's full feature set including codegen, trace viewer, and multi-browser testing.
When to Use
Choose Playwright Browser Automation Studio when:
- Building comprehensive end-to-end test suites with visual debugging and trace recording
- Creating complex browser automation workflows with multi-tab and multi-context support
- Setting up cross-browser testing infrastructure for CI/CD pipelines
- Building production web scraping systems with anti-detection and session management
Consider alternatives when:
- Unit testing React components — use Testing Library
- Simple HTTP API testing — use Supertest or REST clients
- Mobile-specific testing — use Appium or XCUITest
Quick Start
# Initialize Playwright project with codegen npm init playwright@latest npx playwright codegen https://example.com # Record interactions npx playwright test --ui # Visual test runner
import { test, expect, type Page, type BrowserContext } from '@playwright/test'; // Custom fixture for authenticated testing const authenticatedTest = test.extend<{ authedPage: Page }>({ authedPage: async ({ browser }, use) => { const context = await browser.newContext({ storageState: 'auth-state.json' }); const page = await context.newPage(); await use(page); await context.close(); } }); authenticatedTest('manage user dashboard', async ({ authedPage }) => { await authedPage.goto('/dashboard'); await expect(authedPage.getByRole('heading', { name: 'Dashboard' })).toBeVisible(); // Test data table interaction const table = authedPage.getByRole('table'); await expect(table.getByRole('row')).toHaveCount(11); // Header + 10 rows // Sort by name await table.getByRole('columnheader', { name: 'Name' }).click(); const firstCell = table.getByRole('row').nth(1).getByRole('cell').first(); await expect(firstCell).toHaveText(/^A/); // Starts with A after sort // Filter await authedPage.getByPlaceholder('Search...').fill('admin'); await expect(table.getByRole('row')).toHaveCount(2); // Header + 1 match }); // Visual regression test test('homepage visual regression', async ({ page }) => { await page.goto('/'); await page.waitForLoadState('networkidle'); await expect(page).toHaveScreenshot('homepage.png', { maxDiffPixelRatio: 0.01, fullPage: true }); }); // API mocking for deterministic tests test('handles API errors gracefully', async ({ page }) => { await page.route('**/api/data', route => route.fulfill({ status: 500, body: 'Internal Server Error' }) ); await page.goto('/data-view'); await expect(page.getByText('Something went wrong')).toBeVisible(); await expect(page.getByRole('button', { name: 'Retry' })).toBeVisible(); });
Core Concepts
Playwright Features Matrix
| Feature | Description | Use Case |
|---|---|---|
| Codegen | Record and generate test code | Quick test creation |
| Trace Viewer | Visual debugging with timeline | CI failure debugging |
| UI Mode | Interactive test runner | Local development |
| Visual Comparisons | Screenshot diff testing | Visual regression |
| Network Interception | Mock/modify API responses | Deterministic tests |
| Multi-browser | Chromium, Firefox, WebKit | Cross-browser testing |
| Auth State | Save/load authentication | Skip login in tests |
| Fixtures | Custom test setup/teardown | Shared configuration |
Advanced Patterns
// Global setup for authentication import { chromium, type FullConfig } from '@playwright/test'; async function globalSetup(config: FullConfig) { const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('http://localhost:3000/login'); await page.getByLabel('Email').fill('[email protected]'); await page.getByLabel('Password').fill('admin123'); await page.getByRole('button', { name: 'Sign in' }).click(); await page.waitForURL('/dashboard'); await page.context().storageState({ path: 'auth-state.json' }); await browser.close(); } export default globalSetup; // Parallel test execution with worker isolation test.describe.parallel('independent tests', () => { test('test 1', async ({ page }) => { /* ... */ }); test('test 2', async ({ page }) => { /* ... */ }); test('test 3', async ({ page }) => { /* ... */ }); });
Configuration
| Option | Description | Default |
|---|---|---|
baseURL | Base URL for all navigations | "http://localhost:3000" |
projects | Browser configurations to test | [{ name: 'chromium' }] |
workers | Parallel test workers | 50% of CPUs |
retries | Test retry count | 0 (2 on CI) |
timeout | Test timeout (ms) | 30000 |
use.trace | Trace recording mode | "on-first-retry" |
use.screenshot | Screenshot on failure | "only-on-failure" |
globalSetup | Global setup script path | null |
Best Practices
- Use role-based locators (
getByRole,getByLabel,getByPlaceholder) instead of CSS selectors or test IDs — role-based selectors test accessibility simultaneously and are more resilient to implementation changes - Record traces on first retry to get detailed debugging information for flaky tests without the overhead of recording every test run — traces include screenshots, network logs, and console output at every step
- Use the global setup to authenticate once and share the storage state across all tests, eliminating redundant login flows and making the test suite 10-50x faster
- Mock external APIs with
page.route()to make tests deterministic — real API calls make tests slow, flaky, and dependent on external service availability - Run visual regression tests in Docker containers to ensure consistent rendering across local machines and CI, avoiding false positives from font rendering differences between operating systems
Common Issues
Flaky tests passing/failing intermittently: Most flakiness comes from timing issues where the test interacts with elements before they are ready. Use Playwright's built-in auto-waiting, avoid page.waitForTimeout(), and prefer expect(locator).toBeVisible() assertions that auto-retry until the condition is met or the timeout expires.
Visual regression tests failing across environments: Different operating systems render fonts and anti-aliasing differently. Run screenshot comparisons in Docker with a fixed browser version and OS, or use maxDiffPixelRatio to allow minor rendering differences while still catching meaningful visual changes.
Authentication state not persisting: The storage state file may be generated during global setup but not found during test execution if the path is relative to a different directory. Use absolute paths or configure the storageState path relative to playwright.config.ts location, and verify the file exists before tests run.
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.