# 测试模式

**分析日期：** 2026-05-07

## 测试框架

**当前状态：** 未检测到测试基础设施

- **运行器：** 未配置（package.json 中无 Jest、Vitest、Playwright 等依赖）
- **断言库：** 未配置
- **测试脚本：** 未在 package.json 中定义（仅有 `dev`、`build`、`start`、`lint`）

## 测试文件组织

**当前：** 无测试文件

项目中未发现 `*.test.ts`、`*.test.tsx`、`*.spec.ts`、`*.spec.tsx`、`__tests__/` 目录等标准测试文件结构。

## 测试覆盖

**要求：** 未强制

**影响：**
- 新增代码（尤其是 API 集成、表单验证、权限逻辑）缺乏自动化验证
- 技术债风险：`next.config.mjs` 中 `typescript.ignoreBuildErrors: true` 和 `eslint.ignoreDuringBuilds: true`，导致构建时不检查类型和 lint 错误
- 手动测试依赖性高

## 关键需要测试的区域

### API 集成层
**位置：** `lib/api/*.ts`

**建议测试：**
- 认证流程（`emailLogin`、`saveAuthToken`、`logout`）
- API 请求拦截器（token 注入、过期处理）
- 响应拦截器（401 处理、重定向）
- 数据适配器（如 `mapBackendOutfit()` 将后端结构映射到前端类型）
- 错误处理（`handleApiException`、`handleApiRequest` 的成功/失败路径）

**示例测试需求：**
```typescript
// 应测试：token 自动注入
test('请求拦截器应在请求头中添加 Bearer token', () => {
  // 前置条件：localStorage 中有 auth_token
  // 发送 API 请求
  // 验证：Authorization 头包含 "Bearer <token>"
})

// 应测试：401 处理
test('响应拦截器应在收到 401 时清除 token 并重定向到登录', () => {
  // 前置条件：发送请求后服务器返回 401
  // 验证：localStorage 中 auth_token 被移除
  // 验证：浏览器重定向到 /login
})

// 应测试：数据适配
test('mapBackendOutfit 应正确转换后端服装数据', () => {
  const backendData = { id: 1, name: '测试服装', image_url: '...' }
  const result = mapBackendOutfit(backendData)
  expect(result).toHaveProperty('imageUrl') // 字段映射
  expect(result.id).toBe('1') // 类型转换
})
```

### 权限控制
**位置：** `lib/permissions.ts`

**建议测试：**
- `hasPermission(module)` 根据用户角色返回正确的权限
- `getUserRole()` 从 localStorage 获取当前角色
- `getModuleFromPath(pathname)` 正确提取路径中的模块
- `hasPathPermission(pathname)` 组合权限检查

**示例测试需求：**
```typescript
test('超级管理员应有所有模块的权限', () => {
  // 前置：localStorage.user_role = '超级管理员'
  // 验证：hasPermission('users') === true
  // 验证：hasPermission('ai-model') === true
  // 等等所有模块
})

test('内容管理员应无权限访问用户管理', () => {
  // 前置：localStorage.user_role = '内容管理员'
  // 验证：hasPermission('users') === false
  // 验证：hasPermission('outfits') === true
})
```

### 表单验证与提交
**位置：** `components/*/add-*-dialog.tsx`、`app/*/page.tsx`

**当前模式：**
- 使用 `useState` 管理表单状态
- 基本的非空检查（如 `if (!formData.name || !formData.description)` 在 `add-achievement-dialog.tsx`）
- 客户端验证不完整

**建议测试：**
- 必填字段验证（空值拒绝）
- 表单提交成功调用正确的 API
- 提交过程中加载状态变化（`isSubmitting`）
- 表单重置（关闭后清空状态）
- 错误显示（API 失败时显示 toast）

**示例测试需求：**
```typescript
test('添加服装对话框应在名称为空时禁用提交', () => {
  // 渲染 AddOutfitDialog
  // 验证：提交按钮禁用状态
})

test('提交表单应调用 createOutfit API', () => {
  // 填写表单字段
  // 点击提交
  // 验证：createOutfit 被调用，参数正确
})
```

### 组件交互
**位置：** `components/`

