Specialist Playwright Ally
Boost productivity using this testing, mode, playwright, tests. Includes structured workflows, validation checks, and reusable patterns for development tools.
Specialist Playwright Ally
A Playwright end-to-end testing specialist that helps you write, debug, and maintain browser automation tests with expertise in test patterns, page objects, cross-browser testing, and CI integration.
When to Use This Agent
Choose Specialist Playwright Ally when:
- Writing end-to-end browser tests for web applications
- Setting up Playwright infrastructure and configuration
- Debugging flaky E2E tests or test timing issues
- Implementing page object patterns and test utilities
- Configuring cross-browser testing in CI/CD pipelines
Consider alternatives when:
- Writing unit or integration tests (use a test engineering agent)
- Testing APIs without browser interaction (use an API testing agent)
- Testing mobile native applications (use a mobile testing agent)
Quick Start
# .claude/agents/specialist-playwright-ally.yml name: Specialist Playwright Ally description: Write and maintain Playwright E2E tests model: claude-sonnet tools: - Read - Write - Edit - Bash - Glob - Grep
Example invocation:
claude "Write Playwright tests for the checkout flow: add item to cart, proceed to checkout, fill in payment details, and verify order confirmation"
Core Concepts
Playwright Configuration
// playwright.config.ts import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './e2e', timeout: 30_000, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: [ ['html', { open: 'never' }], ['json', { outputFile: 'test-results.json' }], ], use: { baseURL: 'http://localhost:3000', trace: 'on-first-retry', screenshot: 'only-on-failure', video: 'retain-on-failure', }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, { name: 'firefox', use: { ...devices['Desktop Firefox'] } }, { name: 'mobile', use: { ...devices['iPhone 14'] } }, ], webServer: { command: 'npm run dev', port: 3000, reuseExistingServer: !process.env.CI, }, });
Page Object Pattern
// e2e/pages/CheckoutPage.ts import { Page, Locator, expect } from '@playwright/test'; export class CheckoutPage { readonly page: Page; readonly cartItems: Locator; readonly subtotal: Locator; readonly checkoutButton: Locator; readonly emailInput: Locator; readonly cardNumberInput: Locator; readonly placeOrderButton: Locator; readonly orderConfirmation: Locator; constructor(page: Page) { this.page = page; this.cartItems = page.getByTestId('cart-item'); this.subtotal = page.getByTestId('subtotal'); this.checkoutButton = page.getByRole('button', { name: 'Checkout' }); this.emailInput = page.getByLabel('Email'); this.cardNumberInput = page.getByLabel('Card number'); this.placeOrderButton = page.getByRole('button', { name: 'Place order' }); this.orderConfirmation = page.getByTestId('order-confirmation'); } async fillPaymentDetails(email: string, card: string) { await this.emailInput.fill(email); await this.cardNumberInput.fill(card); } async placeOrder() { await this.placeOrderButton.click(); await expect(this.orderConfirmation).toBeVisible({ timeout: 10_000 }); } async expectItemCount(count: number) { await expect(this.cartItems).toHaveCount(count); } }
Test Structure
// e2e/checkout.spec.ts import { test, expect } from '@playwright/test'; import { CheckoutPage } from './pages/CheckoutPage'; import { ProductPage } from './pages/ProductPage'; test.describe('Checkout Flow', () => { test('complete purchase with valid payment', async ({ page }) => { const productPage = new ProductPage(page); const checkoutPage = new CheckoutPage(page); // Add item to cart await productPage.goto('/products/widget-pro'); await productPage.addToCart(); await productPage.expectCartBadge(1); // Navigate to checkout await page.getByRole('link', { name: 'Cart' }).click(); await checkoutPage.expectItemCount(1); // Fill payment and complete order await checkoutPage.checkoutButton.click(); await checkoutPage.fillPaymentDetails( '[email protected]', '4242424242424242' ); await checkoutPage.placeOrder(); // Verify confirmation await expect(checkoutPage.orderConfirmation).toContainText('Order confirmed'); }); });
Configuration
| Parameter | Description | Default |
|---|---|---|
browsers | Browsers to test (chromium, firefox, webkit) | ["chromium"] |
base_url | Application URL for tests | http://localhost:3000 |
retries | Number of retries for failed tests | 2 in CI |
workers | Parallel test workers | 1 in CI |
trace_mode | When to capture traces (on, off, on-first-retry) | on-first-retry |
screenshot_mode | When to capture screenshots | only-on-failure |
Best Practices
-
Use role-based and label-based locators, never CSS selectors or XPath.
page.getByRole('button', { name: 'Submit' })is resilient to CSS class changes and DOM restructuring.page.locator('.btn-primary')breaks when someone renames the class. Role-based locators also verify accessibility — if an element cannot be found by role, it may not be accessible to screen readers either. -
Wait for specific conditions, never use fixed timeouts. Replace
await page.waitForTimeout(2000)with explicit waits:await expect(element).toBeVisible(),await page.waitForResponse('**/api/order'), orawait page.waitForLoadState('networkidle'). Fixed timeouts are either too long (slowing tests) or too short (causing flakes). Explicit waits are both faster and more reliable. -
Isolate test data — each test should create its own state. Tests that depend on pre-existing database state are fragile and cannot run in parallel. Use API calls in
beforeEachto create the exact state each test needs. If a test requires a user with items in their cart, create the user and add items via API calls, then test the checkout UI. This makes tests independent and parallelizable. -
Use
data-testidattributes sparingly and only for elements that are not selectable by role or label. Prefer semantic locators first (getByRole, getByLabel, getByText). Only adddata-testidwhen no semantic alternative exists (generic containers, dynamically generated content). Over-relying on test IDs creates tight coupling between tests and implementation that role-based locators avoid. -
Capture traces and screenshots only on failure to keep CI fast. Configure
trace: 'on-first-retry'andscreenshot: 'only-on-failure'. Always-on tracing adds significant overhead and generates large artifacts. On-failure artifacts provide the debugging context you need without the performance cost. Upload trace artifacts to CI storage for download when investigating failures.
Common Issues
Tests are flaky — passing locally but failing in CI intermittently. The most common causes are timing issues (elements not yet visible), stale test data (leftover state from previous runs), and resource constraints (CI machines are slower). Fix timing by using explicit waits instead of timeouts. Fix data issues by resetting state in beforeEach. Fix CI speed by running with workers: 1 and increasing timeouts. Enable traces on retry to capture the exact failure state.
Tests break after UI changes even though functionality is unchanged. This indicates tests are coupled to implementation details (CSS selectors, DOM structure, specific text content). Migrate to role-based locators that test semantic meaning rather than visual appearance. A button labeled "Submit" should be found by getByRole('button', { name: 'Submit' }), not by .submit-btn — the label is part of the specification, the class name is not.
E2E test suite takes too long to run in CI. A suite that takes 30+ minutes blocks deployments and discourages running tests. Parallelize independent tests with workers > 1 (ensure test isolation first). Run only smoke tests on every PR and the full suite nightly. Use Playwright's --shard option to split tests across CI workers. Optimize slow tests by using API setup instead of UI navigation for test preconditions.
Reviews
No reviews yet. Be the first to review this template!
Similar Templates
API Endpoint Builder
Agent that scaffolds complete REST API endpoints with controller, service, route, types, and tests. Supports Express, Fastify, and NestJS.
Documentation Auto-Generator
Agent that reads your codebase and generates comprehensive documentation including API docs, architecture guides, and setup instructions.
Ai Ethics Advisor Partner
All-in-one agent covering ethics, responsible, development, specialist. Includes structured workflows, validation checks, and reusable patterns for ai specialists.