diff --git a/e2e/.env.example b/e2e/.env.example index 2baf499..0c13dd2 100644 --- a/e2e/.env.example +++ b/e2e/.env.example @@ -1,2 +1,29 @@ -BASE_URL=http://localhost:3000 +# 测试环境配置 +# 可选值: development, staging, production +TEST_ENV=development + +# 基础URL(可选,会覆盖环境配置) +# BASE_URL=http://localhost:3001 + +# API URL(可选,会覆盖环境配置) +# API_URL=http://localhost:3001/api + +# 浏览器配置 +HEADLESS=true +SLOW_MO=0 + +# 测试配置 +TIMEOUT=120000 +RETRIES=0 + +# 截图和视频配置 +SCREENSHOT=only-on-failure +VIDEO=retain-on-failure +TRACE=retain-on-failure + +# CI配置 CI=false + +# 调试配置 +DEBUG=false +PWDEBUG=false diff --git a/e2e/ENVIRONMENT.md b/e2e/ENVIRONMENT.md new file mode 100644 index 0000000..3c43dda --- /dev/null +++ b/e2e/ENVIRONMENT.md @@ -0,0 +1,184 @@ +# E2E测试环境配置指南 + +## 环境说明 + +本项目支持三个测试环境: + +- **development**: 本地开发环境 (http://localhost:3001) +- **staging**: 预发布环境 +- **production**: 生产环境 + +## 快速开始 + +### 1. 配置环境变量 + +复制环境变量示例文件: + +```bash +cp e2e/.env.example e2e/.env +``` + +### 2. 运行测试 + +#### 开发环境测试 + +```bash +# 默认使用development环境 +npm run test:e2e + +# 或者显式指定 +TEST_ENV=development npm run test:e2e +``` + +#### 预发布环境测试 + +```bash +TEST_ENV=staging npm run test:e2e +``` + +#### 生产环境测试 + +```bash +TEST_ENV=production npm run test:e2e +``` + +## 环境配置详解 + +### Development环境 + +- **baseURL**: http://localhost:3001 +- **headless**: false (显示浏览器窗口) +- **slowMo**: 100ms (减慢操作速度,便于调试) +- **retries**: 0 (不重试) +- **webServer**: 自动启动开发服务器 + +### Staging环境 + +- **baseURL**: https://staging.novalon.com +- **headless**: true (无头模式) +- **slowMo**: 0 (正常速度) +- **retries**: 1 (失败重试1次) +- **webServer**: 不启动 + +### Production环境 + +- **baseURL**: https://novalon.com +- **headless**: true (无头模式) +- **slowMo**: 0 (正常速度) +- **retries**: 2 (失败重试2次) +- **webServer**: 不启动 + +## 环境变量 + +| 变量名 | 说明 | 默认值 | +|--------|------|--------| +| TEST_ENV | 测试环境 | development | +| BASE_URL | 基础URL | 根据环境配置 | +| API_URL | API URL | 根据环境配置 | +| HEADLESS | 无头模式 | true | +| SLOW_MO | 减慢操作(ms) | 0 | +| TIMEOUT | 超时时间(ms) | 120000 | +| RETRIES | 重试次数 | 0 | +| SCREENSHOT | 截图策略 | only-on-failure | +| VIDEO | 视频策略 | retain-on-failure | +| TRACE | 追踪策略 | retain-on-failure | +| CI | CI环境 | false | +| DEBUG | 调试模式 | false | +| PWDEBUG | Playwright调试 | false | + +## CI/CD集成 + +### Woodpecker CI配置示例 + +```yaml +pipeline: + test-smoke: + image: mcr.microsoft.com/playwright:v1.48.0-focal + commands: + - cd e2e + - npm ci + - TEST_ENV=staging npx playwright test --project=chromium --grep=@smoke + when: + event: [push, pull_request] + + test-regression: + image: mcr.microsoft.com/playwright:v1.48.0-focal + commands: + - cd e2e + - npm ci + - TEST_ENV=staging npx playwright test --project=chromium --grep=@regression + when: + event: [push, pull_request] + + test-full: + image: mcr.microsoft.com/playwright:v1.48.0-focal + commands: + - cd e2e + - npm ci + - TEST_ENV=production npx playwright test + when: + event: [deployment] +``` + +## 最佳实践 + +### 1. 本地开发 + +使用development环境,可以看到浏览器操作过程,便于调试: + +```bash +TEST_ENV=development npm run test:e2e +``` + +### 2. 代码提交 + +在staging环境运行smoke和regression测试: + +```bash +TEST_ENV=staging npm run test:e2e -- --grep="@smoke|@regression" +``` + +### 3. 生产部署 + +在production环境运行完整测试套件: + +```bash +TEST_ENV=production npm run test:e2e +``` + +### 4. 调试测试 + +启用Playwright调试模式: + +```bash +PWDEBUG=1 TEST_ENV=development npm run test:e2e -- --grep="test name" +``` + +## 故障排查 + +### 问题1: 环境变量不生效 + +确保在项目根目录运行命令,或者在e2e目录下运行。 + +### 问题2: 开发服务器启动失败 + +检查端口3001是否被占用,或者修改配置中的端口。 + +### 问题3: 测试超时 + +增加TIMEOUT环境变量值: + +```bash +TIMEOUT=180000 npm run test:e2e +``` + +### 问题4: 网络问题 + +检查网络连接,确保可以访问目标环境URL。 + +## 相关文档 + +- [测试数据管理](./test-data-management.md) +- [性能测试指南](./performance-testing.md) +- [安全测试指南](./security-testing.md) +- [可访问性测试指南](./accessibility-testing.md) diff --git a/e2e/playwright.config.ts b/e2e/playwright.config.ts index c1269ab..1d6abbe 100644 --- a/e2e/playwright.config.ts +++ b/e2e/playwright.config.ts @@ -1,10 +1,13 @@ import { defineConfig, devices } from '@playwright/test'; +import { getEnvironment } from './src/config/environments'; + +const env = getEnvironment(); export default defineConfig({ testDir: './src/tests', fullyParallel: true, forbidOnly: !!process.env.CI, - retries: process.env.CI ? 2 : 0, + retries: env.retries, workers: process.env.CI ? 1 : undefined, reporter: [ ['html', { open: 'never' }], @@ -13,19 +16,22 @@ export default defineConfig({ ['line'], ['list'] ], - timeout: 120000, + timeout: env.timeout, expect: { timeout: 30000 }, use: { - baseURL: 'http://localhost:3001', - trace: 'retain-on-failure', - screenshot: 'only-on-failure', - video: 'retain-on-failure', - headless: true, + baseURL: env.baseURL, + trace: env.trace, + screenshot: env.screenshot, + video: env.video, + headless: env.headless, viewport: { width: 1280, height: 720 }, actionTimeout: 30000, - navigationTimeout: 60000 + navigationTimeout: 60000, + launchOptions: { + slowMo: env.slowMo, + }, }, projects: [ { @@ -49,5 +55,10 @@ export default defineConfig({ use: { ...devices['iPhone 12'] }, }, ], - webServer: undefined, + webServer: env.name === 'development' ? { + command: 'npm run dev', + url: 'http://localhost:3001', + timeout: 120000, + reuseExistingServer: !process.env.CI, + } : undefined, }); diff --git a/e2e/src/config/environments.ts b/e2e/src/config/environments.ts new file mode 100644 index 0000000..0490782 --- /dev/null +++ b/e2e/src/config/environments.ts @@ -0,0 +1,82 @@ +export interface EnvironmentConfig { + name: string; + baseURL: string; + apiURL: string; + timeout: number; + retries: number; + headless: boolean; + slowMo: number; + screenshot: 'on' | 'off' | 'only-on-failure'; + video: 'on' | 'off' | 'retain-on-failure'; + trace: 'on' | 'off' | 'retain-on-failure'; +} + +export const environments: Record = { + development: { + name: 'development', + baseURL: 'http://localhost:3001', + apiURL: 'http://localhost:3001/api', + timeout: 120000, + retries: 0, + headless: false, + slowMo: 100, + screenshot: 'only-on-failure', + video: 'retain-on-failure', + trace: 'retain-on-failure', + }, + staging: { + name: 'staging', + baseURL: 'https://staging.novalon.com', + apiURL: 'https://staging.novalon.com/api', + timeout: 120000, + retries: 1, + headless: true, + slowMo: 0, + screenshot: 'only-on-failure', + video: 'retain-on-failure', + trace: 'retain-on-failure', + }, + production: { + name: 'production', + baseURL: 'https://novalon.com', + apiURL: 'https://novalon.com/api', + timeout: 120000, + retries: 2, + headless: true, + slowMo: 0, + screenshot: 'only-on-failure', + video: 'retain-on-failure', + trace: 'retain-on-failure', + }, +}; + +export function getEnvironment(): EnvironmentConfig { + const envName = process.env.TEST_ENV || 'development'; + const env = environments[envName]; + + if (!env) { + throw new Error(`Unknown environment: ${envName}. Valid environments: ${Object.keys(environments).join(', ')}`); + } + + return env; +} + +export function getBaseURL(): string { + return getEnvironment().baseURL; +} + +export function getApiURL(): string { + return getEnvironment().apiURL; +} + +export function isDevelopment(): boolean { + return getEnvironment().name === 'development'; +} + +export function isStaging(): boolean { + return getEnvironment().name === 'staging'; +} + +export function isProduction(): boolean { + return getEnvironment().name === 'production'; +}