mcpField
P
playwright-e2e-tester

playwright-e2e-tester

github.com/curiositech测试与质量257189 次安装2 天前更新
代码仓库

关于 playwright-e2e-tester

playwright-e2e-tester 是面向编写和维护 Playwright 端到端测试团队的技能,涵盖测试设计、配置、调试与 CI 流程,并涉及浏览器、API 和视觉测试。

主要功能

  1. 01根据用户故事生成测试
  2. 02使用页面对象模式和 fixtures
  3. 03配置浏览器、视口与报告器
  4. 04模拟 API 并检查网络请求
  5. 05配置 GitHub Actions 与分片执行
  6. 06分析追踪并减少不稳定测试

适用场景

  1. 01为关键用户流程编写端到端测试
  2. 02排查间歇性测试故障
  3. 03通过截图比对发现视觉回归
  4. 04在 CI 流程中运行浏览器测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/curiositech/some_claude_skills --skill playwright-e2e-tester

安装后在 Claude Code 中输入/playwright-e2e-tester确认已加载。

附带文件.claude-plugin/plugin.json

详细介绍

Playwright 端到端测试

概述

精通使用 Playwright 这一现代跨浏览器测试框架进行端到端测试。专长包括测试生成、页面对象模式、视觉回归测试和 CI/CD 集成。可处理复杂测试场景,包括身份验证流程、API 模拟和移动设备仿真。

适用场景

  • 在新项目或现有项目中设置 Playwright
  • 为关键用户流程编写端到端测试
  • 调试不稳定的测试或测试失败
  • 实现视觉回归测试
  • 为 CI/CD 流水线配置 Playwright
  • 从 Cypress、Selenium 或 Puppeteer 迁移
  • 使用会话管理测试经过身份验证的流程
  • 跨浏览器测试(Chromium、Firefox、WebKit)

能力

测试生成与编写
  • 根据用户故事或验收标准生成 Playwright 测试
  • 遵循最佳实践编写测试(定位器、断言、等待)
  • 实现页面对象模型(POM)模式
  • 创建可复用的测试 fixture 和工具
  • 处理动态内容和竞态条件
配置与设置
  • 为不同环境配置 playwright.config.ts
  • 为多个浏览器和视口设置项目
  • 配置基础 URL、超时和重试
  • 实现用于身份验证的全局设置/清理
  • 设置测试报告器(HTML、JSON、JUnit)
高级模式
  • 使用 route() 和 fulfill() 模拟 API
  • 拦截网络请求并验证请求
  • 使用 toHaveScreenshot() 进行视觉回归测试
  • 使用 @axe-core/playwright 进行无障碍测试
  • 移动设备仿真和设备测试
  • 模拟地理位置和权限
CI/CD 集成
  • 配置 GitHub Actions 工作流
  • 使用分片并行执行测试
  • 收集构建产物(追踪、截图、视频)
  • 检测不稳定的测试并制定重试策略
  • 报告测试结果并发送通知
调试与维护
  • 使用 Playwright Inspector 和 Trace Viewer
  • 使用 page.pause() 和有界面模式进行调试
  • 分析测试追踪以查找失败原因
  • 通过适当的等待减少测试不稳定性
  • 长期维护测试稳定性

依赖项

适用于搭配:

  • vitest-testing-patterns - 与端到端测试互补的单元测试模式
  • github-actions-pipeline-builder - CI/CD 流水线设置
  • accessibility-auditor - 扩展无障碍测试
  • api-architect - 与端到端测试搭配的 API 契约测试

示例

基本测试结构
import { test, expect } from '@playwright/test';

test.describe('User Authentication', () => {
  test('should allow user to sign in', async ({ page }) => {
    await page.goto('/login');

    await page.getByLabel('Email').fill('[email protected]');
    await page.getByLabel('Password').fill('securepassword');
    await page.getByRole('button', { name: 'Sign In' }).click();

    await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
    await expect(page).toHaveURL('/dashboard');
  });
});
页面对象模式
// pages/LoginPage.ts
import { Page, Locator } from '@playwright/test';

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

  constructor(page: Page) {
    this.page = page;
    this.emailInput = page.getByLabel('Email');
    this.passwordInput = page.getByLabel('Password');
    this.signInButton = page.getByRole('button', { name: 'Sign In' });
  }

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

  async signIn(email: string, password: string) {
    await this.emailInput.fill(email);
    await this.passwordInput.fill(password);
    await this.signInButton.click();
  }
}
身份验证设置 fixture
// fixtures/auth.ts
import { test as base } from '@playwright/test';

export const test = base.extend({
  authenticatedPage: async ({ page }, use) => {
    // Perform authentication
    await page.goto('/login');
    await page.getByLabel('Email').fill(process.env.TEST_USER!);
    await page.getByLabel('Password').fill(process.env.TEST_PASS!);
    await page.getByRole('button', { name: 'Sign In' }).click();

    // Wait for auth to complete
    await page.waitForURL('/dashboard');

    // Use the authenticated page in tests
    await use(page);
  },
});
GitHub Actions CI
name: E2E Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright browsers
        run: npx playwright install --with-deps

      - name: Run E2E tests
        run: npx playwright test

      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report/
视觉回归测试
test('homepage matches snapshot', async ({ page }) => {
  await page.goto('/');

  // Full page screenshot comparison
  await expect(page).toHaveScreenshot('homepage.png', {
    fullPage: true,
    maxDiffPixelRatio: 0.01,
  });

  // Component-level screenshot
  const hero = page.getByTestId('hero-section');
  await expect(hero).toHaveScreenshot('hero-section.png');
});
API 模拟
test('displays products from API', async ({ page }) => {
  // Mock the API response
  await page.route('**/api/products', async (route) => {
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify([
        { id: 1, name: 'Product A', price: 29.99 },
        { id: 2, name: 'Product B', price: 49.99 },
      ]),
    });
  });

  await page.goto('/products');

  await expect(page.getByText('Product A')).toBeVisible();
  await expect(page.getByText('$29.99')).toBeVisible();
});

最佳实践

  1. 使用基于角色的定位器 - 优先使用 getByRole()、getByLabel()、getByText(),而非 CSS 选择器
  2. 避免固定等待 - 使用 waitForSelector()、waitForURL() 或断言,而非 waitForTimeout()
  3. 隔离测试 - 每项测试都应彼此独立,不依赖其他测试的状态
  4. 使用 fixture - 通过 fixture 共享设置逻辑,而非使用 beforeEach 钩子
  5. 让测试保持专注 - 每项测试只测试一个用户流程,避免测试多个无关事项
  6. 主动处理不稳定性 - 使用恰当的等待、重试和稳定的定位器
  7. 使用页面对象组织代码 - 封装页面交互以便维护
  8. 在 CI 中运行 - 合并前务必在 CI 中运行端到端测试

常见问题

  • 定位器不稳定:避免使用 nth-child(3) 或自动生成的类名等脆弱选择器
  • 竞态条件:交互前务必等待元素或导航完成
  • 共享状态:测试不应依赖执行顺序
  • 测试速度慢:尽可能使用 API 调用设置状态,而非通过 UI 交互
  • 缺少清理:清理测试数据,避免运行之间相互污染

评论

支持 Markdown