# 分层测试策略（SDD / OpenSpec 强制）

> 由 `sdd-flow-kit` 安装到目标项目时，应合并进 `tdd-script` 与 `playwright-e2e-dev-server` skill 的「验收层级」章节。

## 四层模型

| 层级 | 覆盖范围 | 典型断言 | 缺失风险 | 门禁 |
|------|---------|---------|---------|------|
| **L1 能力** | API、状态机、mapper、脏数据 | 接口封装、枚举映射、mutation 参数、**snake/camel normalize** + **fixture 字段覆盖** | 主流程不通、列表空数据 | `assess-api-field-contract.mjs` + `assess-api-field-coverage.mjs` + unit |
| **L2 交互契约** | 列序、disabled、toast、tooltip、placeholder | **完整字符串**（禁止 `toContain('成功')`） | PRD 细节漏项 | AC 映射须 test 块内 `expect` |
| **L3 路径** | 每页面/每主链路一条 E2E | 登录 → 列表有数据 → 点详情 → **演示映射中的按钮/区块** | 只 smoke placeholder | `assess-e2e-assertion-depth.mjs` |
| **L3.5 演示迁移** | 演示模块 → 生产组件 1:1 | design 映射表每行在生产代码有「关键交互信号」+ **非空壳组件**；信号≥2 且非弱词；design 不得弱于 04 | 单文件只读骨架代替演示；「搜索、保存」假信号 | `demo-signal-quality` + `design-demo-not-weaker` + `assess-demo-implementation-coverage.mjs` + `assess-component-substance.mjs` |
| **L3.6 UI 约束** | 壳层 + 交互原语 | UI P0 AC 写明独立页/Tab/弹窗/Drawer 与双击/行内等 | 仅接口权限当验收 | `ui-ac-criteria-quality`（docs-closed） |
| **L3.7 AC 断言绑定** | P0 验收标准字面量 | test expect 含 05 原文（禁止模糊 toContain('成功')） | PRD 文案漏测 | `assess-ac-assertion-binding.mjs` |
| **L3.8 E2E 演示点击** | 映射表中可点击信号 | spec 中 click/getByText 覆盖「编辑/保存/导入」等 | 有按钮无点击 | `assess-e2e-assertion-depth.mjs`（含 demo signal） |
| **L4 视觉** | 原型图 / PRD 截图 / `visual-baseline` | 至少 1 条 **P0/P1** visual + `toHaveScreenshot`；豁免须可审计原因 | UI 与原型偏差；P2 应付；无因 EXEMPT | `visual-ac-priority` + `assess-visual-regression.mjs` |

## 禁止伪覆盖

- **禁止** `prd-atoms-coverage.spec.ts` 等仅 `toBeGreaterThan(0)` 或注释登记 PRD-ID 的文件计入 semantic/e2e 覆盖。
- **禁止** `expect(true).toBe(true)` / `expect(1).toBe(1)` 等恒真断言充当 AC 绑定（`assess-e2e-assertion-depth` + `ac-assertion-binding` 会 FAIL）。
- **禁止** `[交互]` e2e AC 仅用 `body.click({ x: 8, y: 8 })` 冒充真实交互；须点击对应 shell 触发器（如 Drawer 的 `[title="列配置"]`）。
- **禁止** 仅 `getByPlaceholder` 可见即宣布列表类 AC 通过；须 `waitForResponse` / `getByRole('cell')` / `toContainText` 等数据断言。
- **禁止** 用 `fs.readFileSync` / `readFile` 读 `.vue`/`.ts` 源码再 `expect(content)` 冒充浏览器 E2E（须 `page.goto` + DOM/交互断言）。
- **禁止** 用单个 DetailDrawer 只读骨架代替演示中的 BD预估/红票/可编辑金额等子模块；须遵循 `demo-reference-mandatory-workflow` skill。
- **禁止** 05 无可抽字面量时，用「有 expect 即通过」糊弄 `ac-assertion-binding`；e2e AC 须 `testBlockIsMeaningfulBrowserE2e`（`page.goto` + DOM 断言；`[交互]` 还须真实 click/fill）。
- `[交互]` 且测试类型含 `e2e` 的 AC：对应 test 块须含 `click`/`dblclick`/`fill` 等真实交互（`ac-e2e-depth-AC-xx`），并断言 Drawer/Modal 内业务文案（禁止函数源码泄露到 UI，如 `NTooltip` / `() => h(`）。

## 与 05-验收清单的绑定

1. 每条 AC 的「测试类型」列决定最低层级（`unit`→L1/L2，`e2e`→L3，`visual`→L4）。
2. `tasks.md` 的 Red task 标题须含 `[AC-XX]`，断言文案从 05「验收标准」列复制。
3. P0 AC 至少一条自动化测试（unit/component/e2e）；纯 `manual` 的 P0 须在 deliver 前在 05 标 `已验收` 并注明证据路径。

## UI 类 change 强制规则

- **每个受影响页面**至少 **1 条 E2E**（非单点 smoke）。
- **列表/表格类**：断言列顺序（`nth-child`、`data-column-index` 或表头文案顺序）。
- **文案类**：断言 PRD/05 中的**完整** toast、tooltip、placeholder。
- **弹窗类**：单条/批量模式、保存成功/失败分支均须有 L2 或 L3 覆盖。

## Playwright

- 默认无头；每用例结束截图到 `playwright-pic/<module>/<change>/`。
- change 级 scope 须覆盖 05 中所有 `e2e` 类型 AC。

## TDD Red 阶段

- 先写失败测试，断言来自 `05-验收清单.md`，再写实现。
- 禁止「规则列展示」类模糊断言；须写清「第 N 列」「文案为 XXX」。
