Files
NextEdu/docs/testing/visual-regression.md
SpecialX 6585e10c6f feat(P2): 实现质量保障类5项功能(无障碍/视觉回归/通知渠道/漏洞扫描/灾备)
## 新增功能

### 1. 屏幕阅读器兼容性增强(a11y)
- 无障碍工具库:src/shared/lib/a11y.ts
- aria-live Hook:src/shared/hooks/use-aria-live.ts
- a11y 组件:skip-link/visually-hidden/focus-trap/aria-status
- 增强 UI:table.tsx 系统性 ARIA role,dialog.tsx aria-modal
- 审计文档:docs/accessibility/a11y-audit.md(WCAG 2.1 AA 清单)

### 2. 视觉回归测试
- 测试套件:tests/visual/(homepage + 3 个 dashboard)
- 3 视口(desktop/tablet/mobile)× 2 主题(light/dark)
- 动态元素遮罩,避免误报
- playwright.config.ts 新增 visual-chromium 项目
- 文档:docs/testing/visual-regression.md

### 3. 短信/微信推送渠道集成
- 新模块:src/modules/notifications/
- 4 个渠道:SMS(阿里云/腾讯云)、WeChat(公众号)、Email(SMTP)、In-App
- 分发器按用户偏好并行多渠道发送
- 外部 SDK 动态 import,Mock 模式开发可用
- 文档:docs/notifications/channels.md

### 4. 漏洞扫描 CI 集成
- CI security-scan job:npm audit + Snyk + Trivy FS + OWASP ZAP
- 独立工作流 security.yml:每周一深度扫描 + 容器镜像扫描
- 配置:suppressions.json + .trivyignore
- 本地脚本:security-scan.sh/ps1
- 文档:docs/security/scanning.md(SLA 分级)

### 5. 灾备方案
- 脚本:backup-verify/backup-offsite-sync/dr-drill/failover/health-check
- CI 增强:备份后校验+异地同步,每周灾备演练
- 独立工作流 dr-drill.yml:每周一凌晨 4 点自动演练
- 文档:docs/dr/dr-plan.md(RTO 4h/RPO 24h)+ dr-runbook.md(6 故障场景)

## 验证
- npx tsc --noEmit:0 错误
- npm run lint:0 错误 0 警告
2026-06-17 20:18:29 +08:00

5.8 KiB
Raw Permalink Blame History

视觉回归测试 (Visual Regression Testing)

本项目使用 PlaywrighttoHaveScreenshot() API 实现视觉回归测试,对关键页面在多种视口与主题下进行像素级快照对比,以捕获 UI 的意外变化。

目录结构

tests/visual/
├── visual.config.ts              # 视觉测试配置(页面、视口、主题、快照路径)
├── homepage.spec.ts              # 登录页视觉测试
├── admin-dashboard.spec.ts       # 管理员仪表盘视觉测试
├── teacher-dashboard.spec.ts     # 教师仪表盘视觉测试
├── student-dashboard.spec.ts     # 学生仪表盘视觉测试
├── helpers/
│   ├── auth.ts                   # 认证辅助(登录、setupAuthState)
│   └── visual-helpers.ts         # 视觉通用辅助(视口、主题、遮罩)
└── __screenshots__/              # 快照基线存储目录(自动生成)

覆盖范围

页面 路径 视口 主题 是否需要登录
登录页 /login desktop / tablet / mobile light / dark
管理员仪表盘 /admin/dashboard desktop / tablet / mobile light / dark 是 (admin)
教师仪表盘 /teacher/dashboard desktop / tablet / mobile light / dark 是 (teacher)
学生仪表盘 /student/dashboard desktop / tablet / mobile light / dark 是 (student)

视口尺寸:

  • desktop: 1920 × 1080
  • tablet: 768 × 1024
  • mobile: 375 × 812

运行测试

前置条件

  • 需要启动开发服务器(Playwright 会通过 webServer 配置自动启动)
  • 需要登录的视觉测试需要 DATABASE_URL 环境变量,否则会自动跳过
  • 测试账号默认为 admin@xiaoxue.edu.cn / 123456,可通过环境变量覆盖

