背景:远端自建 Gitea 未部署 Actions runner,推送后线上 CI 无法执行;原规范仍要求「推送后确认 CI」,容易误以为需等待远端流水线。 改动: - AGENTS §6/§7:CI 只本地执行,推送前必须 pnpm ci:local 或本地门禁全绿,禁止等待/依赖远端 CI。 - 06-测试与CI规范 V1.1:新增「本地 CI 流水线(远端不跑 CI)」强制规则;集成/契约运行时机改为推送前本地。 - 01-Git规范 / 07-CodeReview:删除「推送后确认 CI」,改为本地门禁后推送。 - README:明确远端无 runner,ci.yml 仅本地参考/手动触发。 - .gitea/workflows/ci.yml:去掉 push 触发,仅保留 workflow_dispatch,避免推送停留在 queued。 影响面:仅规范与工作流配置,不影响代码/数据。 验证:pnpm format:check / lint 通过;pnpm ci:local 全部门禁通过(237.2s,4 e2e 冒烟 passed,8 个门控用例按环境变量跳过)。
127 lines
6.0 KiB
Markdown
127 lines
6.0 KiB
Markdown
# 06 · 测试与 CI 规范
|
||
|
||
| 项 | 内容 |
|
||
| --- | --- |
|
||
| 文档版本 | V1.1(2026-11-04) |
|
||
| 依据 | 技术架构 §10.4(测试策略)、§4.6(CI/CD)、§4.1.1(本地环境) |
|
||
| 适用范围 | 全仓库 |
|
||
| 强制级别 | 强制 |
|
||
| 远端 CI | **不启用**:Gitea 无 runner,CI 只本地执行 |
|
||
|
||
---
|
||
|
||
## 1 测试分层
|
||
|
||
| 层级 | 工具 | 范围 | 运行时机 |
|
||
| --- | --- | --- | --- |
|
||
| 单元 | Vitest | Service、工具函数、状态机、命名 / 表单引擎 | 每次提交(CI + 本地) |
|
||
| 集成 | Vitest + Testcontainers(PG 18 / Redis 7.4 / MinIO) | Repository、队列、迁移、事务 | 每次推送前本地 `pnpm ci:local` |
|
||
| 契约 | OpenAPI + `oasdiff` | 接口兼容性 | 每次推送前本地 `pnpm ci:local` |
|
||
| E2E | Playwright | 主链路(登录 → 生成 → 预览 → 勾选 → 导出) | 主干 + 发布前 |
|
||
| 性能 | k6 | 列表 / 任务提交 / SSE | 发布前(仅 staging) |
|
||
| 视觉回归 | 图片像素比对 | PSD 合成产物 | 改动 `packages/render` 时 |
|
||
|
||
- `TST-01` 单测与源码同目录,命名 `<name>.spec.ts`;集成 `*.int.spec.ts`;E2E 放 `e2e/`。
|
||
- `TST-02` 关键包(`shared` / `form-engine` / `render` / `ai-sdk`)行覆盖率 **≥ 70%**;整体基线只升不降。
|
||
- `TST-03` 禁止提交 `.skip` / `.only`;本地 `pnpm ci:local` 检测到即失败。
|
||
- `TST-04` 禁止依赖执行顺序;每个测试自建数据、自清理(用独立 `customer_id` 前缀)。
|
||
|
||
---
|
||
|
||
## 2 必测清单(缺一项即 Review 不通过)
|
||
|
||
| 编号 | 场景 |
|
||
| --- | --- |
|
||
| `TST-05` | **权限三态**:每个端点至少「有权限 / 无权限 / 范围外」3 条用例 |
|
||
| `TST-06` | **客户隔离**:跨客户读取必须 403 或空集,且不得泄漏存在性 |
|
||
| `TST-07` | **状态机**:合法迁移 + 非法迁移(返回 409)各一条 |
|
||
| `TST-08` | **幂等**:同 `Idempotency-Key` 重复提交只产生一次副作用 |
|
||
| `TST-09` | **成本前置**:任务提交未带预估成本 / 超预算时被拒 |
|
||
| `TST-10` | **审计**:导出、权限变更、AI 配置变更均落审计 |
|
||
| `TST-11` | **降级路径**:抠图失败 → 原图 + `low_quality` 标记;AI 内容违规 → 不重试 |
|
||
| `TST-12` | **迁移**:升级后可回滚;expand 阶段旧代码仍可用 |
|
||
| `TST-13` | **任务断点**:SSE 断线后 `Last-Event-ID` 可续推 |
|
||
| `TST-14` | **命名规则**:非法字符、超长、同名重名各一条(PRD R-01) |
|
||
|
||
---
|
||
|
||
## 3 测试数据与环境
|
||
|
||
- `TST-15` 禁止连接生产库 / 生产对象存储;本地 CI 用 Testcontainers / 本地容器起同版本依赖。
|
||
- `TST-16` 测试数据用 factory 构造,禁止依赖线上导出数据。
|
||
- `TST-17` 测试内置时钟可注入(`clock` 包),禁止 `new Date()` 直接断言时间。
|
||
- `TST-18` AI 调用在测试中一律 mock Provider,**禁止**真实外网调用(防止费用与不稳定)。
|
||
- `TST-19` 涉及文件的测试用内存 / 临时目录,结束后清理。
|
||
|
||
---
|
||
|
||
## 4 本地 CI 流水线(远端不跑 CI)
|
||
|
||
```
|
||
install --frozen-lockfile
|
||
→ format:check → lint --max-warnings=0 → typecheck
|
||
→ unit test(coverage)→ build
|
||
→ integration(Testcontainers)→ openapi:diff
|
||
→ e2e(main)→ 镜像构建 + 漏洞扫描
|
||
```
|
||
|
||
> **强制规则(2026-11-04 确认)**:远端自建 Gitea **未部署 Actions runner,线上 CI 不可用**。所有 CI 一律在本地执行:
|
||
> - 推送前运行 `pnpm ci:local`(完整链路)或至少 `pnpm format:check && pnpm lint && pnpm typecheck && pnpm test`;
|
||
> - `.gitea/workflows/ci.yml` 仅供本地参考 / 手动触发,**不随 push 自动运行**;
|
||
> - 禁止在推送后等待远端 CI、禁止以「远端 CI 会在后续跑」为由跳过本地门禁。
|
||
|
||
| 阶段 | 阻断条件 |
|
||
| --- | --- |
|
||
| 安装 | lock 文件与 `package.json` 不一致 |
|
||
| 格式 / Lint | 任一错误或警告 |
|
||
| 类型 | 任一错误 |
|
||
| 单测 | 失败或覆盖率低于基线 |
|
||
| 集成 | 失败或超时(单测总时长 ≤ 10 分钟) |
|
||
| 契约 | `oasdiff` 检出破坏性变更但未升版本 |
|
||
| 构建 | 失败 |
|
||
| 安全 | 高危漏洞 > 0 |
|
||
|
||
- `TST-20` 流水线并行化按包拆分(Turborepo),但门禁结论必须在聚合 job 上判定。
|
||
- `TST-21` 禁止通过 `--passWithNoTests`、跳过集成测试等方式「修绿」;豁免须技术负责人批准并留提交说明记录。
|
||
- `TST-22` flaky 测试 24 小时内修复或移除并登记,**禁止**重试 3 次掩盖。
|
||
|
||
---
|
||
|
||
## 5 特性开关与灰度
|
||
|
||
| 变量 | 用途 |
|
||
| --- | --- |
|
||
| `FEATURE_VIDEO` | 视频线开关(未完成不得外露) |
|
||
| 其他 `FEATURE_*` | 按里程碑临时开关,上线稳定后删除 |
|
||
|
||
- `TST-23` 未完成功能必须藏在开关后,**禁止**半成品直接可见。
|
||
- `TST-24` 开关必须有默认值、有 owner、有清理期限(写进提交说明或配置注释)。
|
||
- `TST-25` 开关组合不得导致数据不一致(关闭后已产生的数据仍可读)。
|
||
|
||
---
|
||
|
||
## 6 发布与回滚
|
||
|
||
```
|
||
staging 部署 → 冒烟(登录 / 生成 / 预览 / 导出)
|
||
→ 生产迁移(expand)→ 灰度 10% → 观察 30 分钟 → 全量 → 收缩(contract,下个版本)
|
||
```
|
||
|
||
- `TST-26` 迁移先行、代码后行;收缩步骤必须在**确认无旧版本流量**后执行。
|
||
- `TST-27` 每次发布必须有回滚预案:代码回滚 + 数据回滚(或前向修复)分别说明。
|
||
- `TST-28` 发布后观察:错误率、P95、队列积压、AI 费用;异常 15 分钟内决策回滚。
|
||
- `TST-29` 发布记录写入 `docs/releases/`(版本、变更、影响面、回滚方式)。
|
||
|
||
---
|
||
|
||
## 7 检查清单
|
||
|
||
- [ ] 新增 / 修改逻辑有对应单测,关键包覆盖率达标
|
||
- [ ] 端点有权限三态用例,客户隔离用例存在
|
||
- [ ] 状态机非法迁移、幂等、成本前置已覆盖
|
||
- [ ] 集成测试用 Testcontainers,无外网依赖
|
||
- [ ] 本地 `pnpm ci:local` 全绿且未使用豁免(远端无 runner)
|
||
- [ ] 迁移可回滚,staging 已演练
|
||
- [ ] 未完成功能藏开关,开关有清理期限
|
||
- [ ] 发布记录与回滚预案已写
|