测试
01MVP 代码模板的测试覆盖范围、运行命令和扩展建议
这套模板的测试目标是守住最容易改坏、也最影响用户信任的地方:配置、路由、权限边界、登录注册、支付入口、上传安全、共享包和公开页面。
测试怎么选? Web 测试和 Package 测试属于单元测试,不启动浏览器,跑得快,适合验证逻辑和结构。浏览器 E2E 会启动真实页面,适合验证登录、跳转、移动端菜单和关键公开页。日常开发优先跑单元测试,发布前一定跑关键 E2E。
项目当前有三层测试:
- Web / Package 单元测试:快速验证配置、路由、文案、API 边界和共享包逻辑。
- 浏览器 E2E:用 Playwright 打开真实页面,监听页面错误,验证公开流程、匿名保护边界和必要的登录态流程。
- 生产 smoke:先 build,再用生产 Node server 启动页面,确认生产产物、CSP、静态资源、健康检查和登录路由都能工作。
推荐测试流程
日常开发按风险分层执行:
单元和契约测试:不依赖 seed 账号,不复用真实登录态。用 fixture、mock 或测试内 setup 验证权限函数、API contract、路由边界和纯逻辑。
vpr @01mvp/web#test
vpr @01mvp/api#test
vpr @01mvp/auth#test匿名 E2E / smoke:不需要 seed 账号。验证首页、登录页、注册页、未登录访问受保护路由会跳登录、移动端菜单和系统端点。
vpr @01mvp/product#test:e2e:public已登录 E2E:只在本地或可丢弃数据库上执行。01MVP 默认使用本机 postgresql://jackiexiao@localhost:5432/01mvp,你也可以用 PLAYWRIGHT_DATABASE_URL 覆盖。先应用迁移,再由 Playwright auth-setup 项目运行 db:seed、登录测试管理员并保存认证状态,后续登录态用例复用这个状态。
vpr @01mvp/product#db:migrate
vpr @01mvp/product#test:e2e:auth完整本地 E2E:同时运行匿名、移动端和已登录浏览器测试。它会触发 auth-setup,因此需要本地或可丢弃数据库。
vpr @01mvp/product#test:e2e本地生产 smoke:默认在本地构建并启动生产产物,不访问真实线上环境。
vpr @01mvp/product#test:e2e:production预发或线上 smoke:只有显式传入 PLAYWRIGHT_BASE_URL 时才会访问指定环境。预发可以使用专用测试账号;真实生产只做低风险检查,不运行 db:seed,不做破坏性后台操作。
PLAYWRIGHT_BASE_URL=https://staging.example.com vpr @01mvp/product#test:e2e:production登录态 E2E 可以复用一个测试管理员来验证只读页面和基础导航。如果测试会修改服务端状态,例如改资料、改权限、删数据或创建订单,应使用独立测试账号、测试内数据前缀,或在测试结束后清理数据。
运行命令
Web 测试 -- 快速验证配置和路由
vpr @01mvp/web#testPackage 测试 -- 验证共享包逻辑
vpr @01mvp/api#test
vpr @01mvp/auth#test覆盖率 -- 用 package-local 测试入口统计当前 package 的 Vitest 覆盖率
vpr @01mvp/web#test --coverage生产构建 -- 确认代码能正常编译
vpr @01mvp/product#build浏览器 E2E -- 验证关键页面和用户流程
vpr @01mvp/product#test:e2e:public
vpr @01mvp/product#test:e2e:auth
vpr @01mvp/product#test:e2e生产 smoke -- 构建后启动生产服务再验证
vpr @01mvp/product#test:e2e:production改动了 01MVP package 层代码时,建议跑产品级检查,它会通过 Vite Plus 调度 01MVP 下各 workspace 的类型检查和测试:
vpr @01mvp/product#type-check
vpr @01mvp/product#test当前覆盖范围
| 层级 | 命令 | 已覆盖内容 |
|---|---|---|
| Web 测试 | vpr @01mvp/web#test | 模板配置、路由覆盖、迁移边界、公开页面文案和 API 边界 |
| Web 覆盖率 | vpr @01mvp/web#test --coverage | 当前 Web app 的 Vitest 覆盖率,不启动浏览器 |
| Package 测试 | vpr @01mvp/api#test、vpr @01mvp/auth#test 等 | 认证、权限、支付、积分、存储、配置、AI、日志、UI 基础组件 |
| 01MVP 产品测试 | vpr @01mvp/product#test | 通过 Vite Plus 运行 01MVP 产品内已定义的测试脚本 |
| 公开浏览器 E2E | vpr @01mvp/product#test:e2e:public | 首页、登录注册、OAuth 可见性、手机号/邮箱入口、受保护路由跳登录、Drop 登录恢复、移动端菜单、公开长尾页面、系统端点 |
| 已登录浏览器 E2E | vpr @01mvp/product#test:e2e:auth | Playwright setup 登录 seed 管理员后访问 /dashboard、/dashboard/security、/admin |
| 完整浏览器 E2E | vpr @01mvp/product#test:e2e | 同时运行公开、移动端和已登录 E2E |
| 生产 smoke | vpr @01mvp/product#test:e2e:production | 生产构建、Node server 启动、SSR、CSP nonce、静态资源、健康检查、登录路由 |
这几个层级是互补的:Vitest 跑得快,适合守住模板结构和共享包;浏览器 E2E 适合确认页面真的能打开、点击后真的能跳转;生产 smoke 用来抓 dev server 里看不到的构建和运行时问题。
Web 测试示例
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vite-plus/test";
describe("route parity", () => {
it("keeps dashboard route represented", () => {
const source = readFileSync("src/routeTree.gen.ts", "utf8");
expect(source).toContain("/dashboard");
});
});这类测试放在 products/01mvp/apps/web/src/__tests__/*.test.ts。不需要真实浏览器的结构、边界和纯逻辑测试,都优先放这里。
Playwright 测试示例
import { expect, test } from "@playwright/test";
test("dashboard 未登录跳转登录页", async ({ page }) => {
await page.goto("/dashboard", { waitUntil: "networkidle" });
await expect(page).toHaveURL(/\/auth\/login/);
expect(new URL(page.url()).searchParams.get("redirect")).toBe("/dashboard");
});这类测试放在 products/01mvp/apps/web/__e2e__/**/*.spec.ts。本地调试可以进入 products/01mvp/apps/web 后运行:
vp exec playwright test --debug当前 E2E 默认使用隔离端口 7010,避免误用你手动启动在 7001 的开发服务。如果要指定地址,可以设置:
PLAYWRIGHT_BASE_URL=http://localhost:7001 vpr @01mvp/product#test:e2e:public移动端用 .mobile.spec.ts 文件,登录态用 .auth.spec.ts 文件,生产 smoke 用 .production.spec.ts 文件。
登录态 E2E 的认证状态
需要登录态的 E2E 推荐使用 Playwright setup project:
auth-setup项目运行vpr @01mvp/product#db:seed准备测试管理员。auth-setup通过登录页完成一次真实邮箱密码登录。- 登录成功后把
storageState保存到test-results/.auth/admin.json。 authenticated-chromium项目通过storageState启动,直接访问/dashboard、/dashboard/security、/admin等页面。
db:seed 不需要改名。它负责准备数据库数据;Playwright 的 auth-setup 负责准备浏览器登录态。认证状态文件包含 cookie 和会话信息,不能提交到 Git;当前写入已忽略的 test-results/.auth/,只作为本次测试产物。
如果要让 auth E2E 使用指定数据库,可以传入:
PLAYWRIGHT_DATABASE_URL=postgresql://jackiexiao@localhost:5432/01mvp vpr @01mvp/product#test:e2e:auth如果目标是可丢弃的远程开发库,必须显式放行:
PLAYWRIGHT_DB_SEED_ALLOW_REMOTE=true \
PLAYWRIGHT_DATABASE_URL=postgresql://postgres:[email protected]:5432/01mvp-start \
PLAYWRIGHT_BASE_URL=https://staging.example.com \
vpr @01mvp/product#test:e2e:auth如果仓库里同时有 OneSay,OneSay 的本地浏览器测试走 Wrangler D1:Playwright 会先执行 @onesay/db 的本地 D1 migration,再用 Wrangler dev 启动应用,auth-setup 会把测试管理员写入 Wrangler 的本地 D1 状态,不会调用 Postgres seed。
生产 smoke 的目标环境
vpr @01mvp/product#test:e2e:production 默认会执行本地产品 build 和 start,然后访问 http://localhost:7011。这类测试用于确认生产构建产物能启动、SSR 正常、CSP nonce 正常、静态资源能访问、/api/health 正常、登录路由可用。
如果设置了 PLAYWRIGHT_BASE_URL,Playwright 不会启动本地服务,而是直接访问这个地址:
PLAYWRIGHT_BASE_URL=https://example.com vpr @01mvp/product#test:e2e:production真实生产 smoke 应保持只读、低风险:检查首页、登录页、健康检查、静态资源和未登录保护边界即可。需要写数据或管理员权限的流程放在本地、CI 临时库或预发环境。
什么时候补测试
不确定要不要写测试?简单原则:涉及钱、权限、登录的改动,必须有测试。其他改动建议有测试。
下面这些改动建议同步补测试:
- 新增 Hono route、oRPC procedure、TanStack route guard 或鉴权中间件
- 修改支付、积分、权限、上传、登录注册、数据库 schema
- 调整
packages/*中会被多个 app 复用的逻辑 - 修改公开文档路由、定价页、登录页、设置页、后台页
- 修复线上 bug(先写能复现问题的测试,再改实现)
登录注册属于必须重点保护的流程。至少要覆盖:
/auth/login能打开,页面没有 runtime error。/api/rpc/auth/capabilities正常返回,Google / GitHub 按钮按配置可见。- 手机号登录、邮箱登录、注册入口能进入对应表单。
- 未登录访问
/dashboard、/ai、/admin会跳到登录页,并保留安全的 redirect。 - 移动端菜单能打开,并能进入登录页。
测试放哪里
| 你要测什么 | 放在哪里 |
|---|---|
| 不需要浏览器的 app 结构、配置、路由边界 | products/01mvp/apps/web/src/__tests__/*.test.ts |
| 共享 package 的纯函数、provider、service | 对应 packages/<name>/src/**/*.test.ts |
| 用户可见页面、跳转、移动端渲染 | products/01mvp/apps/web/__e2e__/**/*.spec.ts |
| 只在移动端跑的浏览器流程 | products/01mvp/apps/web/__e2e__/**/*.mobile.spec.ts |
| 需要登录态的浏览器流程 | products/01mvp/apps/web/__e2e__/**/*.auth.spec.ts |
| 需要先 build 再验证的生产流程 | products/01mvp/apps/web/__e2e__/**/*.production.spec.ts |
| 文档导航是否能打开 | 优先放入浏览器 E2E 或生产 smoke |
| 需要真实外部服务的流程 | 放到预发环境脚本或单独 E2E,避免污染默认本地测试 |
默认原则:越靠近底层逻辑,测试越小;越靠近用户流程,测试越像真实浏览器操作。
这篇文档有问题?