/** * 用户API模块测试 * 测试用户相关的API调用,包括登录、注册、刷新令牌、获取/更新用户档案、关注/取消关注用户等功能 */ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { userApi } from '@/api/modules/user'; import { createMockAxios } from '@/test/mocks/http-client'; import { createMockUser, createMockUserProfile } from '@/test/mocks/data-factory'; import type { ApiClient } from '@/api/client'; import type { LoginRequest, LoginResponse, RegisterRequest, RegisterResponse, RefreshTokenRequest, RefreshTokenResponse, UserProfileUpdateRequest, UserProfileUpdateResponse, UserFollowRequest, UserFollowResponse } from '@/types/user'; describe('用户API模块', () => { let mockClient: ApiClient; let userApiInstance: ReturnType; beforeEach(() => { // 创建模拟的API客户端 mockClient = { get: vi.fn(), post: vi.fn(), put: vi.fn(), delete: vi.fn(), patch: vi.fn(), request: vi.fn(), getWithResponse: vi.fn(), postWithResponse: vi.fn(), putWithResponse: vi.fn(), deleteWithResponse: vi.fn(), patchWithResponse: vi.fn(), requestWithResponse: vi.fn(), addRequestInterceptor: vi.fn(), addResponseInterceptor: vi.fn(), removeRequestInterceptor: vi.fn(), removeResponseInterceptor: vi.fn(), setDefaults: vi.fn(), setBaseURL: vi.fn(), createInstance: vi.fn(), } as unknown as ApiClient; // 创建用户API实例 userApiInstance = userApi(mockClient); }); describe('用户登录功能', () => { it('应该能够成功登录', async () => { const loginRequest: LoginRequest = { username: 'test@example.com', password: 'password123' }; const mockUser = createMockUser({ username: loginRequest.username }); const mockResponse: LoginResponse = { user: mockUser, sessionId: 'session-123' }; mockClient.post.mockResolvedValue(mockResponse); const result = await userApiInstance.login(loginRequest); expect(mockClient.post).toHaveBeenCalledWith('/auth/login', loginRequest); expect(result).toEqual(mockResponse); }); it('应该处理登录失败的情况', async () => { const loginRequest: LoginRequest = { username: 'wrong@example.com', password: 'wrongpassword' }; const errorResponse = { success: false, data: null, message: '用户名或密码错误', code: 401 }; mockClient.post.mockRejectedValue(errorResponse); await expect(userApiInstance.login(loginRequest)).rejects.toEqual(errorResponse); expect(mockClient.post).toHaveBeenCalledWith('/auth/login', loginRequest); }); }); describe('用户注册功能', () => { it('应该能够成功注册', async () => { const registerRequest: RegisterRequest = { username: 'newuser', email: 'newuser@example.com', password: 'password123' }; const mockUser = createMockUser({ username: registerRequest.username, email: registerRequest.email }); const mockResponse: RegisterResponse = { user: mockUser, sessionId: 'session-456' }; mockClient.post.mockResolvedValue(mockResponse); const result = await userApiInstance.register(registerRequest); expect(mockClient.post).toHaveBeenCalledWith('/auth/register', registerRequest); expect(result).toEqual(mockResponse); }); it('应该处理注册失败的情况', async () => { const registerRequest: RegisterRequest = { username: '', email: 'invalid-email', password: '123' // 密码太短 }; const errorResponse = { success: false, data: null, message: '用户名不能为空,邮箱格式不正确,密码长度至少为6位', code: 400 }; mockClient.post.mockRejectedValue(errorResponse); await expect(userApiInstance.register(registerRequest)).rejects.toEqual(errorResponse); expect(mockClient.post).toHaveBeenCalledWith('/auth/register', registerRequest); }); }); describe('刷新令牌功能', () => { it('应该能够成功刷新令牌', async () => { const refreshTokenRequest: RefreshTokenRequest = { sessionId: 'session-456' }; const mockResponse: RefreshTokenResponse = { sessionId: 'new-session-789' }; mockClient.post.mockResolvedValue(mockResponse); const result = await userApiInstance.refreshToken(refreshTokenRequest); expect(mockClient.post).toHaveBeenCalledWith('/auth/refresh', refreshTokenRequest); expect(result).toEqual(mockResponse); }); it('应该处理刷新令牌失败的情况', async () => { const refreshTokenRequest: RefreshTokenRequest = { sessionId: 'invalid-session' }; const errorResponse = { success: false, data: null, message: '会话无效或已过期', code: 401 }; mockClient.post.mockRejectedValue(errorResponse); await expect(userApiInstance.refreshToken(refreshTokenRequest)).rejects.toEqual(errorResponse); expect(mockClient.post).toHaveBeenCalledWith('/auth/refresh', refreshTokenRequest); }); }); describe('获取用户档案功能', () => { it('应该能够获取用户档案', async () => { const mockUserProfile = createMockUserProfile(); const mockResponse: UserProfileUpdateResponse = { success: true, data: mockUserProfile, message: '获取用户档案成功', code: 200 }; mockClient.get.mockResolvedValue(mockResponse); const result = await userApiInstance.getProfile(); expect(mockClient.get).toHaveBeenCalledWith('/user/profile'); expect(result).toEqual(mockResponse); }); it('应该处理获取用户档案失败的情况', async () => { const errorResponse = { success: false, data: null, message: '用户未登录', code: 401 }; mockClient.get.mockRejectedValue(errorResponse); await expect(userApiInstance.getProfile()).rejects.toEqual(errorResponse); expect(mockClient.get).toHaveBeenCalledWith('/user/profile'); }); }); describe('更新用户档案功能', () => { it('应该能够更新用户档案', async () => { const updateRequest: UserProfileUpdateRequest = { username: 'updateduser', bio: '这是我的个人简介', avatar: 'https://example.com/avatar.jpg' }; const mockUserProfile = createMockUserProfile(updateRequest); const mockResponse: UserProfileUpdateResponse = { success: true, data: mockUserProfile, message: '用户档案更新成功', code: 200 }; mockClient.put.mockResolvedValue(mockResponse); const result = await userApiInstance.updateProfile(updateRequest); expect(mockClient.put).toHaveBeenCalledWith('/user/profile', updateRequest); expect(result).toEqual(mockResponse); }); it('应该处理更新用户档案失败的情况', async () => { const updateRequest: UserProfileUpdateRequest = { username: '', // 用户名不能为空 bio: '', avatar: '' }; const errorResponse = { success: false, data: null, message: '用户名不能为空', code: 400 }; mockClient.put.mockRejectedValue(errorResponse); await expect(userApiInstance.updateProfile(updateRequest)).rejects.toEqual(errorResponse); expect(mockClient.put).toHaveBeenCalledWith('/user/profile', updateRequest); }); }); describe('关注用户功能', () => { it('应该能够关注用户', async () => { const followRequest: UserFollowRequest = { userId: 'user-123' }; const mockResponse: UserFollowResponse = { success: true, data: { isFollowing: true, followersCount: 101 }, message: '关注成功', code: 200 }; mockClient.put.mockResolvedValue(mockResponse); const result = await userApiInstance.followUser(followRequest); expect(mockClient.put).toHaveBeenCalledWith('/user/follow/user-123'); expect(result).toEqual(mockResponse); }); it('应该处理关注不存在的用户的情况', async () => { const followRequest: UserFollowRequest = { userId: 'non-existent-user' }; const errorResponse = { success: false, data: null, message: '用户不存在', code: 404 }; mockClient.put.mockRejectedValue(errorResponse); await expect(userApiInstance.followUser(followRequest)).rejects.toEqual(errorResponse); expect(mockClient.put).toHaveBeenCalledWith('/user/follow/non-existent-user'); }); }); describe('取消关注用户功能', () => { it('应该能够取消关注用户', async () => { const unfollowRequest: UserFollowRequest = { userId: 'user-123' }; const mockResponse: UserFollowResponse = { success: true, data: { isFollowing: false, followersCount: 99 }, message: '取消关注成功', code: 200 }; mockClient.delete.mockResolvedValue(mockResponse); const result = await userApiInstance.unfollowUser(unfollowRequest); expect(mockClient.delete).toHaveBeenCalledWith('/user/follow/user-123'); expect(result).toEqual(mockResponse); }); it('应该处理取消关注不存在的用户的情况', async () => { const unfollowRequest: UserFollowRequest = { userId: 'non-existent-user' }; const errorResponse = { success: false, data: null, message: '用户不存在', code: 404 }; mockClient.delete.mockRejectedValue(errorResponse); await expect(userApiInstance.unfollowUser(unfollowRequest)).rejects.toEqual(errorResponse); expect(mockClient.delete).toHaveBeenCalledWith('/user/follow/non-existent-user'); }); }); });