--- 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) - 真实后端集成测试层