Files
zsp-project/docs/superpowers/specs/2026-04-25-frontend-api-test-infra-design.md
2026-06-03 20:59:39 +08:00

274 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: 前端 API 测试基础设施
description: 为 Vue3+TypeScript 前端建立 Vitest 测试框架Mock Axios 测试 11 个 API 模块
created: 2026-04-25
---
# 前端 API 测试基础设施设计文档
## 一、背景与目标
### 当前状态
- 前端基于 Vue 3 + TypeScript + Vite + Axios
- 11 个 API 模块 (`src/api/*.ts`) 封装 HTTP 请求
- **测试完全缺失**:无 vitest 配置,无 .spec/.test 文件
### 目标
建立前端 API 层测试基础设施,确保:
1. API 请求参数/响应类型正确
2. 错误处理逻辑覆盖
3. 前后端契约一致性验证
4. CI/CD 集成准备
## 二、技术选型
| 项目 | 选择 | 原因 |
|------|------|------|
| 测试框架 | Vitest | Vite 生态原生支持配置简单ESM 原生 |
| Mock 工具 | vi.mock (Vitest 内置) | 无额外依赖Axios mock 简洁 |
| 断言库 | Vitest expect | 内置,支持 TypeScript 类型推断 |
| 覆盖率 | @vitest/coverage-v8 | Istanbul 覆盖率报告 |
## 三、架构设计
### 目录结构
```
frontend/
├── vitest.config.ts # Vitest 配置文件
├── src/api/
│ ├── __tests__/ # API 测试目录
│ │ ├── contract.spec.ts # 合同 API 测试
│ │ ├── zspContract.spec.ts # 中尚鹏合同
│ │ ├── zspFinances.spec.ts # 财务模块
│ │ ├── applyDelivery.spec.ts # 提货申请
│ │ ├── deliveryDetails.spec.ts
│ │ ├── inventory.spec.ts
│ │ ├── ownershipTransfer.spec.ts
│ │ ├── company.spec.ts
│ │ ├── user.spec.ts
│ │ ├── invoice.spec.ts
│ │ ├── settlement.spec.ts
│ │ └── reconciliation.spec.ts
│ └── test-utils.ts # Mock 工具函数
└── package.json # 新增 vitest 相关依赖
```
### Vitest 配置
```typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
plugins: [vue()],
test: {
environment: 'jsdom',
include: ['src/api/__tests__/**/*.spec.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'html'],
include: ['src/api/**/*.ts'],
exclude: ['src/api/__tests__/**', 'src/api/test-utils.ts']
}
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
}
})
```
### Mock 工具函数
```typescript
// src/api/test-utils.ts
import { vi } from 'vitest'
import { http } from '@/utils/http'
/**
* Mock http.request 方法
* @param response 模拟响应数据
* @param status HTTP 状态码 (默认 200)
*/
export function mockHttpRequest(response: any, status = 200) {
vi.spyOn(http, 'request').mockResolvedValue({
success: true,
data: response,
status
})
}
/**
* Mock HTTP 错误响应
* @param message 错误信息
* @param status HTTP 状态码
*/
export function mockHttpError(message: string, status: number) {
vi.spyOn(http, 'request').mockRejectedValue({
success: false,
message,
status
})
}
/**
* 清除所有 mock
*/
export function clearMocks() {
vi.restoreAllMocks()
}
```
## 四、测试模式
每个 API 模块测试遵循统一模式:
### 4.1 请求成功测试
```typescript
describe('getContractList', () => {
it('应返回合同列表', async () => {
const mockData = [{ id: 1, name: '合同1' }]
mockHttpRequest(mockData)
const result = await getContractList()
expect(result.success).toBe(true)
expect(result.data).toEqual(mockData)
})
})
```
### 4.2 参数验证测试
```typescript
it('带 contractType 参数应正确传递', async () => {
mockHttpRequest([])
await getContractList({ contractType: 'business' })
expect(http.request).toHaveBeenCalledWith('get', '/api/contract', {
params: { contractType: 'business' }
})
})
```
### 4.3 错误处理测试
```typescript
describe('错误处理', () => {
it('401 未授权应抛出错误', async () => {
mockHttpError('Unauthorized', 401)
await expect(getContractList()).rejects.toMatchObject({
status: 401
})
})
it('500 服务器错误应抛出错误', async () => {
mockHttpError('Internal Server Error', 500)
await expect(getContractList()).rejects.toMatchObject({
status: 500
})
})
})
```
### 4.4 类型验证
```typescript
it('响应应符合 BusinessContract 类型', async () => {
const mockData: BusinessContract[] = [
{
id: 1,
name: '测试合同',
contractType: 'business',
contractCode: 'C001',
// ... 其他必填字段
}
]
mockHttpRequest(mockData)
const result = await getContractList()
// TypeScript 编译时类型检查,运行时验证结构
expect(result.data[0]).toHaveProperty('id')
expect(result.data[0]).toHaveProperty('name')
})
```
## 五、API 模块测试清单
| 模块 | 文件 | 主要 API 函数 | 预估测试数 |
|------|------|---------------|------------|
| Contract | `contract.spec.ts` | getContractList, getContract, submitContract, batchUploadContracts, updateContract, deleteContract + folders/batches | 15-20 |
| ZSP Contract | `zspContract.spec.ts` | getFolders, getContracts, uploadContract, createDetail, importExcel, exportExcel | 10-15 |
| ZSP Finances | `zspFinances.spec.ts` | CRUD for freight/misc/service/cost/profit | 12-15 |
| Apply Delivery | `applyDelivery.spec.ts` | list, get, create, update, cancel, delete | 10 |
| Delivery Details | `deliveryDetails.spec.ts` | list, get, create, update, delete | 8 |
| Inventory | `inventory.spec.ts` | warehouses, inbound, summary | 8 |
| Ownership Transfer | `ownershipTransfer.spec.ts` | list, get, create, createWithFiles, delete | 8 |
| Company | `company.spec.ts` | folders, files CRUD | 8 |
| User | `user.spec.ts` | login, register, getUser, refreshToken | 8 |
| Invoice | `invoice.spec.ts` | 上游/下游/货代发票 CRUD | 10 |
| Settlement | `settlement.spec.ts` | CRUD | 6 |
| Reconciliation | `reconciliation.spec.ts` | 对账单 CRUD | 6 |
**总计预估90-110 个测试用例**
## 六、执行命令
```bash
# 安装依赖
pnpm add -D vitest @vitest/coverage-v8 jsdom
# 运行测试
pnpm test
# 运行覆盖率
pnpm test:coverage
# 监听模式
pnpm test:watch
```
### package.json 新增脚本
```json
{
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage"
}
}
```
## 七、CI/CD 集成预留
后续可添加 GitHub Actions 或其他 CI 配置:
```yaml
# .github/workflows/test.yml (预留)
- name: Run frontend tests
run: cd frontend && pnpm test:coverage
```
## 八、验收标准
1. 所有 11 个 API 模块有对应 `.spec.ts` 文件
2. 测试覆盖率 > 80%API 模块代码行覆盖)
3. 所有测试通过,无 TypeScript 编译错误
4. `pnpm test` 命令可用
5. 覆盖率报告生成 (`coverage/index.html`)
## 九、后续扩展方向
- 组件测试 (`src/components/`)
- 页面集成测试 (`src/views/`)
- E2E 测试 (Playwright)
- 真实后端集成测试层