1
0
Files
nex/openspec/changes/e2e-real-backend/design.md
lanyuanxiaoyao 59179094ed feat: E2E 测试集成真实后端
- Playwright 双 webServer 模式自动启动 Go 后端 + Vite 前端
- 后端使用临时 SQLite 数据库隔离,固定端口 19026
- vite.config.ts proxy target 动态读取环境变量
- 新增 sql.js 依赖用于 SQLite 统计数据 seed
- 新增 e2e/fixtures.ts 共享工具模块(API seed + SQLite seed)
- 拆分测试文件 5→7(providers/models/stats/navigation/validation)
- 删除旧文件 crud.spec.ts/sidebar.spec.ts/stats-cards.spec.ts
- E2E 测试尚有部分用例需调试修复
2026-04-22 00:31:35 +08:00

5.9 KiB
Raw Blame History

Context

前端 Playwright E2E 测试当前只启动 bun run devVite dev server后端不参与。现有 5 个 E2E 测试文件中,所有写操作(创建/编辑/删除供应商和模型)的验证都不完整——因为 API 请求无法到达后端,表单提交后的数据持久化无法验证,大量测试在缺少已有数据时直接 test.skip()

后端具备天然测试友好特性Go CLI 参数可覆盖所有配置(--server-port--database-path--log-path--log-levelSQLite 文件数据库使每次测试可用独立临时文件,首次启动自动运行 goose 迁移,有 /health 端点可供就绪检查。

Goals / Non-Goals

Goals:

  • bun run test:e2e 一条命令自动启动隔离后端 + 前端,运行完整 E2E 测试,自动清理
  • 每次测试运行使用干净的临时数据库,测试间无状态污染
  • E2E 测试能验证完整 CRUD 流程:创建→验证存在→编辑→验证更新→删除→验证消失
  • 统计页面可通过 seed 数据验证数字、筛选、图表渲染
  • 对日常开发流程零侵入(bun run dev 行为不变)
  • Windows 原生兼容(项目在 Windows 上开发)

Non-Goals:

  • 不修改后端代码(仅通过 CLI 参数启动现有二进制)
  • 不引入 CI 流水线配置
  • 不改动 MSW 在单元测试中的使用
  • 不实现随机端口分配(使用固定非默认端口 19026
  • 不引入 cross-env 等跨平台环境变量工具

Decisions

Decision 1: 固定测试端口 19026 vs 随机端口

选择: 固定端口 19026

理由: 随机端口需要在 globalSetup 中 spawn 后端进程、等待健康检查、管理进程生命周期(包括 Windows 上的 SIGTERM 问题复杂度高。19026 是非标准端口,与开发端口 9826 不冲突冲突概率极低。Playwright webServer 数组模式可直接管理两个进程的生命周期,无需手动 spawn/kill。

备选方案: globalSetup 中分配随机端口 → spawn 后端 → 等待健康检查 → globalTeardown 中 kill 进程。在 Windows 上 SIGTERM 不可靠,需 taskkill 强杀,进程管理复杂。

Decision 2: 环境变量传递方式

选择: process.env 继承,不引入 cross-env

理由: Playwright 的 webServer 通过 child_process.spawn 启动子进程,子进程默认继承父进程 process.env。在 playwright.config.ts 模块顶层设置 process.env.NEX_BACKEND_PORT = '19026'Vite dev server 子进程自动继承,vite.config.tsdefineConfig 函数可读取。E2E 测试文件与 config 同进程,直接读取即可。三处消费者(后端 CLI flags / Vite / 测试文件)都无需额外工具。

Decision 3: 统计数据 seed 方式

选择: sql.js 直接操作 SQLite 文件

理由: 统计数据(usage_stats 表)只能通过后端 statsService.Record() 按当天日期 upsert没有 API 可以插入任意日期的历史数据。统计页面测试需要多日趋势数据来验证筛选和图表。sql.js 是纯 WASM 实现无原生编译依赖Windows 上零风险。通过"读文件→内存操作→写回"模式在 beforeAll 中 seed 数据,串行化保证无并发冲突。

备选方案:

  • better-sqlite3需要原生编译Windows 上可能有编译工具链问题
  • 后端加测试专用 seed API需要修改后端代码违反"不改后端"原则
  • 只测今日数据:无法验证日期筛选和趋势图表,测试覆盖不足

Decision 4: 临时文件管理

选择: fs.mkdtempSync(os.tmpdir() + '/nex-e2e-') 创建,fs.rm(dir, { recursive: true, force: true })globalTeardown 清理

理由: mkdtempSync 跨平台安全Windows 上生成 %TEMP%\nex-e2e-xxxxxxxx 路径。Go 后端的 --database-path--log-path 参数接受 Windows 路径。fs.rm 是 Node.js 14.14+ 内置的递归删除 API无需额外依赖rimraf 等)。

Decision 5: 测试文件拆分 5→7

选择: 按职责拆分

新文件 来源 职责
providers.spec.ts 重写 providers.spec.ts + crud.spec.ts 供应商部分 供应商完整 CRUD 验证
models.spec.ts 新增,来自 crud.spec.ts 模型部分 模型管理完整验证
stats.spec.ts 重写 stats.spec.ts + 合并 stats-cards.spec.ts 统计页面完整验证
navigation.spec.ts 新增,来自 sidebar.spec.ts + 导航测试 导航和侧边栏
validation.spec.ts 新增,来自 crud.spec.ts 表单验证部分 表单校验测试
fixtures.ts 新增 共享常量和 seed 工具函数
global-setup.ts / global-teardown.ts 新增 临时目录生命周期

Decision 6: 进程启动顺序

选择: Playwright webServer 数组,后端在前、前端在后

理由: Playwright 按数组顺序依次等待每个 webServer 的 url 就绪。后端先启动(/health 返回 200再启动前端Vite 默认端口 5173timeout: 60000 覆盖 Go 首次编译耗时。两个 webServer 均设 reuseExistingServer: false,确保每次运行都是全新进程。

Risks / Trade-offs

  • [Go 编译缓存] → 首次 go run 需要 5-10s 编译,后续利用 Go 构建缓存加速。timeout: 60000 提供充足缓冲。如仍嫌慢,可手动 cd backend && go build ./cmd/server/ 预编译。
  • [端口 19026 冲突] → 概率极低。Playwright 报明确错误,用户手动释放即可。不考虑自动重试。
  • [Ctrl+C 强退临时文件残留]globalTeardown 不执行,但下次运行创建新目录,旧目录不占端口。可接受。
  • [SQLite WAL 文件] → 后端进程被 Playwright 强杀时可能留下 .db-wal/.db-shm 文件,但随临时目录一起删除,无影响。
  • [sql.js 串行化约束] → seed 数据时需确保 API 操作完成后再操作 SQLite。在 beforeAll 中串行执行,不存在并发问题。