版本:4.x (已更新为实际使用的测试框架)
本文档定义了出行服务项目中Taro小程序的测试规范。Taro测试使用独立的测试体系,与主项目的Vitest测试框架分离。
测试框架: Jest + @testing-library/react + 自定义Taro组件mock
测试位置: mini/tests/ 目录
测试范围: 组件测试、页面测试、应用级测试、多端测试
在Taro项目根目录(mini/)下安装测试依赖:
# 进入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
在Taro项目根目录(mini/)添加文件 jest.config.js:
// 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']
}
在 mini/package.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官网。
// 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)
})
})
// 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()
})
})
# 在mini目录下执行
npm run test
对于小程序的测试,我们提供了环境变量对 Jest 环境进行区分:TARO_ENV_JEST,我们可以在调用 jest 测试时设置对应的环境变量
// 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 执行:
if (process.env.TARO_ENV === 'weapp') {
// ....setState(....)
console.log('this is weapp')
}
Taro 组件会根据环境变量渲染不同的标签,例如:
// 在 H5 环境中
<View className="cls">
<Image src="xxx" />
</View>
// 在微信小程序环境中会渲染为
<view class="cls">
<image src="xxx" />
</view>
对于小程序特有的生命周期和 API,我们推荐以下做法:
// 模拟 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
# 在mini目录下执行
cd mini
# 运行所有测试
npm test
# 运行H5环境测试
npm run test:h5
# 运行微信小程序环境测试
npm run test:weapp
# 生成覆盖率报告
npm run test:coverage