home / skills / cin12211 / orca-q / playwright-expert

playwright-expert skill

/.agent/skills/playwright-expert

This skill provides expert Playwright guidance for setting up E2E tests, cross-browser runs, and reliable automation workflows.

npx playbooks add skill cin12211/orca-q --skill playwright-expert

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

Files (1)
SKILL.md
5.2 KB
---
name: playwright-expert
description: Playwright E2E testing expert for browser automation, cross-browser testing, visual regression, network interception, and CI integration. Use for E2E test setup, flaky tests, or browser automation challenges.
---

# Playwright Expert

Expert in Playwright for E2E testing, browser automation, and cross-browser testing.

## When Invoked

### Recommend Specialist
- **Unit/integration tests**: recommend jest-expert or vitest-expert
- **React component testing**: recommend testing-expert
- **API testing only**: recommend rest-api-expert

### Environment Detection
```bash
npx playwright --version 2>/dev/null
ls playwright.config.* 2>/dev/null
find . -name "*.spec.ts" -path "*e2e*" | head -5
```

## Problem Playbooks

### Project Setup

```bash
# Initialize Playwright
npm init playwright@latest

# Install browsers
npx playwright install
```

```typescript
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './e2e',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: 'html',
  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
  ],
  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
  },
});
```

### Writing Tests

```typescript
import { test, expect } from '@playwright/test';

test.describe('Authentication', () => {
  test('should login successfully', async ({ page }) => {
    await page.goto('/login');
    
    await page.fill('[data-testid="email"]', '[email protected]');
    await page.fill('[data-testid="password"]', 'password123');
    await page.click('[data-testid="submit"]');
    
    await expect(page).toHaveURL('/dashboard');
    await expect(page.locator('h1')).toContainText('Welcome');
  });

  test('should show error for invalid credentials', async ({ page }) => {
    await page.goto('/login');
    
    await page.fill('[data-testid="email"]', '[email protected]');
    await page.fill('[data-testid="password"]', 'wrong');
    await page.click('[data-testid="submit"]');
    
    await expect(page.locator('.error-message')).toBeVisible();
  });
});
```

### Page Object Model

```typescript
// pages/login.page.ts
import { Page, Locator } from '@playwright/test';

export class LoginPage {
  readonly page: Page;
  readonly emailInput: Locator;
  readonly passwordInput: Locator;
  readonly submitButton: Locator;

  constructor(page: Page) {
    this.page = page;
    this.emailInput = page.locator('[data-testid="email"]');
    this.passwordInput = page.locator('[data-testid="password"]');
    this.submitButton = page.locator('[data-testid="submit"]');
  }

  async goto() {
    await this.page.goto('/login');
  }

  async login(email: string, password: string) {
    await this.emailInput.fill(email);
    await this.passwordInput.fill(password);
    await this.submitButton.click();
  }
}

// Usage in test
test('login test', async ({ page }) => {
  const loginPage = new LoginPage(page);
  await loginPage.goto();
  await loginPage.login('[email protected]', 'password');
});
```

### Network Interception

```typescript
test('mock API response', async ({ page }) => {
  await page.route('**/api/users', async (route) => {
    await route.fulfill({
      status: 200,
      body: JSON.stringify([{ id: 1, name: 'Mock User' }]),
    });
  });

  await page.goto('/users');
  await expect(page.locator('.user-name')).toContainText('Mock User');
});
```

### Visual Regression

```typescript
test('visual comparison', async ({ page }) => {
  await page.goto('/');
  await expect(page).toHaveScreenshot('homepage.png', {
    maxDiffPixelRatio: 0.1,
  });
});
```

### Handling Flaky Tests

```typescript
// Retry flaky tests
test('flaky network test', async ({ page }) => {
  test.slow(); // Triple timeout
  
  await page.goto('/');
  await page.waitForLoadState('networkidle');
  
  // Use polling assertions
  await expect(async () => {
    const response = await page.request.get('/api/status');
    expect(response.ok()).toBeTruthy();
  }).toPass({ timeout: 10000 });
});
```

## Running Tests

```bash
# Run all tests
npx playwright test

# Run specific file
npx playwright test login.spec.ts

# Run in headed mode
npx playwright test --headed

# Run in UI mode
npx playwright test --ui

# Debug mode
npx playwright test --debug

# Generate report
npx playwright show-report
```

## Code Review Checklist

- [ ] data-testid attributes for selectors
- [ ] Page Object Model for complex flows
- [ ] Network requests mocked where needed
- [ ] Proper wait strategies (no arbitrary waits)
- [ ] Screenshots on failure configured
- [ ] Parallel execution enabled

## Anti-Patterns

1. **Hardcoded waits** - Use proper assertions
2. **Fragile selectors** - Use data-testid
3. **Shared state between tests** - Isolate tests
4. **No retries in CI** - Add retry for flakiness
5. **Testing implementation details** - Test user behavior

Overview

This skill is a Playwright E2E testing expert focused on browser automation, cross-browser testing, visual regression, network interception, and CI integration. It helps set up Playwright, design robust tests for Vue and Electron apps, and troubleshoot flaky or environment-dependent failures. Use it to build maintainable E2E suites and integrate tests into CI pipelines for reliable releases.

How this skill works

I inspect your project for existing Playwright configuration, test files, and typical anti-patterns, then recommend a tailored setup and test architecture. I provide configuration snippets (playwright.config.ts), Page Object Model examples, network interception patterns, and visual regression test templates. I also suggest CI settings, retry/backoff strategies for flakiness, and a code-review checklist to keep tests stable and fast.

When to use it

  • Setting up Playwright for a new Vue, Nuxt, or Electron project
  • Adding cross-browser projects (chromium, firefox, webkit) and device presets
  • Debugging flaky tests or CI-only failures
  • Mocking network responses or simulating backend failures
  • Adding visual regression checks or screenshot baselines

Best practices

  • Use data-testid attributes and Page Object Model for stable selectors
  • Configure screenshot on failure, traces on first retry, and retries in CI
  • Avoid hardcoded waits; prefer toHave* assertions and waitForLoadState
  • Mock network requests for predictable test data and faster runs
  • Run tests in parallel locally but limit workers in CI to reduce flakiness

Example use cases

  • Create E2E tests for the login and dashboard flows of a Vue-based database editor
  • Intercept API calls to simulate PostgreSQL responses during UI tests
  • Add cross-browser coverage to ensure features work in Chromium, Firefox, and Safari
  • Implement visual regression for the main editor screen to detect UI regressions
  • Reduce flakiness by adding retries, traces, and targeted slow-timeouts for flaky network tests

FAQ

How do I integrate Playwright into CI?

Add Playwright install and npx playwright install to your CI job, run npx playwright test with a headless browser, enable retries and a single worker in CI, and publish the HTML report or store traces/screenshots as artifacts.

When should I mock network requests vs using a real backend?

Mock when you need deterministic responses, faster tests, or to simulate edge cases. Use a real backend for end-to-end smoke tests that validate integration between UI and data store.