Claude
Skills
Sign in
Back

playwright-test-architecture

Included with Lifetime
$97 forever

Use when setting up Playwright test projects and organizing test suites with proper configuration and project structure.

Code Review

What this skill does


# Playwright Test Architecture

Master test organization, configuration, and project structure for scalable
and maintainable Playwright test suites. This skill covers best practices
for organizing tests, configuring projects, and optimizing test execution.

## Installation and Setup

```bash
# Install Playwright with browsers
npm init playwright@latest

# Install specific browsers
npx playwright install chromium firefox webkit

# Install dependencies only
npm install -D @playwright/test

# Update Playwright
npm install -D @playwright/test@latest
npx playwright install

# Show installed version
npx playwright --version
```

## Project Configuration

### Basic Configuration

**playwright.config.ts:**

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

export default defineConfig({
  // Test directory
  testDir: './tests',

  // Test timeout (30 seconds default)
  timeout: 30000,

  // Expect timeout for assertions
  expect: {
    timeout: 5000,
  },

  // Run tests in files in parallel
  fullyParallel: true,

  // Fail the build on CI if you accidentally left test.only
  forbidOnly: !!process.env.CI,

  // Retry on CI only
  retries: process.env.CI ? 2 : 0,

  // Reporter configuration
  reporter: 'html',

  // Shared settings for all projects
  use: {
    // Base URL for navigation
    baseURL: 'http://localhost:3000',

    // Collect trace on first retry
    trace: 'on-first-retry',

    // Screenshot on failure
    screenshot: 'only-on-failure',

    // Video on retry
    video: 'retain-on-failure',
  },

  // Configure projects for major browsers
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
  ],

  // Run local dev server before starting tests
  webServer: {
    command: 'npm run start',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
    timeout: 120000,
  },
});
```

### Advanced Configuration

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

export default defineConfig({
  testDir: './tests',
  testMatch: '**/*.spec.ts',
  testIgnore: '**/fixtures/**',

  // Global test timeout
  timeout: 30000,

  // Global setup/teardown
  globalSetup: require.resolve('./global-setup'),
  globalTeardown: require.resolve('./global-teardown'),

  // Expect configuration
  expect: {
    timeout: 5000,
    toHaveScreenshot: {
      maxDiffPixels: 100,
    },
    toMatchSnapshot: {
      threshold: 0.2,
    },
  },

  // Test execution
  fullyParallel: true,
  workers: process.env.CI ? 2 : undefined,
  retries: process.env.CI ? 2 : 0,
  forbidOnly: !!process.env.CI,
  maxFailures: process.env.CI ? 10 : undefined,

  // Output configuration
  outputDir: 'test-results',
  preserveOutput: 'failures-only',

  // Reporter configuration
  reporter: [
    ['html', { outputFolder: 'playwright-report' }],
    ['json', { outputFile: 'test-results/results.json' }],
    ['junit', { outputFile: 'test-results/junit.xml' }],
    ['list'],
  ],

  // Shared use options
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',

    // Browser options
    headless: !!process.env.CI,
    viewport: { width: 1280, height: 720 },
    ignoreHTTPSErrors: true,
    bypassCSP: false,

    // Timeouts
    actionTimeout: 10000,
    navigationTimeout: 30000,

    // Context options
    locale: 'en-US',
    timezoneId: 'America/New_York',
    permissions: ['geolocation'],
    geolocation: { latitude: 40.7128, longitude: -74.0060 },
    colorScheme: 'dark',

    // Recording options
    contextOptions: {
      recordVideo: {
        dir: 'videos',
        size: { width: 1280, height: 720 },
      },
    },
  },

  // Multiple projects for different scenarios
  projects: [
    // Setup project - runs first
    {
      name: 'setup',
      testMatch: /global\.setup\.ts/,
    },

    // Desktop browsers
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
      dependencies: ['setup'],
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
      dependencies: ['setup'],
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
      dependencies: ['setup'],
    },

    // Mobile browsers
    {
      name: 'Mobile Chrome',
      use: { ...devices['Pixel 5'] },
      dependencies: ['setup'],
    },
    {
      name: 'Mobile Safari',
      use: { ...devices['iPhone 13'] },
      dependencies: ['setup'],
    },

    // Branded browsers
    {
      name: 'Microsoft Edge',
      use: {
        ...devices['Desktop Edge'],
        channel: 'msedge',
      },
      dependencies: ['setup'],
    },
    {
      name: 'Google Chrome',
      use: {
        ...devices['Desktop Chrome'],
        channel: 'chrome',
      },
      dependencies: ['setup'],
    },

    // Custom viewport
    {
      name: 'tablet',
      use: {
        viewport: { width: 768, height: 1024 },
      },
      dependencies: ['setup'],
    },
  ],

  // Web server configuration
  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
    timeout: 120000,
    stdout: 'ignore',
    stderr: 'pipe',
  },
});
```

## Test Organization Patterns

### By Feature

```text
tests/
├── auth/
│   ├── login.spec.ts
│   ├── logout.spec.ts
│   ├── registration.spec.ts
│   └── password-reset.spec.ts
├── checkout/
│   ├── cart.spec.ts
│   ├── payment.spec.ts
│   └── confirmation.spec.ts
└── profile/
    ├── settings.spec.ts
    └── preferences.spec.ts
```

### By Page

```text
tests/
├── pages/
│   ├── home.spec.ts
│   ├── product-list.spec.ts
│   ├── product-detail.spec.ts
│   └── checkout.spec.ts
└── workflows/
    ├── purchase-flow.spec.ts
    └── user-journey.spec.ts
```

### By User Journey

```text
tests/
├── critical-paths/
│   ├── new-user-signup.spec.ts
│   ├── existing-user-login.spec.ts
│   └── purchase-completion.spec.ts
├── secondary-flows/
│   ├── profile-management.spec.ts
│   └── search-and-filter.spec.ts
└── edge-cases/
    ├── error-handling.spec.ts
    └── boundary-conditions.spec.ts
```

### Hybrid Approach (Recommended)

```text
tests/
├── e2e/                    # End-to-end user journeys
│   ├── checkout-flow.spec.ts
│   └── user-onboarding.spec.ts
├── features/               # Feature-specific tests
│   ├── auth/
│   │   ├── login.spec.ts
│   │   └── registration.spec.ts
│   ├── products/
│   │   ├── search.spec.ts
│   │   └── filters.spec.ts
│   └── profile/
│       └── settings.spec.ts
├── integration/            # API and integration tests
│   ├── api-auth.spec.ts
│   └── api-products.spec.ts
└── visual/                 # Visual regression tests
    ├── homepage.spec.ts
    └── product-page.spec.ts
```

## Test File Structure

### Basic Test Structure

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

test.describe('Login Feature', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/login');
  });

  test('should login with valid credentials', async ({ page }) => {
    await page.getByLabel('Email').fill('[email protected]');
    await page.getByLabel('Password').fill('password123');
    await page.getByRole('button', { name: 'Login' }).click();

    await expect(page).toHaveURL('/dashboard');
    await expect(page.getByText('Welcome back')).toBeVisible();
  });

  test('should show error with invalid credentials', async ({ page }) => {
    await page.getByLabel('Email').fill('[email protected]');
    await page.getByLabel('Password').fill('wrongpassword');
    await page.getByRole('button', { name: 'Login' }).click();

    await expect(
      page.getByText('Invalid email or password')
    ).toBeVisible();
    await expect(page).toHaveURL('/login');
  });
});
```

### Advanced T

Related in Code Review