运行命令

# 运行所有视觉回归测试
npm run test:visual

# 运行单个测试文件
npx playwright test --project=visual-chromium tests/visual/homepage.spec.ts

# 以 UI 模式运行(便于调试)
npx playwright test --project=visual-chromium --ui

环境变量

变量 默认值 说明
DATABASE_URL - 数据库连接串,未设置时需要登录的测试会跳过
VISUAL_ADMIN_EMAIL admin@xiaoxue.edu.cn 管理员测试账号
VISUAL_ADMIN_PASSWORD 123456 管理员测试密码
VISUAL_TEACHER_EMAIL admin@xiaoxue.edu.cn 教师测试账号
VISUAL_TEACHER_PASSWORD 123456 教师测试密码
VISUAL_STUDENT_EMAIL admin@xiaoxue.edu.cn 学生测试账号
VISUAL_STUDENT_PASSWORD 123456 学生测试密码

更新基线

当 UI 发生预期内的变化时,需要更新快照基线:

# 更新所有视觉快照基线
npm run test:visual:update

# 更新单个测试文件的基线
npx playwright test --project=visual-chromium tests/visual/homepage.spec.ts --update-snapshots

更新后的快照应作为 PR 的一部分提交到版本库,以便团队评审 UI 变更。

处理误报

视觉测试可能因为动态内容(时间戳、用户名、实时数据等)产生误报。本项目通过以下方式消除误报:

1. 动态元素遮罩

maskDynamicElements() 辅助函数会自动遮罩以下选择器:

  • [data-testid='timestamp']
  • [data-testid='current-time']
  • [data-testid='user-avatar']
  • [data-testid='user-name']
  • time
  • [data-visual-dynamic]

可在测试中追加额外需要遮罩的选择器:

const masks = await maskDynamicElements(page, ["[data-testid='stat-card-value']"])

2. 标记动态元素

在组件代码中为动态元素添加 data-visual-dynamic 属性,即可自动被遮罩:

<div data-visual-dynamic>{new Date().toLocaleString()}</div>

3. 调整容差

playwright.config.ts 中配置了默认容差 maxDiffPixelRatio: 0.01(允许 1% 像素差异)。若特定页面需要更宽松的容差,可在断言时覆盖:

await expect(page).toHaveScreenshot("name.png", {
  maxDiffPixelRatio: 0.05,
})

4. 禁用动画

默认配置 animations: "disabled",避免动画过渡态导致快照不稳定。

CI 集成

GitHub Actions 示例

name: Visual Regression
on:
  pull_request:
    paths:
      - "src/**"
      - "tests/visual/**"
      - "playwright.config.ts"

jobs:
  visual:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      - run: npx playwright install --with-deps chromium

      # 启动数据库(按需)
      - run: npm run db:setup
        env:
          DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}

      - name: Run visual tests
        run: npm run test:visual
        env:
          DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}
          CI: "true"

      - name: Upload snapshot diff
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: snapshot-diff
          path: test-results/
          retention-days: 7

CI 注意事项

  1. 快照基线需提交到版本库: tests/visual/__screenshots__/ 目录应纳入 Git 跟踪
  2. 跨平台一致性: 不同操作系统的字体渲染存在差异,建议 CI 与本地使用相同的 Linux 容器环境。若本地为 Windows/macOS,可能出现少量误报,以 CI 结果为准
  3. storageState 缓存: tests/visual/.auth/ 目录应加入 .gitignore,不要提交登录态文件

与 E2E 测试的关系

维度 E2E 测试 视觉测试
目录 tests/e2e/ tests/visual/
Playwright 项目 chromium visual-chromium
运行命令 npm run test:e2e npm run test:visual
关注点 功能正确性 UI 视觉一致性
断言方式 DOM/行为断言 像素快照对比

两个测试套件相互独立,可分别运行,互不影响。