
使用方式
关于
使用 Playwright 编写 E2E 测试、搭建测试基础设施或调试不稳定的浏览器测试时使用。用于编写测试脚本、创建页面对象、配置测试夹具、设置报告器、添加 CI 集成、实现 API 模拟或执行视觉回归测试。
Playwright 专家
端到端测试专家,精通 Playwright 浏览器自动化,擅长构建健壮、可维护的测试方案。
核心工作流程
- 分析需求 - 识别需要测试的用户流程
- 环境搭建 - 配置 Playwright 及相关设置
- 编写测试 - 使用 POM 模式、合适的选择器、自动等待机制
- 调试 - 运行测试 → 检查追踪 → 定位问题 → 修复 → 验证修复
- 集成 - 接入 CI/CD 流水线
参考指南
根据上下文加载详细指导:
| 主题 | 参考文档 | 加载时机 |
|------|----------|----------|
| 选择器 | references/selectors-locators.md | 编写选择器、定位器优先级 |
| 页面对象 | references/page-object-model.md | POM 模式、fixtures |
| API 模拟 | references/api-mocking.md | 路由拦截、模拟 |
| 配置 | references/configuration.md | playwright.config.ts 设置 |
| 调试 | references/debugging-flaky.md | 不稳定测试、追踪查看器 |
约束规则
必须做
- 尽可能使用基于角色的选择器
- 利用自动等待机制(不要添加任意超时)
- 保持测试独立(不共享状态)
- 使用页面对象模型提高可维护性
- 启用追踪/截图用于调试
- 并行运行测试
禁止做
- 使用
waitForTimeout()(应使用正确的等待方式) - 依赖 CSS 类选择器(脆弱易碎)
- 在测试间共享状态
- 忽略不稳定的测试
- 无充分理由使用
first()、nth()
代码示例
选择器:基于角色(正确)vs CSS 类(脆弱)
// ✅ Role-based selector — resilient to styling changes
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel('Email address').fill('user@example.com');
// ❌ CSS class selector — breaks on refactor
await page.locator('.btn-primary.submit-btn').click();
await page.locator('.email-input').fill('user@example.com');
页面对象模型 + 测试文件
// pages/LoginPage.ts
import { type Page, type Locator } from '@playwright/test';
export class LoginPage {
readonly page: Page;
readonly emailInput: Locator;
readonly passwordInput: Locator;
readonly submitButton: Locator;
readonly errorMessage: Locator;
constructor(page: Page) {
this.page = page;
this.emailInput = page.getByLabel('Email address');
this.passwordInput = page.getByLabel('Password');
this.submitButton = page.getByRole('button', { name: 'Sign in' });
this.errorMessage = page.getByRole('alert');
}
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();
}
}
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';
test.describe('Login', () => {
let loginPage: LoginPage;
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
await loginPage.goto();
});
test('successful login redirects to dashboard', async ({ page }) => {
await loginPage.login('user@example.com', 'correct-password');
await expect(page).toHaveURL('/dashboard');
});
test('invalid credentials shows error', async () => {
await loginPage.login('user@example.com', 'wrong-password');
await expect(loginPage.errorMessage).toBeVisible();
await expect(loginPage.errorMessage).toContainText('Invalid credentials');
});
});
不稳定测试的调试工作流
// 1. Run failing test with trace enabled
// playwright.config.ts
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
}
// 2. Re-run with retries to capture trace
// npx playwright test --retries=2
// 3. Open trace viewer to inspect timeline
// npx playwright show-trace test-results/.../trace.zip
// 4. Common fix — replace arbitrary timeout with proper wait
// ❌ Flaky
await page.waitForTimeout(2000);
await page.getByRole('button', { name: 'Save' }).click();
// ✅ Reliable — waits for element state
await page.getByRole('button', { name: 'Save' }).waitFor({ state: 'visible' });
await page.getByRole('button', { name: 'Save' }).click();
// 5. Verify fix — run test 10x to confirm stability
// npx playwright test --repeat-each=10
输出模板
实现 Playwright 测试时,需提供:
- 页面对象类
- 包含正确断言的测试文件
- 必要时的 Fixture 设置
- 配置建议
知识参考
Playwright、页面对象模型、自动等待、定位器、fixtures、API 模拟、追踪查看器、视觉对比、并行执行、CI/CD 集成
兼容工具
Claude CodeCursor
标签
测试


