- 创建完整Playwright测试方案文档(docs/specs/) - 创建Playwright配置文件(tests/playwright.config.ts) - 创建测试数据工具类(tests/e2e/utils/test-data.ts) - 建立测试目录结构:fixtures/pages/specs/utils - 支持CI/CD集成,测试失败阻断发布 - 覆盖登录、门诊医生站、手术计费、Bug回归测试 关联任务: UI功能性测试方案落地
215 lines
6.8 KiB
Markdown
215 lines
6.8 KiB
Markdown
# HIS项目 Playwright E2E 自动化测试方案 v1.0
|
||
|
||
## 一、方案概述
|
||
|
||
### 1.1 选型理由
|
||
- **Playwright** 是微软开源的端到端测试框架,完美适配 Vue 3 + Vite 技术栈
|
||
- 自动等待机制适合HIS系统复杂交互场景(异步加载、动态渲染)
|
||
- 支持多浏览器(Chromium/Firefox/WebKit),CI/CD集成成熟
|
||
- 已有 `@playwright/test ^1.58.2` 依赖 installed
|
||
|
||
### 1.2 目标
|
||
1. 核心业务流程自动化覆盖率达到 80%+
|
||
2. 已修复Bug 100% 回归测试覆盖
|
||
3. 每次代码推送自动触发测试,失败阻断发布
|
||
|
||
## 二、项目结构
|
||
|
||
```
|
||
openhis-ui-vue3/
|
||
├── tests/
|
||
│ ├── e2e/
|
||
│ │ ├── fixtures/ # 测试夹具
|
||
│ │ │ └── auth.ts # 登录认证fixture
|
||
│ │ ├── pages/ # 页面对象模型(POM)
|
||
│ │ │ ├── LoginPage.ts
|
||
│ │ │ ├── DoctorStationPage.ts
|
||
│ │ │ └── SurgeryBillingPage.ts
|
||
│ │ ├── specs/ # 测试用例
|
||
│ │ │ ├── login.spec.ts
|
||
│ │ │ ├── doctor-station.spec.ts
|
||
│ │ │ ├── surgery-billing.spec.ts
|
||
│ │ │ └── bug-regression.spec.ts # Bug回归测试
|
||
│ │ └── utils/
|
||
│ │ └── test-data.ts # 测试数据
|
||
│ └── playwright.config.ts # Playwright配置
|
||
├── .env.test # 测试环境变量
|
||
└── package.json # 已有playwright依赖
|
||
```
|
||
|
||
## 三、环境配置
|
||
|
||
### 3.1 环境变量(.env.test)
|
||
```bash
|
||
# 测试环境配置
|
||
VITE_APP_BASE_API=http://192.168.110.253:8080
|
||
TEST_USERNAME=test_admin
|
||
TEST_PASSWORD=test123456
|
||
TEST_BASE_URL=http://localhost:80
|
||
```
|
||
|
||
### 3.2 Playwright配置(playwright.config.ts)
|
||
```typescript
|
||
import { defineConfig, devices } from '@playwright/test';
|
||
|
||
export default defineConfig({
|
||
testDir: './tests/e2e/specs',
|
||
timeout: 60 * 1000,
|
||
expect: { timeout: 10000 },
|
||
fullyParallel: false,
|
||
forbidOnly: !!process.env.CI,
|
||
retries: process.env.CI ? 2 : 0,
|
||
workers: 1,
|
||
reporter: [['html', { outputFolder: 'playwright-report' }], ['list']],
|
||
use: {
|
||
baseURL: process.env.TEST_BASE_URL || 'http://localhost:80',
|
||
trace: 'on-first-retry',
|
||
screenshot: 'only-on-failure',
|
||
video: 'retain-on-failure',
|
||
},
|
||
projects: [
|
||
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
|
||
],
|
||
});
|
||
```
|
||
|
||
## 四、核心测试用例
|
||
|
||
### 4.1 登录测试(login.spec.ts)
|
||
```typescript
|
||
import { test, expect } from '@playwright/test';
|
||
|
||
test('用户登录成功', async ({ page }) => {
|
||
await page.goto('/');
|
||
await page.fill('input[placeholder="请输入用户名"]', process.env.TEST_USERNAME || 'admin');
|
||
await page.fill('input[placeholder="请输入密码"]', process.env.TEST_PASSWORD || '123456');
|
||
await page.click('button:has-text("登录")');
|
||
await expect(page).toHaveURL(/.*dashboard.*/);
|
||
await expect(page.locator('.user-avatar')).toBeVisible();
|
||
});
|
||
|
||
test('登录失败-错误密码', async ({ page }) => {
|
||
await page.goto('/');
|
||
await page.fill('input[placeholder="请输入用户名"]', 'admin');
|
||
await page.fill('input[placeholder="请输入密码"]', 'wrongpassword');
|
||
await page.click('button:has-text("登录")');
|
||
await expect(page.locator('.el-message--error')).toBeVisible();
|
||
});
|
||
```
|
||
|
||
### 4.2 门诊医生站测试(doctor-station.spec.ts)
|
||
```typescript
|
||
import { test, expect } from '@playwright/test';
|
||
|
||
test.describe('门诊医生站', () => {
|
||
test.beforeEach(async ({ page }) => {
|
||
// 登录
|
||
await page.goto('/');
|
||
await page.fill('input[placeholder="请输入用户名"]', process.env.TEST_USERNAME || 'admin');
|
||
await page.fill('input[placeholder="请输入密码"]', process.env.TEST_PASSWORD || '123456');
|
||
await page.click('button:has-text("登录")');
|
||
await page.waitForURL(/.*dashboard.*/);
|
||
});
|
||
|
||
test('#427 检查项目分类手风琴展开', async ({ page }) => {
|
||
await page.goto('/doctorstation');
|
||
// 点击第一个分类
|
||
await page.click('.category-item >> nth=0');
|
||
await expect(page.locator('.category-content >> nth=0')).toBeVisible();
|
||
// 点击第二个分类,第一个应收起
|
||
await page.click('.category-item >> nth=1');
|
||
await expect(page.locator('.category-content >> nth=0')).not.toBeVisible();
|
||
await expect(page.locator('.category-content >> nth=1')).toBeVisible();
|
||
});
|
||
});
|
||
```
|
||
|
||
### 4.3 手术计费回归测试(bug-regression.spec.ts)
|
||
```typescript
|
||
import { test, expect } from '@playwright/test';
|
||
|
||
test.describe('Bug回归测试', () => {
|
||
test('#437 手术计费防重复提交', async ({ page }) => {
|
||
// 登录并导航到手术计费
|
||
await page.goto('/');
|
||
await page.fill('input[placeholder="请输入用户名"]', process.env.TEST_USERNAME || 'admin');
|
||
await page.fill('input[placeholder="请输入密码"]', process.env.TEST_PASSWORD || '123456');
|
||
await page.click('button:has-text("登录")');
|
||
await page.waitForURL(/.*dashboard.*/);
|
||
await page.goto('/surgery-billing');
|
||
|
||
// 快速连续点击新增按钮(测试防重复锁)
|
||
const addBtn = page.locator('button:has-text("新增")');
|
||
await addBtn.click();
|
||
await addBtn.click(); // 第二次应被阻止
|
||
await addBtn.click(); // 第三次应被阻止
|
||
|
||
// 验证只弹出一个表单
|
||
await expect(page.locator('.el-dialog')).toHaveCount(1);
|
||
});
|
||
});
|
||
```
|
||
|
||
## 五、执行命令
|
||
|
||
```bash
|
||
# 安装浏览器
|
||
npx playwright install chromium
|
||
|
||
# 运行所有测试
|
||
npm run test:e2e
|
||
|
||
# 运行单个测试文件
|
||
npx playwright test login.spec.ts
|
||
|
||
# 生成HTML报告
|
||
npx playwright show-report
|
||
|
||
# UI模式(调试用)
|
||
npx playwright test --ui
|
||
```
|
||
|
||
## 六、CI/CD集成
|
||
|
||
### 6.1 package.json脚本
|
||
```json
|
||
{
|
||
"scripts": {
|
||
"test:e2e": "playwright test",
|
||
"test:e2e:ui": "playwright test --ui",
|
||
"test:e2e:report": "playwright show-report"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 6.2 Spug流水线集成
|
||
```yaml
|
||
# Spug 构建后阶段添加
|
||
- name: E2E Testing
|
||
script: |
|
||
cd openhis-ui-vue3
|
||
npx playwright install --with-deps chromium
|
||
npm run test:e2e -- --reporter=html
|
||
# 测试失败则阻断发布
|
||
if [ $? -ne 0 ]; then
|
||
echo "E2E测试失败,阻断发布!"
|
||
exit 1
|
||
fi
|
||
```
|
||
|
||
## 七、实施计划
|
||
|
||
| 阶段 | 时间 | 内容 | 负责人 |
|
||
|------|------|------|--------|
|
||
| Phase 1 | 第1周 | 登录+核心页面冒烟测试 | 张飞+赵云 |
|
||
| Phase 2 | 第2-3周 | 门诊医生站+手术计费全流程 | 张飞 |
|
||
| Phase 3 | 第4周 | Bug回归测试全覆盖 | 张飞 |
|
||
| Phase 4 | 第5周 | CI/CD流水线集成 | 赵云+运维 |
|
||
|
||
## 八、注意事项
|
||
|
||
1. **测试数据隔离**:使用独立的测试数据库,不污染生产数据
|
||
2. **环境变量**:敏感信息通过 `.env.test` 管理,不提交到git
|
||
3. **截图留痕**:失败时自动截图,便于排查
|
||
4. **测试优先**:新功能开发时同步编写测试用例
|