Files
everything-is-suitable/everything-is-suitable-test/README.md
T
张翔 08ea5fbe98 feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
2026-03-28 14:37:29 +08:00

546 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# E2E测试框架使用文档
## 目录
- [概述](#概述)
- [快速开始](#快速开始)
- [项目结构](#项目结构)
- [核心功能](#核心功能)
- [编写测试](#编写测试)
- [运行测试](#运行测试)
- [CI/CD集成](#cicd集成)
- [最佳实践](#最佳实践)
- [故障排查](#故障排查)
## 概述
本E2E测试框架基于Playwright构建,为uniapp和admin模块提供完整的端到端测试解决方案。框架采用模块化设计,支持前后端完全联通的测试场景,确保业务流程的完整性和正确性。
### 主要特性
- ✅ 基于Playwright的现代化E2E测试框架
- ✅ 支持uniapp和admin模块的全流程业务测试
- ✅ 完整的测试数据管理和清理机制
- ✅ 丰富的测试辅助工具(表单、表格、断言等)
- ✅ 详细的测试日志和截图功能
- ✅ 多种测试报告格式(HTML、JSON、JUnit
- ✅ 完整的CI/CD集成支持
- ✅ 支持多浏览器和多设备测试
## 快速开始
### 环境要求
- Node.js >= 18.0.0
- npm >= 9.0.0
- Docker(用于运行测试环境)
### 安装依赖
```bash
cd everything-is-suitable-test
npm install
```
### 安装Playwright浏览器
```bash
npm run test:install
```
### 配置环境变量
复制环境变量示例文件:
```bash
cp .env.example .env
```
编辑`.env`文件,配置测试环境:
```env
TEST_ENV=local
ADMIN_BASE_URL=http://localhost:5174
UNIAPP_BASE_URL=http://localhost:8081
API_BASE_URL=http://127.0.0.1:8080
TEST_USERNAME=admin
TEST_PASSWORD=admin123
MOCK_ENABLED=false
TEST_TIMEOUT=30000
```
### 运行测试
```bash
npm run test
```
## 项目结构
```
everything-is-suitable-test/
├── e2e/
│ ├── fixtures/ # 测试夹具
│ │ └── test-fixtures.ts # 自定义测试夹具
│ ├── core/ # 核心模块
│ │ ├── test-config.ts # 测试配置管理
│ │ ├── test-logger.ts # 测试日志记录
│ │ ├── test-reporter.ts # 测试报告生成
│ │ └── test-data-manager.ts # 测试数据管理
│ ├── helpers/ # 测试辅助工具
│ │ ├── api-helper.ts # API请求辅助
│ │ ├── form-helper.ts # 表单操作辅助
│ │ ├── table-helper.ts # 表格操作辅助
│ │ ├── screenshot-helper.ts # 截图辅助
│ │ └── assertion-helper.ts # 断言辅助
│ └── examples/ # 示例测试
│ ├── user-management.spec.ts
│ ├── api-integration.spec.ts
│ ├── uniapp-almanac.spec.ts
│ ├── uniapp-user.spec.ts
│ ├── admin-user-management.spec.ts
│ └── admin-role-management.spec.ts
├── playwright.config.ts # Playwright配置
├── package.json
├── tsconfig.json
└── .env.example
```
## 核心功能
### 测试夹具 (Fixtures)
框架提供了一组自定义测试夹具,可以在测试中直接使用:
```typescript
test('示例测试', async ({
page,
testConfig,
testLogger,
testDataManager,
apiHelper,
formHelper,
tableHelper,
screenshotHelper,
assertionHelper
}) => {
// 使用夹具进行测试
});
```
#### 可用夹具
| 夹具名称 | 描述 |
|---------|------|
| `testConfig` | 测试配置管理 |
| `testLogger` | 测试日志记录 |
| `testReporter` | 测试报告生成 |
| `testDataManager` | 测试数据管理 |
| `apiHelper` | API请求辅助 |
| `formHelper` | 表单操作辅助 |
| `tableHelper` | 表格操作辅助 |
| `screenshotHelper` | 截图辅助 |
| `assertionHelper` | 断言辅助 |
### 测试数据管理
`TestDataManager`提供完整的测试数据生命周期管理:
```typescript
const testUser = await testDataManager.createTestUser({
realName: '测试用户',
email: 'test@example.com'
});
// 测试完成后自动清理
```
### 测试辅助工具
#### APIHelper
```typescript
await apiHelper.login('admin', 'admin123');
const response = await apiHelper.get('/api/sys/user');
await apiHelper.post('/api/sys/user', userData);
await apiHelper.put('/api/sys/user', updateData);
await apiHelper.delete(`/api/sys/user/${userId}`);
```
#### FormHelper
```typescript
await formHelper.fillField('input[name="username"]', 'testuser');
await formHelper.fillForm({
'input[name="username"]': { value: 'testuser' },
'input[name="password"]': { value: 'password123' }
});
await formHelper.submitForm('button[type="submit"]');
```
#### TableHelper
```typescript
const rowCount = await tableHelper.getRowCount('.user-table');
const cellText = await tableHelper.getCellText('.user-table', 1, 2);
const matchingRows = await tableHelper.findRowsByCellText('.user-table', 'testuser');
await tableHelper.clickRow('.user-table', 1);
```
#### AssertionHelper
```typescript
await assertionHelper.assertElementVisible(page, '.user-table');
await assertionHelper.assertElementText(page, '.user-name', '张三');
await assertionHelper.assertSuccessMessage(page);
await assertionHelper.assertAPISuccess(response);
```
#### ScreenshotHelper
```typescript
await screenshotHelper.takeScreenshot('test-name');
await screenshotHelper.takeElementScreenshot('.element', 'element-name');
await screenshotHelper.takeScreenshotOnFailure('test-name');
await screenshotHelper.takeScreenshotOnSuccess('test-name');
```
## 编写测试
### 基本测试结构
```typescript
import { test, expect } from './fixtures/test-fixtures';
test.describe('功能模块测试', () => {
test.beforeEach(async ({ page, testConfig, testLogger }) => {
testLogger.startTest('功能模块测试');
await page.goto(testConfig.getEnvironment().baseURL);
});
test.afterEach(async ({ testLogger }) => {
testLogger.endTest('功能模块测试', 'passed');
});
test('TC-001: 测试用例名称', async ({
page,
formHelper,
assertionHelper,
testLogger,
screenshotHelper
}) => {
testLogger.startStep('步骤1: 描述步骤');
// 测试逻辑
testLogger.endStep('步骤1: 描述步骤', 'passed');
await screenshotHelper.takeScreenshotOnSuccess('test-name');
});
});
```
### 测试命名规范
- 测试套件:使用`test.describe()`组织相关测试
- 测试用例:使用`TC-模块-序号: 描述`格式
- 测试步骤:使用`步骤N: 描述`格式
### 测试最佳实践
1. **使用测试夹具**:充分利用框架提供的夹具,避免重复代码
2. **详细日志**:使用`testLogger`记录测试步骤,便于调试
3. **截图记录**:在关键步骤和测试结束时截图
4. **数据清理**:使用`testDataManager`管理测试数据,自动清理
5. **断言明确**:使用`assertionHelper`进行清晰的断言
6. **等待稳定**:使用`waitFor`等待元素状态稳定
## 运行测试
### 本地运行
```bash
# 运行所有测试
npm run test
# 运行特定测试文件
npx playwright test e2e/examples/user-management.spec.ts
# 运行特定测试用例
npx playwright test -g "TC-USER-001"
# 有头模式运行
npm run test:headed
# 调试模式
npm run test:debug
# UI模式
npm run test:ui
```
### Docker环境运行
```bash
# 启动测试环境
docker-compose -f docker-compose.test.yml up -d
# 等待服务启动
sleep 30
# 运行测试
npm run test
# 停止环境
docker-compose -f docker-compose.test.yml down
```
### 查看测试报告
```bash
# HTML报告
npm run test:report
# JSON报告
cat test-results/results.json
# JUnit报告
cat test-results/junit.xml
```
## CI/CD集成
### Woodpecker CI
测试框架已集成Woodpecker CI,配置文件位于项目根目录的`.woodpecker.yml`
**触发条件**
- 推送到main或develop分支
- 创建Pull Request
- 每天凌晨2点定时执行
**测试流程**
1. 启动Docker测试环境
2. 并行运行E2E测试(4个分片)
3. 执行API集成测试
4. 生成HTML测试报告
5. 测试失败时发送Slack通知
**Pipeline结构**
- `setup`: 初始化Docker环境
- `e2e-tests`: 执行端到端测试(并行4个分片)
- `api-tests`: 执行API集成测试
- `test-report`: 合并测试报告
- `notify-failure`: 测试失败时发送通知
- `nightly-tests`: 每日定时执行完整测试
详细配置说明请参考:[WOODPECKER_CI.md](../WOODPECKER_CI.md)
### 测试报告
测试完成后会生成以下报告:
1. **HTML报告**:交互式HTML报告,包含测试详情和截图
2. **JSON报告**:机器可读的JSON格式报告
3. **JUnit报告**:兼容JUnit的XML格式报告
报告位置:
- `playwright-report/`HTML报告
- `test-results/results.json`JSON报告
- `test-results/junit.xml`JUnit报告
## 最佳实践
### 1. 测试设计原则
- **测试金字塔**:70% API测试,20% 集成测试,10% E2E测试
- **独立性**:每个测试用例应该独立运行,不依赖其他测试
- **可重复性**:测试结果应该稳定可重复
- **快速反馈**:优先测试核心业务流程
### 2. 数据管理
- 使用`TestDataManager`创建和管理测试数据
- 测试完成后自动清理测试数据
- 避免硬编码测试数据,使用工厂模式生成
### 3. 错误处理
- 使用`try-catch`捕获预期异常
- 提供清晰的错误信息
- 失败时自动截图和记录日志
### 4. 性能优化
- 合理使用并行执行
- 避免不必要的等待
- 复用浏览器实例
### 5. 维护性
- 遵循代码规范
- 添加必要的注释
- 定期重构测试代码
- 更新测试文档
## 故障排查
### 常见问题
#### 1. 测试超时
**问题**:测试执行超时
**解决方案**
```typescript
// 增加超时时间
test.setTimeout(60000);
// 或在配置中设置
use: {
actionTimeout: 60000,
navigationTimeout: 60000
}
```
#### 2. 元素未找到
**问题**:无法定位页面元素
**解决方案**
```typescript
// 等待元素可见
await page.waitForSelector('.element', { timeout: 10000 });
// 使用更精确的选择器
await page.locator('.container .element').click();
```
#### 3. 测试数据冲突
**问题**:测试数据相互干扰
**解决方案**
```typescript
// 使用唯一标识符
const timestamp = Date.now();
const username = `test_user_${timestamp}`;
// 每个测试使用独立数据
beforeEach(async () => {
testUser = await testDataManager.createTestUser();
});
afterEach(async () => {
await testDataManager.cleanup();
});
```
#### 4. 环境配置问题
**问题**:无法连接到测试环境
**解决方案**
```bash
# 检查环境变量
cat .env
# 验证服务状态
docker-compose ps
# 查看服务日志
docker-compose logs backend
```
### 调试技巧
#### 1. 使用调试模式
```bash
npm run test:debug
```
#### 2. 使用UI模式
```bash
npm run test:ui
```
#### 3. 查看详细日志
```typescript
testLogger.debug('调试信息');
testLogger.info('一般信息');
testLogger.warn('警告信息');
testLogger.error('错误信息', error);
```
#### 4. 截图和录屏
```typescript
// 失败时自动截图
await screenshotHelper.takeScreenshotOnFailure('test-name');
// 手动截图
await screenshotHelper.takeScreenshot('debug-point');
// 录屏(在playwright.config.ts中配置)
use: {
video: 'retain-on-failure'
}
```
### 性能优化
#### 1. 减少测试时间
```typescript
// 并行执行测试
workers: 4
// 跳过慢速测试
test.skip('慢速测试', async () => {});
// 使用项目分组
projects: [
{ name: 'fast', testMatch: '**/*.fast.spec.ts' },
{ name: 'slow', testMatch: '**/*.slow.spec.ts' }
]
```
#### 2. 优化等待时间
```typescript
// 使用智能等待
await page.waitForSelector('.element', { state: 'visible' });
// 避免固定等待
// 不推荐:await page.waitForTimeout(5000);
// 推荐:await page.waitForLoadState('networkidle');
```
## 贡献指南
### 添加新测试
1.`e2e/examples/`目录下创建新的测试文件
2. 遵循测试命名规范
3. 使用测试夹具和辅助工具
4. 添加详细的测试步骤和日志
5. 提交前运行测试确保通过
### 扩展框架
1.`e2e/helpers/`目录下添加新的辅助工具
2.`e2e/fixtures/test-fixtures.ts`中注册新的夹具
3. 更新文档说明新功能
4. 添加示例测试
## 许可证
MIT License
## 联系方式
如有问题或建议,请联系测试团队。