**建议测试：**
- 对话框打开/关闭状态
- 模态框表单的步骤导航（`step` 状态变化）
- 确认对话框的确认/取消操作
- 列表分页和搜索

**示例测试需求：**
```typescript
test('AddOutfitDialog 应在提交后关闭', () => {
  // 渲染对话框
  // 填写并提交表单
  // 验证：对话框关闭（open === false）
})

test('多步表单应在点击"下一步"时更新步骤', () => {
  // 验证：初始 step === 1
  // 点击"下一步"按钮
  // 验证：step === 2
})
```

### 中间件和路由保护
**位置：** `middleware.ts`

**建议测试：**
- 无 token 访问受保护路由时重定向到 `/login`
- 有 token 时允许访问受保护路由
- 公共路由（登录、注册）不需要 token

**示例测试需求：**
```typescript
test('中间件应将无 token 的请求重定向到登录', () => {
  // 模拟请求：GET /outfits，无 auth_token cookie
  // 验证：重定向到 /login?callbackUrl=/outfits
})

test('中间件应允许有 token 的请求', () => {
  // 模拟请求：GET /users，包含有效 auth_token cookie
  // 验证：通过，继续处理
})
```

## 建议的测试设置

### 推荐框架组合

**单元/集成测试：**
- **运行器：** Vitest（与 Next.js 15 兼容，开发体验优于 Jest）
- **断言：** Vitest 内置（或 @testing-library/jest-dom）
- **Mock 库：** vitest 的 `vi` 模块或 `@testing-library/react`

**E2E 测试（可选）：**
- **框架：** Playwright 或 Cypress
- **用途：** 完整登录流、权限控制、多步表单

### 安装建议

```bash
# 安装 Vitest 和相关工具
npm install -D vitest @vitest/ui @testing-library/react @testing-library/jest-dom

# 创建配置文件 vitest.config.ts
```

### 最小化配置示例

```typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
import path from 'path'

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./test/setup.ts'],
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, '.'),
    },
  },
})

// test/setup.ts
import '@testing-library/jest-dom'
```

### package.json 脚本建议

```json
{
  "scripts": {
    "test": "vitest",
    "test:ui": "vitest --ui",
    "test:coverage": "vitest --coverage",
    "test:run": "vitest run"
  }
}
```

## 测试文件结构建议

```
project-root/
├── lib/
│   ├── api/
│   │   ├── auth.ts
│   │   ├── auth.test.ts          # API 认证测试
│   │   ├── outfits.ts
│   │   ├── outfits.test.ts       # API 服装测试
│   │   └── ...
│   ├── permissions.ts
│   └── permissions.test.ts        # 权限逻辑测试
├── components/
│   ├── add-outfit-dialog.tsx
│   ├── add-outfit-dialog.test.tsx # 组件交互测试
│   └── ...
├── app/
│   ├── login/
│   │   ├── page.tsx
│   │   └── page.test.tsx          # 登录页测试
│   └── ...
├── test/
│   ├── setup.ts                   # 测试环境初始化
│   ├── mocks/
│   │   ├── handlers.ts            # MSW 请求拦截器
│   │   └── server.ts              # MSW 服务器配置
│   └── fixtures/
│       ├── auth.fixture.ts        # 认证数据 fixtures
│       └── outfits.fixture.ts     # 服装数据 fixtures
└── vitest.config.ts
```

## 当前缺失的覆盖范围

**高优先级（生产关键）：**
- ✗ API 集成和数据适配
- ✗ 认证流程（登录、token 管理、登出）
- ✗ 权限检查和路由保护
- ✗ 表单验证和提交

**中优先级（功能完整性）：**
- ✗ 错误处理和用户通知
- ✗ 组件交互（对话框、模态框）
- ✗ 列表管理（分页、搜索）

**低优先级（UX 细节）：**
- ✗ 样式和响应性
- ✗ 无障碍访问 (a11y)

---

*测试分析日期：2026-05-07*

**关键建议：** 该项目缺乏测试基础设施，强烈建议在新增核心功能（特别是认证、权限、API 集成）时同步添加测试。考虑从 API 层和权限控制开始，这些是最容易产生 bug 的关键区域。
