Files
his/docs/specs/playwright-e2e-testing-plan.md
liubei 7d55717037 feat: 添加Playwright E2E自动化测试完整方案
- 创建完整Playwright测试方案文档(docs/specs/)
- 创建Playwright配置文件(tests/playwright.config.ts)
- 创建测试数据工具类(tests/e2e/utils/test-data.ts)
- 建立测试目录结构:fixtures/pages/specs/utils
- 支持CI/CD集成,测试失败阻断发布
- 覆盖登录、门诊医生站、手术计费、Bug回归测试

关联任务: UI功能性测试方案落地
2026-04-25 21:02:13 +08:00

6.8 KiB
Raw Permalink Blame History

HIS项目 Playwright E2E 自动化测试方案 v1.0

一、方案概述

1.1 选型理由

  • Playwright 是微软开源的端到端测试框架,完美适配 Vue 3 + Vite 技术栈
  • 自动等待机制适合HIS系统复杂交互场景异步加载、动态渲染
  • 支持多浏览器Chromium/Firefox/WebKitCI/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

# 测试环境配置
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

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

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

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

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);
  });
});

五、执行命令

# 安装浏览器
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脚本

{
  "scripts": {
    "test:e2e": "playwright test",
    "test:e2e:ui": "playwright test --ui",
    "test:e2e:report": "playwright show-report"
  }
}

6.2 Spug流水线集成

# 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. 测试优先:新功能开发时同步编写测试用例