# Taro小程序测试规范

版本：4.x (已更新为实际使用的测试框架)

## 概述

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

**测试框架**: Jest + @testing-library/react + 自定义Taro组件mock
**测试位置**: `mini/tests/` 目录
**测试范围**: 组件测试、页面测试、应用级测试、多端测试

## 安装

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

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

# 安装测试框架
npm i jest @testing-library/react @testing-library/jest-dom --save-dev
npm i @types/jest jest-environment-jsdom ts-jest --save-dev
```

**注意**: Taro 4 项目使用 Jest + @testing-library/react 进行测试，无需安装 @tarojs/test-utils-react

## 配置

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

```javascript
// mini/jest.config.js
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/tests/setup.ts'],
  moduleNameMapping: {
    '^@/(.*)$': '<rootDir>/src/$1',
    '\.(css|less|scss|sass)$': 'identity-obj-proxy',
    '\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
      '<rootDir>/tests/__mocks__/fileMock.js'
  },
  testMatch: [
    '<rootDir>/tests/**/*.spec.{ts,tsx}',
    '<rootDir>/tests/**/*.test.{ts,tsx}'
  ],
  collectCoverageFrom: [
    'src/**/*.{ts,tsx}',
    '!src/**/*.d.ts',
    '!src/**/index.{ts,tsx}',
    '!src/**/*.stories.{ts,tsx}'
  ],
  coverageDirectory: 'coverage',
  coverageReporters: ['text', 'lcov', 'html'],
  testPathIgnorePatterns: [
    '/node_modules/',
    '/dist/',
    '/coverage/'
  ],
  transform: {
    '^.+\\.(ts|tsx)$': 'babel-jest',
    '^.+\\.(js|jsx)$': 'babel-jest'
  },
  transformIgnorePatterns: [
    '/node_modules/(?!(swiper|@tarojs)/)'
  ],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json']
}
```

### 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"
  }
}
```

配置文件参考 [Jest官网](https://jestjs.io/docs/configuration)。

## 编写测试用例

### 组件级别测试
```typescript
// tests/components/button.test.tsx
import { render, screen, fireEvent } from '@testing-library/react'
import Button from '../../src/components/Button'

describe('Button Component', () => {
  it('应该渲染按钮并响应点击事件', () => {
    const handleClick = jest.fn()

    render(<Button onClick={handleClick}>点击我</Button>)

    const button = screen.getByRole('button', { name: '点击我' })
    expect(button).toBeInTheDocument()

    fireEvent.click(button)
    expect(handleClick).toHaveBeenCalledTimes(1)
  })
})
```

### 页面级别测试
```typescript
// tests/pages/index.test.tsx
import { render, screen } from '@testing-library/react'
import Index from '../../src/pages/index'

describe('Index Page', () => {
  it('应该渲染首页内容', () => {
    render(<Index />)

    expect(screen.getByText('欢迎使用出行服务')).toBeInTheDocument()
    expect(screen.getByRole('button', { name: '开始使用' })).toBeInTheDocument()
  })
})
```

### 运行测试
```bash
# 在mini目录下执行
npm run test
```

## 多端测试

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

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

这里会有几点差异：

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

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

### 标签差异
Taro 组件会根据环境变量渲染不同的标签，例如：

```typescript
// 在 H5 环境中
<View className="cls">
  <Image src="xxx" />
</View>

// 在微信小程序环境中会渲染为
<view class="cls">
  <image src="xxx" />
</view>
```

### 模拟小程序 API
对于小程序特有的生命周期和 API，我们推荐以下做法：

```typescript
// 模拟 Taro API
jest.mock('@tarojs/taro', () => ({
  navigateTo: jest.fn(),
  request: jest.fn(),
  getStorage: jest.fn(),
  setStorage: jest.fn(),
}))

// 在测试中使用模拟的 API
import Taro from '@tarojs/taro'

describe('小程序功能', () => {
  it('应该调用导航API', () => {
    Taro.navigateTo({ url: '/pages/index' })
    expect(Taro.navigateTo).toHaveBeenCalledWith({ url: '/pages/index' })
  })
})
```

## 项目特定测试指导

### 测试目录结构
```
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流水线需要分别配置两个项目的测试任务