# 测试文档 ## 测试概述 项目使用 Playwright 进行端到端(E2E)测试,测试框架位于 `e2e/` 目录,采用 Page Object 模式组织测试代码。 ## 测试框架结构 ``` e2e/ ├── src/ │ ├── config/ # 配置文件 │ │ ├── environments.ts # 环境配置 │ │ └── network-configs.ts # 网络配置 │ ├── data/ # 测试数据 │ │ └── test-data.ts │ ├── fixtures/ # 测试 Fixtures │ │ ├── base.fixture.ts # 基础 Fixture │ │ └── a11y.fixture.ts # 可访问性 Fixture │ ├── pages/ # Page Object Model │ │ ├── BasePage.ts # 基础页面 │ │ ├── HomePage.ts # 首页 │ │ ├── AboutPage.ts # 关于页 │ │ ├── CasesPage.ts # 案例页 │ │ ├── ContactPage.ts # 联系页 │ │ ├── NewsPage.ts # 新闻页 │ │ ├── ProductsPage.ts # 产品页 │ │ ├── ServicesPage.ts # 服务页 │ │ └── SolutionsPage.ts # 解决方案页 │ └── tests/ # 测试用例 │ ├── accessibility/ # 可访问性测试 │ ├── debug/ # 调试测试 │ ├── deployment/ # 部署就绪测试 │ ├── error-handling/ # 错误处理测试 │ ├── mobile/ # 移动端测试 │ ├── performance/ # 性能测试 │ ├── regression/ # 回归测试 │ ├── responsive/ # 响应式测试 │ ├── security/ # 安全测试 │ ├── smoke/ # 冒烟测试 │ ├── utils/ # 工具测试 │ └── visual/ # 视觉回归测试 ├── playwright.config.ts # Playwright 配置 ├── package.json └── .env.example ``` ## 测试类型 ### 1. 冒烟测试 (Smoke Tests) **目录**: `e2e/src/tests/smoke/` **目的**: 验证核心功能是否正常工作 **测试文件**: - `all-pages.spec.ts` - 所有页面加载测试 - `home-page.smoke.spec.ts` - 首页冒烟测试 - `contact-page.smoke.spec.ts` - 联系页冒烟测试 - `navigation.smoke.spec.ts` - 导航冒烟测试 **运行命令**: ```bash npm run test:smoke # 或 npx playwright test --grep @smoke ``` ### 2. 回归测试 (Regression Tests) **目录**: `e2e/src/tests/regression/` **目的**: 确保新代码没有破坏现有功能 **测试文件**: - `contact-form.regression.spec.ts` - 联系表单回归测试 - `home-page.regression.spec.ts` - 首页回归测试 - `navigation.spec.ts` - 导航回归测试 **运行命令**: ```bash npm run test:regression # 或 npx playwright test --grep @regression ``` ### 3. 性能测试 (Performance Tests) **目录**: `e2e/src/tests/performance/` **目的**: 验证页面性能指标 **测试文件**: - `core-web-vitals.spec.ts` - Core Web Vitals 测试 - `performance.spec.ts` - 通用性能测试 - `image-loading.spec.ts` - 图片加载性能 - `interaction-performance.spec.ts` - 交互性能测试 **监控指标**: - LCP (Largest Contentful Paint) < 2.5s - FID (First Input Delay) < 100ms - CLS (Cumulative Layout Shift) < 0.1 - TTFB (Time to First Byte) < 600ms **运行命令**: ```bash npm run test:performance # 或 npx playwright test --grep @performance ``` ### 4. 响应式测试 (Responsive Tests) **目录**: `e2e/src/tests/responsive/` **目的**: 验证多设备适配 **测试文件**: - `responsive.spec.ts` - 响应式布局测试 - `mobile-interaction.spec.ts` - 移动端交互测试 **测试设备**: - Desktop: 1920x1080, 1366x768 - Tablet: iPad Pro (1024x1366), iPad Air (820x1180) - Mobile: iPhone 12 (390x844), iPhone SE (375x667), Pixel 5 (393x851) **运行命令**: ```bash npm run test:responsive # 或 npx playwright test --grep @responsive ``` ### 5. 可访问性测试 (Accessibility Tests) **目录**: `e2e/src/tests/accessibility/` **目的**: 验证 WCAG 合规性 **测试文件**: - `accessibility.spec.ts` - 可访问性测试 - `wcag-compliance.spec.ts` - WCAG 合规测试 **检查项**: - 颜色对比度 ≥ 4.5:1 (AA 级别) - 键盘导航支持 - 屏幕阅读器兼容 - ARIA 属性正确性 - 焦点顺序合理 **运行命令**: ```bash npm run test:accessibility # 或 npx playwright test --grep @accessibility ``` ### 6. 安全测试 (Security Tests) **目录**: `e2e/src/tests/security/` **目的**: 验证安全防护措施 **测试文件**: - `security.spec.ts` - 通用安全测试 - `xss-protection.spec.ts` - XSS 防护测试 - `csrf-protection.spec.ts` - CSRF 防护测试 **检查项**: - XSS 攻击防护 - CSRF Token 验证 - 安全头部配置 - 表单验证 **运行命令**: ```bash npm run test:security # 或 npx playwright test --grep @security ``` ### 7. 视觉回归测试 (Visual Tests) **目录**: `e2e/src/tests/visual/` **目的**: 检测 UI 变化 **测试文件**: - `home-page.visual.spec.ts` - 首页视觉测试 - `contact-page.visual.spec.ts` - 联系页视觉测试 - `visual-regression.spec.ts` - 视觉回归测试 **快照目录**: - `*-snapshots/` - 基线快照 **运行命令**: ```bash npm run test:visual # 或 npx playwright test --grep @visual ``` **更新快照**: ```bash npx playwright test --grep @visual --update-snapshots ``` ### 8. 移动端测试 (Mobile Tests) **目录**: `e2e/src/tests/mobile/` **目的**: 验证移动端功能 **测试文件**: - `compatibility/mobile-compatibility.spec.ts` - 兼容性测试 - `gesture/mobile-gesture.spec.ts` - 手势测试 - `network/network-environment.spec.ts` - 网络环境测试 - `performance/mobile-performance.spec.ts` - 移动性能测试 - `pwa/pwa-functionality.spec.ts` - PWA 功能测试 - `mobile-ux.spec.ts` - 移动端 UX 测试 ### 9. 部署就绪测试 (Deployment Tests) **目录**: `e2e/src/tests/deployment/` **目的**: 验证部署前检查 **测试文件**: - `deployment-readiness.spec.ts` - 部署就绪检查 - `quick-check.spec.ts` - 快速检查 ## Page Object Model ### 基础页面类 ```typescript // e2e/src/pages/BasePage.ts export class BasePage { readonly page: Page; constructor(page: Page) { this.page = page; } async navigate(path: string) { await this.page.goto(path); } async waitForPageLoad() { await this.page.waitForLoadState('networkidle'); } async takeScreenshot(name: string) { await this.page.screenshot({ path: `screenshots/${name}.png` }); } } ``` ### 首页 Page Object ```typescript // e2e/src/pages/HomePage.ts import { BasePage } from './BasePage'; export class HomePage extends BasePage { readonly heroSection: Locator; readonly servicesSection: Locator; readonly productsSection: Locator; constructor(page: Page) { super(page); this.heroSection = page.locator('[data-testid="hero-section"]'); this.servicesSection = page.locator('#services'); this.productsSection = page.locator('#products'); } async goto() { await this.navigate('/'); await this.waitForPageLoad(); } async scrollToSection(sectionId: string) { await this.page.locator(`#${sectionId}`).scrollIntoViewIfNeeded(); } } ``` ### 使用示例 ```typescript // e2e/src/tests/smoke/home-page.smoke.spec.ts import { test, expect } from '@playwright/test'; import { HomePage } from '../../pages/HomePage'; test.describe('首页冒烟测试', () => { let homePage: HomePage; test.beforeEach(async ({ page }) => { homePage = new HomePage(page); await homePage.goto(); }); test('首页加载成功', async () => { await expect(homePage.heroSection).toBeVisible(); }); }); ``` ## 测试配置 ### Playwright 配置 ```typescript // e2e/playwright.config.ts export default defineConfig({ testDir: './src/tests', fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 4 : '50%', reporter: [ ['html'], ['json', { outputFile: 'test-results/results.json' }], ['junit', { outputFile: 'test-results/junit.xml' }], ['allure-playwright'], ], timeout: 90000, use: { baseURL: 'http://localhost:3000', trace: 'on-first-retry', screenshot: 'only-on-failure', video: 'on-first-retry', headless: true, }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, { name: 'firefox', use: { ...devices['Desktop Firefox'] } }, { name: 'webkit', use: { ...devices['Desktop Safari'] } }, { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] } }, { name: 'Mobile Safari', use: { ...devices['iPhone 12'] } }, ], webServer: { command: 'cd .. && npm run dev', url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, }, }); ``` ### 环境配置 ```typescript // e2e/src/config/environments.ts export interface Environment { name: string; baseURL: string; retries: number; trace: 'on' | 'off' | 'on-first-retry'; screenshot: 'on' | 'off' | 'only-on-failure'; video: 'on' | 'off' | 'on-first-retry'; headless: boolean; slowMo: number; } export const environments: Record = { development: { name: 'development', baseURL: 'http://localhost:3000', retries: 0, trace: 'on-first-retry', screenshot: 'only-on-failure', video: 'on-first-retry', headless: true, slowMo: 0, }, production: { name: 'production', baseURL: 'https://www.novalon.cn', retries: 2, trace: 'on-first-retry', screenshot: 'only-on-failure', video: 'on-first-retry', headless: true, slowMo: 0, }, }; export function getEnvironment(): Environment { const env = process.env.TEST_ENV || 'development'; return environments[env]; } ``` ## 运行测试 ### 本地运行 ```bash # 进入测试目录 cd e2e # 安装依赖 npm install # 安装浏览器 npx playwright install # 运行所有测试 npm run test # 运行特定测试 npx playwright test path/to/test.spec.ts # 运行带标签的测试 npx playwright test --grep @smoke # UI 模式 npm run test:ui # 调试模式 npm run test:debug # 有头模式 npm run test:headed ``` ### CI 环境运行 ```bash # CI 模式(禁止 only、增加重试) CI=true npx playwright test ``` ## 测试报告 ### HTML 报告 ```bash npx playwright show-report ``` ### Allure 报告 ```bash # 生成报告 npm run test:allure # 打开报告 npm run test:allure:open # 实时服务 npm run test:allure:serve ``` ### JUnit 报告 用于 CI 集成,输出到 `test-results/junit.xml`。 ## 测试最佳实践 ### 1. 使用数据测试 ID ```tsx // 组件中
// 测试中 await page.locator('[data-testid="hero-section"]') ``` ### 2. 等待策略 ```typescript // 等待元素可见 await expect(locator).toBeVisible(); // 等待网络空闲 await page.waitForLoadState('networkidle'); // 等待特定响应 await page.waitForResponse('**/api/contact'); ``` ### 3. 避免硬编码等待 ```typescript // 不推荐 await page.waitForTimeout(1000); // 推荐 await expect(locator).toBeVisible(); ``` ### 4. 使用 Fixtures ```typescript // e2e/src/fixtures/base.fixture.ts import { test as base } from '@playwright/test'; import { HomePage } from '../pages/HomePage'; export const test = base.extend<{ homePage: HomePage; }>({ homePage: async ({ page }, use) => { const homePage = new HomePage(page); await use(homePage); }, }); ``` ### 5. 测试隔离 ```typescript test.describe('测试组', () => { test.beforeEach(async ({ page }) => { // 每个测试前的初始化 }); test.afterEach(async ({ page }) => { // 每个测试后的清理 }); }); ``` ## CI 集成 ### Woodpecker CI 配置 ```yaml # .woodpecker.yml pipeline: e2e-tests: image: node:18-alpine environment: NODE_ENV: test CI: true commands: - cd e2e - npm ci - npx playwright install --with-deps chromium - npm run test:ci when: event: - push - pull_request ``` ### 测试命令 ```json { "scripts": { "test": "playwright test", "test:smoke": "playwright test --grep @smoke", "test:regression": "playwright test --grep @regression", "test:performance": "playwright test --grep @performance", "test:responsive": "playwright test --grep @responsive", "test:visual": "playwright test --grep @visual", "test:accessibility": "playwright test --grep @accessibility", "test:security": "playwright test --grep @security", "test:ci": "playwright test --reporter=html,json,junit" } } ``` ## 调试技巧 ### 1. Trace Viewer ```bash # 运行测试并生成 trace npx playwright test --trace on # 查看 trace npx playwright show-trace trace.zip ``` ### 2. 截图和视频 ```typescript // 手动截图 await page.screenshot({ path: 'debug.png' }); // 元素截图 await locator.screenshot({ path: 'element.png' }); // 全页截图 await page.screenshot({ path: 'full.png', fullPage: true }); ``` ### 3. 控制台日志 ```typescript // 监听控制台 page.on('console', msg => console.log(msg.text())); // 监听页面错误 page.on('pageerror', error => console.error(error)); ``` ### 4. Playwright Inspector ```bash npx playwright test --debug ```