Playwright端到端测试框架

一个完整的Playwright测试自动化框架,提供AI代理辅助、SauceDemo应用测试套件和可重用的代理技能,用于编写高质量的端到端测试。

  • by Duynguyen231
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 Duynguyen231/Playwright-MCP

使用说明

具有代理技能和MCP的剧作家E2E测试框架

一个完整的Playwright测试自动化框架 AI代理协助, SauceDemo应用程序测试套件,并且可重复使用 代理技能 用于编写高质量的E2E测试。

该项目同时具有以下功能:

  1. 工作参考 -SauceDemo应用程序的完整测试套件
  2. 模板框架 -您自己项目的代理技能和模式

📁 项目结构

.
├── .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助手:

可用技能

  1. write-e2e-test -系统地编写新的E2E测试

    • 需求收集和澄清
    • 实施研究
    • 测试计划批准
    • 结构化实施(5阶段工作流程)
    • 自动验证和过滤
  2. 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文件

自定义说明:

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规则强制执行此优先级:

  1. ✅ getByRole('button', { name: 'Submit' }) -最便于访问
  2. ✅ getByLabel('Email') -对于表单字段
  3. ✅ getByTestId('user-menu') -当语义查询不可能时
  4. ✅ getByText('Welcome') -对于唯一文本
  5. ❌ 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()));

📚 文档

快速参考

集成指南

SauceDemo文档

外部资源

🔄 整合到现有项目中

要将此框架集成到您现有的Playwright项目中:

  1. 复制代理技能:

    cp -r .claude/skills <your-project>/.claude/
    
  2. 复制测试指南:

    cp AGENTS.md <your-project>/AGENTS.md
    cp tests/AGENTS.md <your-project>/tests/AGENTS.md
    
  3. 复制夹具和配置:

    cp -r tests/fixtures <your-project>/tests/
    cp .eslintrc.json <your-project>/
    
  4. 更新package.json 使用lint脚本:

    {
      "scripts": {
        "lint": "eslint tests/**/*.ts --fix-dry-run",
        "lint:fix": "eslint tests/**/*.ts --fix"
      }
    }
    

看 集成_指南.md 详细步骤。

🤝 项目特点

框架功能

✅ AI 代理技能 -具有质量验证的自动化E2E测试编写
✅ SauceDemo示例 -完整的工作测试套件供参考
✅ 页面对象模型 -可维护、可扩展的测试代码
✅ 全局设置 -测试前认证和状态管理
✅ 定制夹具 -可重用的测试工具和帮助程序
✅ 目视检测 -基于屏幕截图的回归测试
✅ ESLint集成 -自动执行最佳实践
✅ 多用户测试 -基于角色和数据驱动的测试执行
✅ 性能测试 -检测和衡量性能问题
✅ 环境配置 -安全的凭证管理

代码质量

  • TypeScript从头开始
  • 严格的衣冠规定
  • 自验证测试工作流程
  • 自动屏幕截图区分
  • 内置测试数据生成器

📄 许可证

麻省理工学院