# Taro小程序测试规范

版本：4.x

## 概述

本文档定义了出行服务项目中Taro小程序的测试规范。Taro测试使用独立的测试体系，与主项目的Vitest测试框架分离。

**测试框架**: Jest + @tarojs/test-utils-react
**测试位置**: `mini/tests/` 目录
**测试范围**: 组件测试、页面测试、应用级测试、多端测试

## 安装

在Taro项目根目录（mini/）下安装测试依赖：

```bash
# 进入mini目录
cd mini

# React:
npm i @tarojs/test-utils-react --save
# 安装Jest
npm i jest --save
```

**注意**: @tarojs/plugin-platform-h5为前置 peerDependencies，请勿删除该依赖申明

## 配置

### Jest配置
在Taro项目根目录（mini/）添加文件 `jest.config.js`：

```javascript
// mini/jest.config.js
const defineJestConfig = require('@tarojs/test-utils-react/dist/jest.js').default

module.exports = defineJestConfig({
  testEnvironment: 'jsdom',
  testMatch: ['<rootDir>/tests/**/*.test.{js,ts,tsx}'],
  collectCoverageFrom: [
    'src/**/*.{ts,tsx}',
    '!src/**/*.d.ts',
    '!src/app.tsx',
    '!src/app.config.ts'
  ],
  coverageDirectory: 'coverage',
  coverageReporters: ['text', 'lcov', 'html'],
  setupFilesAfterEnv: ['<rootDir>/tests/setup.ts']
})
```

### package.json脚本配置
在 `mini/package.json` 中添加测试脚本：

```json
{
  "scripts": {
    "test": "jest",
    "test:h5": "export TARO_ENV_JEST=h5 && jest",
    "test:weapp": "export TARO_ENV_JEST=weapp && jest",
    "test:coverage": "jest --coverage"
  }
}
```

`defineJestConfig` 已内置了部分初始化配置，需要修改可自行配置覆盖。配置文件参考 [Jest官网](https://jestjs.io/docs/configuration)。

编写测试用例
组件级别
// __test__/main/index.test.js
import TestUtils from '@tarojs/test-utils-react'
import Hello from '../../src/components/Hello.tsx'
const testUtils = new TestUtils()
describe('App', () => {
  it('RenderComponent', async () => {
    // React跟Vue相同用法
    await testUtils.mount(Hello, {
      props: {
        // 配置项
        a: 1,
      },
    })
    // 等待页面出现.btn这个节点
    const btn = await testUtils.queries.waitForQuerySelector('.btn')
    // 等待react的渲染更新完成
    await testUtils.act(() => {
      // 触发点击事件
      testUtils.fireEvent.click(btn)
    })
    // 打印渲染结果
    expect(testUtils.html()).toMatchSnapshot()
    // <div class="hello">...
  })
})

运行测试
# package.json
# scripts: {
#   "test": "jest",
# }
npm run test

应用级别
// __test__/main/index.test.js
import TestUtils from '@tarojs/test-utils-react'
import Taro from '@tarojs/taro'
import App from '../../src/app.ts'
const testUtils = new TestUtils()
describe('App', () => {
  it('RenderApp', async () => {
    await testUtils.createApp()
    // 监听/pages/index/index这个页面路由的onShow生命周期触发
    await testUtils.PageLifecycle.onShow('/pages/index/index')
    // 跳转到第二个页面
    Taro.navigateTo({ url: '/pages/second/index' })
    // 监听/pages/second/index这个页面路由的onShow生命周期触发
    await testUtils.PageLifecycle.onShow('/pages/second/index')
    // 当/pages/second/index触发onShow后，打印页面内容
    expect(testUtils.html()).toMatchSnapshot()
    // <body><div class="taro_router" id="app">...
  })
})

多端
对于小程序的测试，我们提供了环境变量对 Jest 环境进行区分：TARO_ENV_JEST，我们可以在调用 jest 测试时设置对应的环境变量

// package.json
scripts: {
  "test": "jest",
   "test:weapp": "export TARO_ENV_JEST=weapp && jest"
}

这里会有几点差异：

环境差异
这里会将运行代码中的process.env.TARO_ENV切换为TARO_ENV_JEST的值，主要用于一些"环境判断"比如下面的代码将会在test:weapp执行:

if (process.env.TARO_ENV === 'weapp') {
  // ....setState(....)
  console.log('this is weapp')
}

标签差异
除此之外html()输出的节点内容也会改变，将以小程序标签的形式输出，例如:

<!-- h5 -->
<taro-core-view className="cls">
  <taro-image-view src="xxx">
    <img src="xxx" />
  </taro-image-view>
</taro-core-view>

<!-- weapp -->
<view className="cls">
  <image src="xxx" />
</view>

因为这是一个在线运行的测试工具，主要目的也是对用户行为和外部表现进行测试断言，在测试环境使用的还是以 h5 的形式来模拟整个程序的运行，对于其他小程序特有的生命周期和 API，我们推荐以下做法：

生命周期： 使用PageLifecycle的triggerXxxxx进行生命周期的触发
API： 使用jest提供的mock方法来模拟@tarojs/taro的 api，模拟小程序的返回值

## 项目特定测试指导

### 测试目录结构
```
mini/
├── tests/
│   ├── setup.ts                    # 测试设置文件
│   ├── components/                 # 组件测试
│   │   ├── ui/                    # UI组件测试
│   │   │   ├── button.test.tsx
│   │   │   ├── form.test.tsx
│   │   │   └── tab-bar.test.tsx
│   ├── pages/                      # 页面测试
│   │   ├── index.test.tsx         # 首页测试
│   │   ├── login.test.tsx         # 登录页测试
│   │   ├── profile.test.tsx       # 个人中心测试
│   │   └── explore.test.tsx       # 探索页测试
│   └── utils/                      # 工具函数测试
│       ├── auth.test.ts
│       └── minio.test.ts
```

### 测试覆盖率目标
- **组件测试**: ≥ 70%
- **页面测试**: ≥ 60%
- **工具函数**: ≥ 80%
- **关键业务逻辑**: 100%

### 测试执行
```bash
# 在mini目录下执行
cd mini

# 运行所有测试
npm test

# 运行H5环境测试
npm run test:h5

# 运行微信小程序环境测试
npm run test:weapp

# 生成覆盖率报告
npm run test:coverage
```

### 与主项目的关系
- Taro测试体系完全独立于主项目的Vitest测试
- 两者使用不同的测试框架和配置
- 测试执行需要分别进入对应目录
- CI/CD流水线需要分别配置两个项目的测试任务