Skip to main content
ClaudeWave
Skill171 estrellas del repoactualizado 1mo ago

Playwright E2E Testing

Build end-to-end tests with Playwright, Feature Object pattern, cross-browser testing, and visual regression. Apply when testing critical user flows, automating regression testing, or validating integrations.

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/ThamJiaHe/claude-code-handbook /tmp/playwright-e2e-testing && cp -r /tmp/playwright-e2e-testing/skills/examples/playwright-e2e-testing- ~/.claude/skills/playwright-e2e-testing
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

playwright-e2e-testing-skill.md

# Playwright E2E Testing

Systematic end-to-end testing with Playwright ensuring critical user flows work correctly.

## Overview

This Skill enforces:
- Feature Object pattern (replaces Page Object)
- Arrange-Act-Assert test structure
- Cross-browser testing (Chromium, Firefox, WebKit)
- Reliable selectors (getByRole, getByTestId)
- Visual regression testing
- Network mocking and interception
- Parallel test execution
- CI/CD integration

Apply when testing critical user flows, automating regression testing, or validating integrations.

## Setup Playwright

### Install

```bash
npm install -D @playwright/test
npx playwright install
```

### Configure playwright.config.ts

```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',
    video: 'retain-on-failure'
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] }
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] }
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] }
    },
    {
      name: 'Mobile Chrome',
      use: { ...devices['Pixel 5'] }
    }
  ],
  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI
  }
});
```

### Package.json Scripts

```json
{
  "scripts": {
    "test:e2e": "playwright test",
    "test:e2e:ui": "playwright test --ui",
    "test:e2e:debug": "playwright test --debug"
  }
}
```

## Feature Object Pattern

### Directory Structure

```
e2e/
├── features/
│   ├── auth.feature.ts      # Authentication flows
│   ├── users.feature.ts     # User management
│   └── dashboard.feature.ts # Dashboard features
├── fixtures/
│   ├── api.fixture.ts       # API interactions
│   └── ui.fixture.ts        # UI interactions
└── tests/
    ├── auth.spec.ts
    ├── users.spec.ts
    └── dashboard.spec.ts
```

### Feature Object (Auth)

```ts
// e2e/features/auth.feature.ts
import { Page } from '@playwright/test';

export class AuthFeature {
  constructor(private page: Page) {}

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

  async enterEmail(email: string) {
    await this.page.getByLabel('Email').fill(email);
  }

  async enterPassword(password: string) {
    await this.page.getByLabel('Password').fill(password);
  }

  async clickLoginButton() {
    await this.page.getByRole('button', { name: /login/i }).click();
  }

  async verifyLoginSuccess() {
    await this.page.waitForURL('/dashboard');
    await expect(this.page).toHaveURL('/dashboard');
  }

  async verifyLoginError(message: string) {
    const error = this.page.getByRole('alert');
    await expect(error).toContainText(message);
  }

  async logout() {
    await this.page.getByRole('button', { name: /logout/i }).click();
    await this.page.waitForURL('/login');
  }
}
```

### Fixture Setup

```ts
// e2e/fixtures/test.fixture.ts
import { test as base } from '@playwright/test';
import { AuthFeature } from '../features/auth.feature';
import { DashboardFeature } from '../features/dashboard.feature';

type Fixtures = {
  auth: AuthFeature;
  dashboard: DashboardFeature;
};

export const test = base.extend<Fixtures>({
  auth: async ({ page }, use) => {
    const auth = new AuthFeature(page);
    await use(auth);
  },
  dashboard: async ({ page }, use) => {
    const dashboard = new DashboardFeature(page);
    await use(dashboard);
  }
});

export { expect } from '@playwright/test';
```

## Arrange-Act-Assert Pattern

### Login Test

```ts
// e2e/tests/auth.spec.ts
import { test, expect } from '../fixtures/test.fixture';

test.describe('Authentication', () => {
  test('successful login flow', async ({ auth }) => {
    // ARRANGE: Navigate to login page
    await auth.navigateToLogin();

    // ACT: Enter credentials and submit
    await auth.enterEmail('user@example.com');
    await auth.enterPassword('password123');
    await auth.clickLoginButton();

    // ASSERT: Verify login success
    await auth.verifyLoginSuccess();
  });

  test('login with invalid credentials', async ({ auth }) => {
    // ARRANGE
    await auth.navigateToLogin();

    // ACT
    await auth.enterEmail('user@example.com');
    await auth.enterPassword('wrongpassword');
    await auth.clickLoginButton();

    // ASSERT
    await auth.verifyLoginError('Invalid credentials');
  });

  test('logout flow', async ({ page, auth }) => {
    // ARRANGE: Login first
    await auth.navigateToLogin();
    await auth.enterEmail('user@example.com');
    await auth.enterPassword('password123');
    await auth.clickLoginButton();
    await page.waitForURL('/dashboard');

    // ACT
    await auth.logout();

    // ASSERT
    await expect(page).toHaveURL('/login');
  });
});
```

## Selectors (getByRole, getByTestId)

### Recommended Selectors

```ts
// ✅ GOOD: Accessible selectors
await page.getByRole('button', { name: /submit/i }).click();
await page.getByRole('textbox', { name: /email/i }).fill('user@example.com');
await page.getByLabel('Password').fill('password');
await page.getByText('Welcome, Alice').isVisible();

// ✅ GOOD: Test IDs (for complex elements)
<div data-testid="user-profile">Profile</div>
await page.getByTestId('user-profile').click();

// ❌ BAD: Fragile selectors (auto-generated)
await page.locator('.css-1a2b3c4d').click();  // Will break on CSS change

// ❌ BAD: XPath (brittle)
await page.locator('//*[@class="button"]').click();

// ❌ BAD: Overly specific
await page.locator('div > section > form > button').click();
```

## Critical Admin Flows

### User Management Test

```ts
// e2e/features/admin.feature.ts
export class AdminFeature {
  constructor(private page: Page) {}

  async navigateToUsers() {
API DevelopmentSkill

Build REST APIs with proper error handling, status codes, request validation, response formatting, and rate limiting. Apply when creating API routes, handling errors, validating input, or designing API responses.

API Security HardeningSkill

Harden REST and GraphQL APIs against common attack vectors. Apply when building API endpoints, implementing authentication, handling file uploads, or exposing APIs to external consumers.

AWS Cloud InfrastructureSkill

Deploy Node.js applications on AWS using EC2, RDS, and managed services with security best practices. Apply when setting up AWS infrastructure, configuring databases, managing security, or optimizing costs.

Build Error ResolverSkill

Rapidly fix build failures, type errors, and lint issues with minimal diffs. Apply when builds fail, TypeScript reports errors, or CI/CD pipelines break. Focuses on getting the build green fast.

Cybersecurity Threat ModelingSkill

STRIDE-based threat modeling for application architecture. Apply when designing new systems, reviewing architecture, or assessing security posture of existing applications.

Docker ContainerizationSkill

Production-ready Docker patterns for multi-stage builds, security hardening, and orchestration. Apply when creating Dockerfiles, docker-compose configs, or deploying containerized applications.

Git WorkflowSkill

Enforces Conventional Commits, PR standards, merge conflict resolution, and branch management. Apply when committing code, opening PRs, resolving conflicts, managing branches, or handling Git operations.

Google Cloud Platform & APIsSkill

Deploy Node.js applications on Google Cloud with Cloud Run, Cloud Firestore, and Google APIs. Implement OAuth2 authentication and manage service accounts. Apply when building serverless applications, integrating Google services, or deploying to GCP.