测试指南
本文档介绍了 IAM 项目中引入的自动化测试体系。我们采用了 Vitest 进行单元和组件测试,以及 Playwright 进行端到端(E2E)测试,并通过 Turborepo 实现了全栈测试的统一编排。
测试架构概览
Section titled “测试架构概览”项目采用分布式测试策略,针对不同层级的代码选用最合适的工具:
| 层级 | 工具选型 | 目标 | 路径 |
|---|---|---|---|
| 后端单元/集成测试 | Vitest | 测试 Hono API 路由、tRPC Logic、Utils | apps/server/src/*.test.ts |
| 前端组件测试 | Vitest + RTL | 测试 UI 组件渲染与交互逻辑 | apps/web/src/**/*.test.ts(x) |
| 共享包测试 | Vitest | 认证、契约、数据库、API 路由与工具函数 | packages/*/src/*.test.ts |
| 端到端测试 (E2E) | Playwright | 模拟真实用户在浏览器中的核心业务链路 | apps/web/e2e/*.spec.ts |
检查环境变量
Section titled “检查环境变量”pnpm env:check该命令检查本地 .dev.vars 是否存在、必填项格式和企业微信配置组是否完整,但不会输出任何密钥值。
运行全路径测试
Section titled “运行全路径测试”在项目根目录下,可以通过一个命令运行所有子项目的单元与组件测试:
pnpm test[!NOTE] 该命令通过 Turborepo 运行所有配置了
test脚本的 workspace,包括apps/server、apps/web以及packages下的api、auth、contracts、db、env。
运行指定包的测试
Section titled “运行指定包的测试”改单个包时优先跑窄范围测试,比全仓库更快也更少受本机资源影响:
pnpm --filter @IAM/auth testpnpm --filter server testpnpm --filter web test共享包(如 @IAM/contracts)改动会影响多个应用,这类变更应再跑一次 pnpm test 确认。
运行端到端测试
Section titled “运行端到端测试”pnpm test:e2e[!TIP] Playwright 会自动启动
apps/web的 Next.js 服务。需要真实认证后端的用例仍需确保 8787 API 可用,并正确配置AUTH_UPSTREAM_URL。
详细配置说明
Section titled “详细配置说明”1. 后端测试 (apps/server)
Section titled “1. 后端测试 (apps/server)”后端使用 Vitest 的 node 环境执行。
- tRPC 集成测试:我们推荐使用 tRPC 的
createCaller模式。这种模式不需要启动真实的 HTTP 服务,而是直接在进程内调用路由逻辑,执行速度极快且能够深度覆盖权限检查、数据库交互等业务。 - Hono 请求测试:利用 Hono 实例自带的
.request()方法,可以直接模拟 Fetch API 风格的请求来验证 REST 路由。
2. 前端测试 (apps/web)
Section titled “2. 前端测试 (apps/web)”前端使用 Vitest 的 jsdom 环境,结合 React Testing Library (RTL)。
- 环境 Mock:我们在
vitest.setup.ts中配置了常用的浏览器 API Mock(如matchMedia,ResizeObserver),并集成了jest-dom断言库。 - TypeScript 支持:项目已配置项目级类型定义,在
.test.tsx文件中可直接获得describe,it,expect的智能补全。
3. E2E 测试 (Playwright)
Section titled “3. E2E 测试 (Playwright)”- 配置文件:
apps/web/playwright.config.ts - 可视化调试:执行
pnpm --filter web test:e2e:ui可打开 Playwright 的交互式界面,支持断点调试、时光倒流追踪(Trace Viewer)等功能,极大提升 E2E 编写效率。test:e2e:ui只定义在apps/web,根目录没有同名脚本。
覆盖率统计 (Coverage)
Section titled “覆盖率统计 (Coverage)”项目接入了 v8 覆盖率引擎。分别执行:
pnpm --filter server test:coveragepnpm --filter web test:coveragepnpm --filter @IAM/auth test:coverage运行结束后,可分别在 apps/server/coverage、apps/web/coverage 和 packages/auth/coverage 查看报告。packages 下的其余包(api、contracts、db、env)也都配置了同名 test:coverage 脚本。
最佳实践与建议
Section titled “最佳实践与建议”- 测试文件命名:
- 单元测试请以
.test.ts或.test.tsx结尾,并与源代码放在同级目录。 - E2E 测试请统一存放在
apps/web/e2e/目录下。
- 单元测试请以
- 避免过度 Mock:在 tRPC 测试中,建议尽量真实调用底层 Service,仅对外部网络请求或极其复杂的模块进行 Mock。
- CI 集成:
.github/workflows/ci.yml已分三个 job 执行完整门禁——静态检查(pnpm lint、pnpm format:check、pnpm check-types)、Vitest(pnpm test)与 Playwright(pnpm test:e2e)。本地提交前至少运行pnpm check与受影响包的测试。
当前覆盖与缺口
Section titled “当前覆盖与缺口”已有测试覆盖 Hono 路由、OIDC 负例、数据库 batch、R2 上传、企微登录、认证默认配置、前端登录与 OAuth 客户端表单。上线前仍需优先补:
- 完整 Authorization Code + PKCE 正流程
- refresh token rotation、重放和撤销
- 邮箱验证、密码重置与旧会话失效 E2E
- 企微离职禁用、通讯录回调和全量同步异常
- 应用角色、用户/部门授权与
app_roleclaim 一致性
安全回归与隔离环境
Section titled “安全回归与隔离环境”pnpm test:e2e 会启动 apps/server/e2e/server.ts,使用每次重建的内存 PostgreSQL(PGlite)及固定测试账号,不读取本地 .dev.vars。测试账号仅在该测试进程存在,启动入口拒绝非 test 环境。端口 8787 必须空闲,避免浏览器用例误连已有后端;前端使用 3000 端口。
浏览器回归覆盖管理员登录与应用列表、普通用户页面和 API 拒绝访问,以及原生资料更新的部门字段保护。协议层的完整授权码、刷新及撤权回归位于 apps/server/src/oauth-flow.test.ts。
PGlite 的 runDbBatch 使用真实数据库事务执行,批次后续失败必须回滚前面的写入。packages/db/src/batch-rollback.test.ts 与 packages/auth/src/provisioning-outbox.test.ts 覆盖事务回滚、审计失败、任务重试及并发新任务保护;它们不代表已验证线上 Neon 的网络与性能行为。
CI 另外执行 API Worker 的 wrangler deploy --dry-run 和 OpenNext Worker 生产构建,均不发布线上资源。