playwright-expert

📁 cin12211/orca-q 📅 Jan 23, 2026
0
总安装量
19
周安装量
安装命令
npx skills add https://github.com/cin12211/orca-q --skill playwright-expert

Agent 安装分布

claude-code 16
opencode 15
gemini-cli 14
cursor 12
antigravity 11
github-copilot 11

Skill 文档

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

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

Problem Playbooks

Project Setup

# Initialize Playwright
npm init playwright@latest

# Install browsers
npx playwright install
// 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

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"]', 'user@example.com');
    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"]', 'wrong@example.com');
    await page.fill('[data-testid="password"]', 'wrong');
    await page.click('[data-testid="submit"]');
    
    await expect(page.locator('.error-message')).toBeVisible();
  });
});

Page Object Model

// 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('user@example.com', 'password');
});

Network Interception

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

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

Handling Flaky Tests

// 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

# 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