关于 playwright-e2e-tester
playwright-e2e-tester 是面向编写和维护 Playwright 端到端测试团队的技能,涵盖测试设计、配置、调试与 CI 流程,并涉及浏览器、API 和视觉测试。
主要功能
- 01根据用户故事生成测试
- 02使用页面对象模式和 fixtures
- 03配置浏览器、视口与报告器
- 04模拟 API 并检查网络请求
- 05配置 GitHub Actions 与分片执行
- 06分析追踪并减少不稳定测试
适用场景
- 01为关键用户流程编写端到端测试
- 02排查间歇性测试故障
- 03通过截图比对发现视觉回归
- 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();
});
最佳实践
- 使用基于角色的定位器 - 优先使用
getByRole()、getByLabel()、getByText(),而非 CSS 选择器 - 避免固定等待 - 使用
waitForSelector()、waitForURL()或断言,而非waitForTimeout() - 隔离测试 - 每项测试都应彼此独立,不依赖其他测试的状态
- 使用 fixture - 通过 fixture 共享设置逻辑,而非使用
beforeEach钩子 - 让测试保持专注 - 每项测试只测试一个用户流程,避免测试多个无关事项
- 主动处理不稳定性 - 使用恰当的等待、重试和稳定的定位器
- 使用页面对象组织代码 - 封装页面交互以便维护
- 在 CI 中运行 - 合并前务必在 CI 中运行端到端测试
常见问题
- 定位器不稳定:避免使用
nth-child(3)或自动生成的类名等脆弱选择器 - 竞态条件:交互前务必等待元素或导航完成
- 共享状态:测试不应依赖执行顺序
- 测试速度慢:尽可能使用 API 调用设置状态,而非通过 UI 交互
- 缺少清理:清理测试数据,避免运行之间相互污染
评论
支持 Markdown