08ea5fbe98
添加用户管理视图、API和状态管理文件
461 lines
10 KiB
Markdown
461 lines
10 KiB
Markdown
# Uniapp E2E测试使用指南
|
||
|
||
## 概述
|
||
|
||
本E2E测试工具为everything-is-suitable-uniapp小程序提供全面的端到端测试解决方案,基于Playwright构建,支持多浏览器、多平台测试,并提供详细的测试报告。
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
e2e/uniapp/
|
||
├── pages/ # 页面对象模型
|
||
│ ├── base-page.ts # 基础页面类
|
||
│ ├── calendar-page.ts # 万年历页面
|
||
│ ├── almanac-page.ts # 黄历页面
|
||
│ ├── user-page.ts # 用户中心页面
|
||
│ └── bottom-navigation.ts # 底部导航栏
|
||
├── navigation.spec.ts # 页面导航测试
|
||
├── calendar.spec.ts # 万年历页面测试
|
||
├── almanac.spec.ts # 黄历页面测试
|
||
├── user.spec.ts # 用户中心页面测试
|
||
├── data-loading.spec.ts # 数据加载测试
|
||
├── state-update.spec.ts # 状态更新测试
|
||
├── boundary.spec.ts # 边界条件测试
|
||
├── test-reporter.ts # 测试报告生成器
|
||
├── global-setup.ts # 全局测试设置
|
||
└── global-teardown.ts # 全局测试清理
|
||
```
|
||
|
||
## 快速开始
|
||
|
||
### 1. 安装依赖
|
||
|
||
```bash
|
||
cd everything-is-suitable-test
|
||
npm install
|
||
```
|
||
|
||
### 2. 启动Uniapp应用
|
||
|
||
在另一个终端中启动Uniapp应用:
|
||
|
||
```bash
|
||
cd ../everything-is-suitable-uniapp
|
||
npm run dev:h5
|
||
```
|
||
|
||
### 3. 运行测试
|
||
|
||
```bash
|
||
# 运行所有Uniapp E2E测试
|
||
npm run test:e2e:uniapp
|
||
|
||
# 运行特定测试文件
|
||
npx playwright test --config=playwright.uniapp.config.ts e2e/uniapp/navigation.spec.ts
|
||
|
||
# 运行特定测试用例
|
||
npx playwright test --config=playwright.uniapp.config.ts -g "底部导航栏切换测试"
|
||
|
||
# 调试模式运行
|
||
npm run test:e2e:uniapp:debug
|
||
|
||
# UI模式运行
|
||
npm run test:e2e:uniapp:ui
|
||
|
||
# 有头模式运行(显示浏览器)
|
||
npm run test:e2e:uniapp:headed
|
||
```
|
||
|
||
### 4. 查看测试报告
|
||
|
||
```bash
|
||
# 查看Playwright HTML报告
|
||
npm run test:e2e:uniapp:report
|
||
```
|
||
|
||
## 测试用例
|
||
|
||
### 页面导航测试 (navigation.spec.ts)
|
||
|
||
- **TC-001**: 底部导航栏切换测试
|
||
- **TC-002**: 页面标题显示测试
|
||
|
||
### 万年历页面测试 (calendar.spec.ts)
|
||
|
||
- **TC-003**: 日历月份切换测试
|
||
- **TC-004**: 日期选择测试
|
||
- **TC-005**: 农历信息显示测试
|
||
|
||
### 黄历页面测试 (almanac.spec.ts)
|
||
|
||
- **TC-006**: 黄历日期切换测试
|
||
- **TC-007**: 黄历信息显示测试
|
||
|
||
### 用户中心页面测试 (user.spec.ts)
|
||
|
||
- **TC-008**: 用户信息显示测试
|
||
- **TC-009**: 菜单导航测试
|
||
|
||
### 数据加载测试 (data-loading.spec.ts)
|
||
|
||
- **TC-012**: 黄历数据加载测试
|
||
- **TC-013**: 日历数据加载测试
|
||
|
||
### 状态更新测试 (state-update.spec.ts)
|
||
|
||
- **TC-014**: 选中日期状态更新测试
|
||
- **TC-015**: 导航栏状态更新测试
|
||
|
||
### 边界条件测试 (boundary.spec.ts)
|
||
|
||
- **TC-016**: 月份边界测试
|
||
- **TC-017**: 日期边界测试
|
||
- **TC-018**: 表单验证测试
|
||
|
||
## 页面对象模型
|
||
|
||
### BasePage
|
||
|
||
所有页面对象的基类,提供通用的页面操作方法:
|
||
|
||
```typescript
|
||
import { BasePage } from './pages/base-page';
|
||
|
||
const page = new BasePage(page);
|
||
await page.navigate('/pages/calendar/index');
|
||
await page.waitForLoad();
|
||
await page.clickElement('.button');
|
||
await page.fillInput('.input', 'value');
|
||
```
|
||
|
||
### CalendarPage
|
||
|
||
万年历页面对象:
|
||
|
||
```typescript
|
||
import { CalendarPage } from './pages/calendar-page';
|
||
|
||
const calendarPage = new CalendarPage(page);
|
||
await calendarPage.navigate();
|
||
await calendarPage.clickNextMonth();
|
||
await calendarPage.clickDay(15);
|
||
const lunarDate = await calendarPage.getLunarDate();
|
||
```
|
||
|
||
### AlmanacPage
|
||
|
||
黄历页面对象:
|
||
|
||
```typescript
|
||
import { AlmanacPage } from './pages/almanac-page';
|
||
|
||
const almanacPage = new AlmanacPage(page);
|
||
await almanacPage.navigate();
|
||
await almanacPage.clickNextDate();
|
||
const almanacInfo = await almanacPage.getAllAlmanacInfo();
|
||
```
|
||
|
||
### UserPage
|
||
|
||
用户中心页面对象:
|
||
|
||
```typescript
|
||
import { UserPage } from './pages/user-page';
|
||
|
||
const userPage = new UserPage(page);
|
||
await userPage.navigate();
|
||
const userName = await userPage.getUserName();
|
||
await userPage.clickMenuItem(0);
|
||
```
|
||
|
||
### BottomNavigation
|
||
|
||
底部导航栏对象:
|
||
|
||
```typescript
|
||
import { BottomNavigation } from './pages/bottom-navigation';
|
||
|
||
const bottomNavigation = new BottomNavigation(page);
|
||
await bottomNavigation.clickTab('almanac');
|
||
const isActive = await bottomNavigation.isTabActive('almanac');
|
||
```
|
||
|
||
## 测试报告
|
||
|
||
### Playwright报告
|
||
|
||
Playwright自动生成HTML报告,包含:
|
||
- 测试执行摘要
|
||
- 每个测试的详细信息
|
||
- 失败测试的截图和视频
|
||
- 性能指标
|
||
|
||
### 自定义报告
|
||
|
||
使用`test-reporter.ts`生成自定义报告:
|
||
|
||
```typescript
|
||
import { UniappTestReporter } from './test-reporter';
|
||
|
||
const reporter = new UniappTestReporter();
|
||
reporter.addTestSuite('测试套件名称', [
|
||
{
|
||
testName: '测试用例名称',
|
||
status: 'passed',
|
||
duration: 1000,
|
||
}
|
||
]);
|
||
|
||
await reporter.generateJSONReport('test-results/uniapp-report.json');
|
||
await reporter.generateHTMLReport('test-results/uniapp-report.html');
|
||
await reporter.generateMarkdownReport('test-results/uniapp-report.md');
|
||
```
|
||
|
||
## 配置
|
||
|
||
### Playwright配置
|
||
|
||
配置文件:`playwright.uniapp.config.ts`
|
||
|
||
主要配置项:
|
||
- `testDir`: 测试文件目录
|
||
- `baseURL`: 应用基础URL
|
||
- `projects`: 浏览器项目配置
|
||
- `webServer`: 开发服务器配置
|
||
|
||
### 环境变量
|
||
|
||
- `BASE_URL`: 应用基础URL
|
||
- `CI`: 是否在CI环境中运行
|
||
- `NODE_ENV`: Node环境
|
||
|
||
## 最佳实践
|
||
|
||
### 1. 测试用例编写
|
||
|
||
- 使用描述性的测试名称
|
||
- 遵循AAA模式(Arrange-Act-Assert)
|
||
- 使用页面对象而不是直接操作元素
|
||
- 添加适当的等待和断言
|
||
|
||
```typescript
|
||
test('应该能够切换到黄历页面', async ({ page }) => {
|
||
await calendarPage.navigate();
|
||
await bottomNavigation.clickTab('almanac');
|
||
|
||
const title = await page.title();
|
||
expect(title).toContain('黄历');
|
||
});
|
||
```
|
||
|
||
### 2. 页面对象使用
|
||
|
||
- 将选择器封装在页面对象中
|
||
- 实现业务逻辑方法
|
||
- 保持页面对象的独立性
|
||
|
||
```typescript
|
||
export class CalendarPage extends BasePage {
|
||
private readonly selectors = {
|
||
prevMonthButton: '[data-testid="prev-month"]',
|
||
nextMonthButton: '[data-testid="next-month"]',
|
||
};
|
||
|
||
async clickNextMonth() {
|
||
await this.clickElement(this.selectors.nextMonthButton);
|
||
await this.waitForLoad();
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 测试数据管理
|
||
|
||
- 使用测试数据生成器
|
||
- 避免硬编码测试数据
|
||
- 使用测试夹具提供的预定义数据
|
||
|
||
### 4. 错误处理
|
||
|
||
- 在测试用例中使用try-catch捕获错误
|
||
- 使用测试日志记录错误信息
|
||
- 在测试失败时截图
|
||
|
||
```typescript
|
||
test('测试用例', async ({ page }) => {
|
||
try {
|
||
await page.goto('/pages/calendar/index');
|
||
expect(await page.title()).toContain('万年历');
|
||
} catch (error) {
|
||
await page.screenshot({ path: 'test-failure.png' });
|
||
throw error;
|
||
}
|
||
});
|
||
```
|
||
|
||
### 5. 等待策略
|
||
|
||
- 使用页面对象提供的等待方法
|
||
- 避免使用固定的等待时间
|
||
- 使用Playwright的自动等待机制
|
||
|
||
```typescript
|
||
await page.waitForLoadState('networkidle');
|
||
await page.waitForSelector('.element', { state: 'visible' });
|
||
```
|
||
|
||
## 故障排查
|
||
|
||
### 测试失败时的调试
|
||
|
||
1. 查看测试日志:控制台输出
|
||
2. 查看截图:`test-results/uniapp-artifacts/`
|
||
3. 查看测试报告:`npm run test:e2e:uniapp:report`
|
||
4. 使用调试模式运行:`npm run test:e2e:uniapp:debug`
|
||
|
||
### 常见问题
|
||
|
||
1. **元素未找到**
|
||
- 检查选择器是否正确
|
||
- 确保元素已加载
|
||
- 使用适当的等待策略
|
||
|
||
2. **测试超时**
|
||
- 增加超时配置
|
||
- 检查网络请求是否正常
|
||
- 优化测试等待策略
|
||
|
||
3. **应用未启动**
|
||
- 确保Uniapp应用已启动
|
||
- 检查端口是否正确
|
||
- 查看应用日志
|
||
|
||
## CI/CD集成
|
||
|
||
### GitHub Actions示例
|
||
|
||
```yaml
|
||
name: Uniapp E2E Tests
|
||
|
||
on:
|
||
push:
|
||
branches: [ main, develop ]
|
||
pull_request:
|
||
branches: [ main, develop ]
|
||
|
||
jobs:
|
||
test:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v3
|
||
- uses: actions/setup-node@v3
|
||
with:
|
||
node-version: '18'
|
||
- run: npm ci
|
||
- run: npm run test:e2e:uniapp
|
||
- uses: actions/upload-artifact@v3
|
||
if: failure()
|
||
with:
|
||
name: test-results
|
||
path: test-results/
|
||
```
|
||
|
||
## 扩展开发
|
||
|
||
### 添加新的页面对象
|
||
|
||
1. 在`pages/`目录下创建新的页面类
|
||
2. 继承`BasePage`类
|
||
3. 实现页面特定的方法和选择器
|
||
|
||
```typescript
|
||
import { BasePage } from './base-page';
|
||
|
||
export class NewPage extends BasePage {
|
||
private readonly selectors = {
|
||
// 页面选择器
|
||
};
|
||
|
||
async navigate() {
|
||
await this.navigate('/pages/new/index');
|
||
}
|
||
|
||
async doSomething() {
|
||
// 页面方法
|
||
}
|
||
}
|
||
```
|
||
|
||
### 添加新的测试用例
|
||
|
||
1. 在`e2e/uniapp/`目录下创建新的测试文件
|
||
2. 使用`test.describe`组织测试用例
|
||
3. 使用页面对象进行测试
|
||
|
||
```typescript
|
||
import { test, expect } from '@playwright/test';
|
||
import { NewPage } from './pages/new-page';
|
||
|
||
test.describe('新功能测试', () => {
|
||
test('应该能够执行新功能', async ({ page }) => {
|
||
const newPage = new NewPage(page);
|
||
await newPage.navigate();
|
||
await newPage.doSomething();
|
||
|
||
expect(await page.title()).toContain('新页面');
|
||
});
|
||
});
|
||
```
|
||
|
||
## 性能优化
|
||
|
||
### 并行执行
|
||
|
||
Playwright默认支持并行执行测试,可以通过配置文件调整:
|
||
|
||
```typescript
|
||
export default defineConfig({
|
||
workers: 4,
|
||
fullyParallel: true,
|
||
});
|
||
```
|
||
|
||
### 测试隔离
|
||
|
||
确保每个测试用例都是独立的,避免测试之间的依赖:
|
||
|
||
```typescript
|
||
test.beforeEach(async ({ page }) => {
|
||
await page.goto('/');
|
||
});
|
||
|
||
test.afterEach(async ({ page }) => {
|
||
await page.close();
|
||
});
|
||
```
|
||
|
||
### 重试机制
|
||
|
||
配置测试失败时的重试次数:
|
||
|
||
```typescript
|
||
export default defineConfig({
|
||
retries: 2,
|
||
});
|
||
```
|
||
|
||
## 总结
|
||
|
||
本E2E测试工具提供了完整的Uniapp应用端到端测试解决方案,包括:
|
||
|
||
- ✅ 模块化的测试用例编写
|
||
- ✅ 统一的测试环境配置
|
||
- ✅ 常用测试操作的封装与复用
|
||
- ✅ 清晰的测试报告与日志输出
|
||
- ✅ 页面对象模型(POM)
|
||
- ✅ 多浏览器支持
|
||
- ✅ 跨平台兼容性测试
|
||
- ✅ 自动化测试执行流程
|
||
- ✅ 详细的测试报告生成
|
||
|
||
通过使用本工具,可以高效地编写、执行和维护E2E测试,确保应用的质量和稳定性。
|