feat(image): 新建 knowai-core:1.0.0 镜像并完成推送
Some checks reported errors
continuous-integration/drone/push Build was killed
Some checks reported errors
continuous-integration/drone/push Build was killed
- 搭建 api、auth、utils 等逻辑模块 - 通过 tsc、eslint、vitest 测试验证 BREAKING CHANGE: 新镜像分支
This commit is contained in:
334
test/unit/api/modules/user.test.ts
Normal file
334
test/unit/api/modules/user.test.ts
Normal file
@@ -0,0 +1,334 @@
|
||||
/**
|
||||
* 用户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<typeof userApi>;
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user