Files
life-echo/app-expo/docs/testing.md
2026-05-20 10:27:40 +08:00

5.1 KiB
Raw Blame History

app-expo 测试框架规范

目标

测试只解决一件事:阻止高价值回归。

禁止为了覆盖率、形式感或 TDD 仪式感添加低价值测试。

工具链

  • 测试框架:Jest
  • 组件测试:@testing-library/react-native
  • Expo 预设:jest-expo
  • E2E暂不纳入默认门禁后续如需引入使用 Maestro

强制规则

  • 必须优先测试高风险代码:有分支、有状态、有环境差异、有回归历史。
  • 必须优先写用户可见断言,不写实现细节断言。
  • 必须把测试文件放在 tests/,禁止放进 Expo Router 的 app/ 目录。
  • 必须让 react-test-rendererreact 主版本严格一致。
  • 必须在新增领域逻辑时评估是否加入 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

本地命令

npm run test
npm run test:changed
npm run test:ci
npm run test:update

本地约束:

  • 日常开发优先使用 npm run testnpm 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 回归脚本。

前置准备

安装 Maestro CLI

curl -Ls "https://get.maestro.mobile.dev" | bash

构建并安装到目标 iOS Simulator / Android Emulator / 真机。不同 flow 对构建方式的要求不同:

场景 构建命令 读取配置
普通开发 pnpm ios / pnpm android env/development
需要登录态的 E2E pnpm ios:e2e / pnpm android:e2e .env.e2estaging backend + E2E 开关)

正常 staging 构建继续使用 env/staginguse-env staging),不注入 EXPO_PUBLIC_E2E

现有 flow

Flow 文件 用途 需要后端 需要 E2E 构建
login-smoke.yaml 登录页协议拦截 smoke验证 App 启动到未登录态
login-authenticated.yaml 快捷登录进入已登录态
post-login-tabs-smoke.yaml 登录后 Tab 导航 smoke对话 → 回忆录 → 我的 → 对话)
post-login-long-chat.yaml 登录后发送大量对话消息,为回忆录生成提供种子数据

运行命令

无后端依赖(普通构建即可):

pnpm e2e:ios
pnpm e2e:android

需要 E2E 构建 + 后端 mock 登录:

pnpm e2e:auth:ios
pnpm e2e:auth:android
pnpm e2e:post-login:ios
pnpm e2e:long-chat:ios

调试时可通过 pnpm start:e2e 启动 dev server 并自动加载 .env.e2e

登录后 E2E 环境要求

  • 后端:APP_ENV 不能是 production,并开启 MOCK_SMS_LOGIN_ENABLED=1
  • App通过 pnpm ios:e2e / pnpm android:e2e 构建安装,读取 .env.e2e
  • 所有需要登录态的 flow 通过点击 login.e2e.quickLogin.button 进入已登录态