使用说明
具有代理技能和MCP的剧作家E2E测试框架
一个完整的Playwright测试自动化框架 AI代理协助, SauceDemo应用程序测试套件,并且可重复使用 代理技能 用于编写高质量的E2E测试。
该项目同时具有以下功能:
- 工作参考 -SauceDemo应用程序的完整测试套件
- 模板框架 -您自己项目的代理技能和模式
📁 项目结构
.
├── .claude/ # Agent configuration
│ ├── skills/
│ │ ├── write-e2e-test/ # E2E test writing skill
│ │ └── auth-global-setup/ # Authentication setup skill
│ └── hooks/
│ └── lint-e2e.sh # ESLint validation hook
│
├── tests/
│ ├── e2e/
│ │ ├── auth.setup.ts # Global authentication setup
│ │ └── saucedemo/ # SauceDemo test suite
│ │ ├── checkout-flow.spec.ts # Checkout workflow tests
│ │ ├── role-based.spec.ts # Multi-user role tests
│ │ ├── advanced-scenarios.spec.ts # Complex scenarios
│ │ ├── performance-validation.spec.ts # Performance tests
│ │ └── visual-regression.spec.ts # Visual regression tests
│ │
│ ├── pages/ # Page Object Model
│ │ ├── login.page.ts
│ │ └── inventory.page.ts
│ │
│ ├── fixtures/
│ │ ├── api.ts # API fixture for state setup
│ │ ├── visual.ts # Visual regression utilities
│ │ ├── test-data.ts # Test data generators
│ │ ├── global-setup.ts # Global test setup
│ │ └── saucedemo/
│ │ ├── test.fixture.ts # SauceDemo custom fixture
│ │ └── roles.ts # User role definitions
│ │
│ └── AGENTS.md # Testing-specific instructions
│
├── docs/ # Documentation
│ ├── guides/ # Integration and setup guides
│ └── saucedemo/ # SauceDemo-specific docs
│
├── specs/ # Test specifications
│ └── *.spec.md # Test plans
│
├── AGENTS.md # Root-level project instructions
├── AGENTS-CUSTOM.md # Customized agent instructions
├── playwright.config.ts # Playwright configuration
├── .eslintrc.json # ESLint configuration
├── package.json # Dependencies and scripts
├── STRUCTURE.md # Detailed directory structure
├── QUICKSTART.md # Quick setup guide
├── INTEGRATION_CHECKLIST.md # Integration checklist
└── INTEGRATION_GUIDE.md # Full integration guide
🚀 快速开始
1.安装依赖项
npm install
2.配置环境
创建一个 .env 项目根目录中的文件:
# SauceDemo Application
SAUCE_BASE_URL=https://www.saucedemo.com
SAUCE_PASSWORD=secret_sauce
# User Roles
SAUCE_STANDARD_USER=standard_user
SAUCE_LOCKED_OUT_USER=locked_out_user
SAUCE_PROBLEM_USER=problem_user
SAUCE_PERFORMANCE_GLITCH_USER=performance_glitch_user
SAUCE_ERROR_USER=error_user
SAUCE_VISUAL_USER=visual_user
3.运行测试
# All tests
npm run test
# Specific test suites
npm run test:saucedemo # SauceDemo suite
npm run test:smoke # Smoke tests (@smoke)
npm run test:integration # Integration tests (@integration)
npm run test:regression # Regression tests (@regression)
npm run test:visual # Visual tests (@visual)
# Headed mode (see browser)
npm run test:headed
# UI mode (interactive)
npm run test:ui
# Debug mode
npm run test:debug
# View results
npm run test:report
4.棉绒
# Check for linting errors
npm run lint
# Fix linting errors
npm run lint:fix
🎯 工作测试套件:SauceDemo
该项目包括 完整的工作测试套件 为了 SauceDemo 应用程序:
- 基于角色的测试 -具有不同行为的6个不同用户角色
- 页面对象模型 -干净、可维护的页面交互(
login.page.ts,inventory.page.ts) - 数据驱动测试 -跨多个用户的参数化执行
- 多个测试套件:
role-based.spec.ts-登录和导航验证checkout-flow.spec.ts-完整的采购工作流程performance-validation.spec.ts-性能延迟检测visual-regression.spec.ts-基于屏幕截图的视觉一致性advanced-scenarios.spec.ts-复杂的用户场景
运行SauceDemo测试
# All SauceDemo tests
npm run test:saucedemo
# With UI mode
npm run test:ui -- tests/e2e/saucedemo/
# With headed browser
npm run test:headed -- tests/e2e/saucedemo/role-based.spec.ts
# Specific test
npx playwright test -g "should login successfully"
SauceDemo用户角色
| 角色 | 行为 | 测试重点 |
|---|---|---|
| 标准用户 | ✅ 正常运行 | 快乐之路 |
| 被锁在外面 | 🔒 登录被拒绝 | 错误处理 |
| 问题用户 | ⚠️ UI/功能问题 | 边缘案例 |
| 性能故障 | 🐢 性能缓慢 | 性能检测 |
| 错误用户 | ❌ 后端错误 | 错误恢复 |
| 视觉用户 | 👁️ 视觉差异 | 回归检测 |
有关SauceDemo的详细文档,请参阅 docs/sotedemo/
🤖 AI 代理技能
该框架包括 可重用代理技能 对于AI助手:
可用技能
-
write-e2e-test -系统地编写新的E2E测试
- 需求收集和澄清
- 实施研究
- 测试计划批准
- 结构化实施(5阶段工作流程)
- 自动验证和过滤
-
auth全局设置 -配置全局身份验证
- 预测试身份验证设置
- 代币存储和管理
- 测试集成模式
使用AI代理的技能
与克劳德或其他支持他的代理人合作时 .claude/skills/:
"Write an e2e test for the checkout flow"
"Set up global authentication for tests"
"Add visual regression tests for the inventory page"
代理将自动:
- 使用适当的技能
- 研究实际代码和API
- 提交一份测试计划供您审查
- 以最佳实践实施
- 运行测试以验证
📝 写作测试
页面对象模型模式
测试使用页面对象模型进行可维护性:
// pages/inventory.page.ts
export class InventoryPage {
constructor(private page: Page) {}
async addItemToCart(itemName: string) {
await this.page.getByRole('button', { name: `Add to cart: ${itemName}` }).click();
}
async viewCart() {
await this.page.getByTestId('shopping-cart-link').click();
}
}
// Test usage
test('should add item to cart', async ({ page }) => {
const inventory = new InventoryPage(page);
await inventory.addItemToCart('Backpack');
await inventory.viewCart();
});
使用自定义夹具
该项目包括SauceDemo的自定义夹具:
import { test, expect } from '../../fixtures/saucedemo/test.fixture';
test('should login with different roles', async ({ page, loginAs }) => {
// Helper function from fixture
await loginAs('standard_user');
await expect(page).toHaveURL(/\/inventory/);
});
API夹具(状态设置)
通过API快速设置测试数据:
test('should display order history', async ({ api, page }) => {
// Create user and order via API (faster than UI)
const user = await api.createUser({
email: 'test@example.com',
name: 'Test User'
});
const order = await api.createOrder({
userId: user.id,
items: ['item1', 'item2']
});
await page.goto(`/orders/${order.id}`);
await expect(page.getByText('Order confirmed')).toBeVisible();
// Automatic cleanup on test end
});
视觉回归测试
test('should match baseline screenshot', async ({ page }) => {
await page.goto('/inventory');
await expect(page).toHaveScreenshot('inventory-page.png', {
mask: [
page.getByTestId('current-user'), // Dynamic content
page.getByTestId('timestamp')
],
maxDiffPixels: 100
});
});
🔧 定制
适应自己的项目
这个框架可以很容易地适应测试任何web应用程序:
1.更新AGENTS.md文件
自定义说明:
- 代理商.md -根级项目惯例
- 测试/AGENTS.md -测试特定模式
2.创建页面对象
为您的应用程序创建页面类:
// tests/pages/dashboard.page.ts
import { Page } from '@playwright/test';
export class DashboardPage {
constructor(private page: Page) {}
async navigateTo() {
await this.page.goto('/dashboard');
}
async getWelcomeMessage() {
return this.page.getByRole('heading', { level: 1 });
}
}
3.延长固定装置
添加应用程序的自定义夹具:
// tests/fixtures/your-app.fixture.ts
import { test as base } from '@playwright/test';
import { YourAppPage } from '../pages/your-app.page';
type YourAppFixtures = {
appPage: YourAppPage;
};
export const test = base.extend<YourAppFixtures>({
appPage: async ({ page }, use) => {
const appPage = new YourAppPage(page);
await use(appPage);
},
});
export { expect } from '@playwright/test';
4.配置环境
更新 .env 使用应用程序的变量:
APP_BASE_URL=https://your-app.com
API_KEY=your-api-key
# ... other env vars
扩展ESLint规则
在中添加特定于项目的linting规则 .eslintrc.json:
{
"rules": {
"playwright/valid-title": [
"error",
{
"mustMatch": {
"test": "^should",
"describe": ""
}
}
]
}
}
🎓 最佳实践(内置)
定位器策略(优先级顺序)
ESLint规则强制执行此优先级:
- ✅
getByRole('button', { name: 'Submit' })-最便于访问 - ✅
getByLabel('Email')-对于表单字段 - ✅
getByTestId('user-menu')-当语义查询不可能时 - ✅
getByText('Welcome')-对于唯一文本 - ❌
page.locator('.btn-primary')-避免CSS选择器(ESLint错误)
等待策略
// ✅ GOOD - Wait for specific response
const responsePromise = page.waitForResponse(
response => response.url().includes('/api/users') && response.status() === 200
);
await page.getByRole('button', { name: 'Load Users' }).click();
await responsePromise;
// ✅ GOOD - Wait for element
await expect(page.getByText('Data loaded')).toBeVisible();
// ❌ BAD - Arbitrary waitForTimeout (ESLint error)
await page.waitForTimeout(2000);
测试结构(届时给出)
test('should complete checkout', async ({ page }) => {
// GIVEN: User is logged in and on inventory page
await page.goto('/inventory');
// WHEN: User adds items and checks out
await page.getByRole('button', { name: /add to cart/i }).first().click();
await page.getByRole('link', { name: 'cart' }).click();
await page.getByRole('button', { name: 'Checkout' }).click();
// THEN: Checkout flow is completed
await expect(page).toHaveURL(/checkout/);
});
测试独立性
// ✅ GOOD - Each test is independent
test('should create project', async ({ api, page }) => {
const project = await api.createProject({ name: 'Test' });
await page.goto(`/projects/${project.id}`);
// Automatic cleanup via fixture
});
// ❌ BAD - Tests with shared state (causes flakiness in parallel)
let sharedProject;
beforeAll(async () => {
sharedProject = await api.createProject({ name: 'Shared' });
});
错误处理
// ✅ GOOD - Graceful error handling
try {
const response = await page.goto('/protected', { waitUntil: 'networkidle' });
if (!response?.ok()) {
throw new Error(`Failed to load: ${response?.status()}`);
}
} catch (error) {
console.error('Navigation failed:', error);
throw;
}
// ❌ BAD - Swallowing errors
page.goto('/protected').catch(() => {});
ESLint执行
这个项目的 ESLint配置 自动捕获:
- ❌
waitForTimeout()-请改用正确的断言 - ❌
networkidle-使用waitForResponse()相反 - ❌ 强制选项(
{ force: true })-改为修复测试 - ❌ 硬编码超时-使用动态等待
- ✅ Web优先断言-
expect()超过自定义代码
🐛 调试与故障排除
交互式调试
# Debug Mode - Step through tests
npm run test:debug
# UI Mode - Control test execution
npm run test:ui
# Headed Mode - See browser activity
npm run test:headed
# Specific test
npx playwright test -g "should login successfully"
检测瑕疵测试
# Run test multiple times to check for flakiness
npx playwright test -g "test name" --repeat-each=5
# Run in serial mode (useful for dependency debugging)
npx playwright test --serial
# View detailed test report
npm run test:report
常见问题
| 问题 | 解决方案 |
|---|---|
| 测试在本地通过,在CI中失败 | 检查环境变量、浏览器版本 |
| 测试随机失败 | 通常是时间问题-使用适当的等待而不是超时 |
| 选择器不工作 | 使用浏览器DevTools, page.pause(),或调试模式 |
| API调用挂起 | 在DevTools中检查网络请求,使用 waitForResponse() |
| 视觉回归不匹配 | 使用更新快照 --update-snapshots 如果是故意的 |
调试命令
// Pause test execution
test('debug example', async ({ page }) => {
await page.pause(); // Opens DevTools
});
// Print element information
const element = page.getByRole('button', { name: 'Click me' });
console.log(await element.boundingBox());
// Track network requests
page.on('request', req => console.log(req.url()));
page.on('response', res => console.log(res.status(), res.url()));
📚 文档
快速参考
- QUICKSTART.md -5分钟设置指南
- 结构.md -详细的目录结构
- 代理商.md -AI代理说明
集成指南
SauceDemo文档
- docs/sucedemo/saucedemo_QUICKSTART.md
- docs/saucedemo/saucedemo_IMPLEMENTATION_GUIDE.md
- docs/saucedemo/saucedemo_ARCHITECTURE.md
外部资源
🔄 整合到现有项目中
要将此框架集成到您现有的Playwright项目中:
-
复制代理技能:
cp -r .claude/skills <your-project>/.claude/ -
复制测试指南:
cp AGENTS.md <your-project>/AGENTS.md cp tests/AGENTS.md <your-project>/tests/AGENTS.md -
复制夹具和配置:
cp -r tests/fixtures <your-project>/tests/ cp .eslintrc.json <your-project>/ -
更新package.json 使用lint脚本:
{ "scripts": { "lint": "eslint tests/**/*.ts --fix-dry-run", "lint:fix": "eslint tests/**/*.ts --fix" } }
看 集成_指南.md 详细步骤。
🤝 项目特点
框架功能
✅ AI 代理技能 -具有质量验证的自动化E2E测试编写
✅ SauceDemo示例 -完整的工作测试套件供参考
✅ 页面对象模型 -可维护、可扩展的测试代码
✅ 全局设置 -测试前认证和状态管理
✅ 定制夹具 -可重用的测试工具和帮助程序
✅ 目视检测 -基于屏幕截图的回归测试
✅ ESLint集成 -自动执行最佳实践
✅ 多用户测试 -基于角色和数据驱动的测试执行
✅ 性能测试 -检测和衡量性能问题
✅ 环境配置 -安全的凭证管理
代码质量
- TypeScript从头开始
- 严格的衣冠规定
- 自验证测试工作流程
- 自动屏幕截图区分
- 内置测试数据生成器
📄 许可证
麻省理工学院