TESTING.md — Agentaily Design System
本仓库怎么测、什么在哪测、以及护栏。这是一个以展示型组件为主的组件库,所以它的测试姿态刻意 不同于逻辑密集的产品 —— 先读「理念」,它解释了为什么这里是 30 个测试而不是 3000 个。
理念 —— 测逻辑,不测展示
这里约 115 个组件直接在本仓维护(.jsx + .d.ts + .prompt.md + 一份 .stories.jsx)。绝大多数是 展示型的 —— 接收 props、渲染 token。对这些组件,「能不能渲染 / 两种主题下读起来对不对」已经被以下两项覆盖:
npm run build:lib—— ESM 库构建(抓出坏掉的 export/import),以及npm run build-storybook+ 在paper(亮色) 和ink(暗色) 下肉眼过一遍 Storybook。
单元测试只留给那种带真实、危险逻辑的稀有原语 —— 一个 parser、一个 XSS 净化器、一个有状态的 headless hook (useForm / useAuth / useQueue)、派生计算。这些有肉眼无法穷尽捕捉的失败模式(安全漏洞、边界输入下崩溃)。 别给展示型镜像组件写单元测试 —— 除了「它能渲染」之外没什么可断言的,而构建 + Storybook 已经证明了这一点。
第一个(也是目前唯一一个)够格拥有测试套件的组件是 <Markdown> (src/components/chat/Markdown.jsx):markdown → React-node 解析、URL scheme 净化、以及流式半截容错。它的失败模式是 安全(javascript: / data: href 注入、原始 HTML 注入)与 崩溃(半截流入的 ** / 代码围栏 / 表格在流式途中抛错)。
这个套件正是
.claude/agents/README.md里那条预言的兑现: 「如果这个仓库哪天长出了真正的逻辑层…… 届时再重引implementer+ 一道 单元测试 gate 和一份TESTING.md。」<Markdown>就是那个时刻。
分层(各层测什么)
| 层 | 状态 | 工具 | 覆盖什么 |
|---|---|---|---|
| Unit | 现在 | vitest + @testing-library/react + jsdom | 带逻辑的原语:解析、净化、流式容错、有状态 hook 的状态转移。 |
| 视觉回归 | 以后 | 复用约 120 个 stories + Storybook test-runner / Chromatic | 跨 paper + ink 的逐组件像素 / diff。 |
| 交互 | 以后 | Storybook play() + @storybook/test-runner | 键盘 / 焦点 / 开合流程,由既有 stories 驱动。 |
| a11y | 以后 | 经 test-runner 跑 axe | 角色、标签、对比度。 |
目前只接通了 Unit 这一层;其余刻意延后(stories 已经存在,是它们天然的底座)。等真有需要时再加,别 预先铺设。
护栏(硬规则)
- 测试与组件分开放 —— 永远放
tests/。 绝不把测试文件放在src/components/**旁边或里面。把测试 留在tests/让它们与组件树解耦。vitest.config.js只采集tests/**/*.test.{js,jsx}。 - 展示型组件上一个失败的测试,是一个契约信号。 如果某个单元测试证明了一个组件有真 bug,就在本仓 修组件、让测试保持绿。测试的职责是 钉住契约。
- 断言行为 / 契约,别断言快照琐碎。 经
@testing-library/react查询 DOM 结构、 角色、属性、转义。别用 DOM 快照 —— 它们在外观微调时就破、什么有意义的东西都钉不住。覆盖 危险边界(XSS、半截输入崩溃),而不只是 happy path。 - 绝不跑全仓 prettier。 lefthook 只格式化暂存文件。
怎么跑
npm test # vitest run —— CI / pre-push 这道 gate
npm run test:watch # vitest watch —— 本地内环 TDD(红 → 绿 → 重构)「done」gate(针对逻辑改动)
一处碰到带逻辑代码的改动,当三项全绿时才算 done:
npm test # 单元 gate —— vitest
npm run build:lib # ESM 库构建 —— 抓坏掉的 export/import
npm run build-storybook # 静态 Storybook —— 抓坏掉的 stories此外,对任何组件改动,两种主题下肉眼过一遍 Storybook、以及 .claude/agents/README.md 里描述的 文档 / 计数同步,仍然适用。npm test 也会在 pre-push(lefthook)时连同 build:lib 自动跑。
谁来驱动
implementer agent 负责内环单元测试循环(写失败测试、转绿、重构 —— 同一只手),严格限定在 tests/ 内。 reviewer 独立复核测试质量与安全契约。 完整角色名册见 .claude/agents/README.md。