# `app-expo` 测试框架规范 ## 目标 测试只解决一件事:阻止高价值回归。 禁止为了覆盖率、形式感或 TDD 仪式感添加低价值测试。 ## 工具链 - 测试框架:`Jest` - 组件测试:`@testing-library/react-native` - Expo 预设:`jest-expo` - E2E:暂不纳入默认门禁,后续如需引入,使用 `Maestro` ## 强制规则 - 必须优先测试高风险代码:有分支、有状态、有环境差异、有回归历史。 - 必须优先写用户可见断言,不写实现细节断言。 - 必须把测试文件放在 `tests/`,禁止放进 Expo Router 的 `app/` 目录。 - 必须让 `react-test-renderer` 与 `react` 主版本严格一致。 - 必须在新增领域逻辑时评估是否加入 `collectCoverageFrom`。 - 必须保证 CI 可重复运行,测试不得依赖本地手工环境。 ## 禁止规则 - 禁止为了凑覆盖率给低价值代码补测试。 - 禁止批量给 `src/components/ui/*` 生成型 wrapper 补测试。 - 禁止测试 `className`、样式细节、第三方库内部实现。 - 禁止默认使用 snapshot。 - 禁止在没有明确回归风险时盲目 TDD。 - 禁止在 CI 中自动更新 snapshot。 ## 测什么 优先级从高到低: 1. 纯逻辑和桥接层 2. 关键页面的关键可见结果 3. 少量高价值主流程 当前门禁覆盖文件: - `src/i18n/index.ts` - `src/constants/theme-bridge.ts` - `src/app/index.tsx` ## 不测什么 默认不测以下内容,除非出现真实回归或明确业务风险: - `src/components/ui/*` - 纯透传组件 - 静态文案和静态布局 - 样式实现细节 - 第三方库已经保证的行为 ## RNTL 规则 - 当前使用 `@testing-library/react-native@13` - 直接使用内置 matcher,例如 `toBeOnTheScreen()` - 不添加 `@testing-library/react-native/extend-expect` - 不引入 `@testing-library/jest-native`,除非现有 matcher 明确不够用 ## TDD 规则 - 新增业务逻辑、修 bug、有明确回归风险时:优先测试先行 - 配置接入、探索性 UI 调整、低风险文案变更:不强制 TDD - 如果代码很难测:先拆耦合,再决定是否写测试 ## Snapshot 规则 默认不用 snapshot。 只有同时满足以下条件才允许: - 组件稳定 - 共享范围广 - 风险来自整体结构而不是交互 - 评审明确同意 否则一律改写为行为断言。 ## 覆盖率规则 覆盖率是门禁,不是目标。 当前阈值: - `branches >= 80` - `functions >= 90` - `lines >= 90` - `statements >= 90` 这些阈值只对 `collectCoverageFrom` 中的高价值文件生效。 新增有分支、状态变化或环境差异的领域逻辑时,评审必须回答一个问题: `这个文件要不要进入 collectCoverageFrom?` ## 本地命令 ```bash npm run test npm run test:changed npm run test:ci npm run test:update ``` 本地约束: - 日常开发优先使用 `npm run test` 或 `npm run test:changed` - 提交前必须至少运行一次 `npm run test:ci` - 只有明确批准时才运行 `npm run test:update` ## CI 门禁 `App Expo Quality` 必须执行: - `npm ci` - `npm run format:check` - `npm run lint` - `npm run test:ci` 同仓 PR 额外要求: - 发布 coverage sticky comment ## E2E 规则 E2E 不是默认门禁。 只有满足以下条件才引入: - 核心用户旅程稳定 - 已明确 smoke flow - 团队能承担维护成本 引入后也只测关键主路径,不做像素巡检,不做大面积 UI 回归脚本。