Files
knowai/test/unit/api/modules/post.test.ts
tobegold574 6a81b7bb13
Some checks reported errors
continuous-integration/drone/push Build was killed
feat(image): 新建 knowai-core:1.0.0 镜像并完成推送
- 搭建 api、auth、utils 等逻辑模块
- 通过 tsc、eslint、vitest 测试验证

BREAKING CHANGE: 新镜像分支
2025-11-10 20:20:25 +08:00

408 lines
12 KiB
TypeScript
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.

/**
* 帖子API模块测试
* 测试帖子相关的API调用包括创建帖子、获取帖子列表、点赞、评论等功能
*/
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { postApi } from '@/api/modules/post';
import { createMockAxios } from '@/test/mocks/http-client';
import {
createMockPost,
createMockUser,
createMockPostComment
} from '@/test/mocks/data-factory';
import type { ApiClient } from '@/api/client';
import type {
CreatePostRequest,
CreatePostResponse,
GetPostsRequest,
GetPostsResponse,
GetPostRequest,
GetPostResponse,
LikePostRequest,
LikePostResponse,
BookmarkPostRequest,
BookmarkPostResponse,
CreateCommentRequest,
CreateCommentResponse,
GetCommentsRequest,
GetCommentsResponse,
LikeCommentRequest,
LikeCommentResponse
} from '@/types/post/api';
describe('帖子API模块', () => {
let mockClient: ApiClient;
let postApiInstance: ReturnType<typeof postApi>;
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实例
postApiInstance = postApi(mockClient);
});
describe('创建帖子功能', () => {
it('应该能够创建新帖子', async () => {
const createRequest: CreatePostRequest = {
title: '测试帖子标题',
content: '这是一个测试帖子的内容',
tags: ['测试', 'API'],
isPublic: true
};
const mockPost = createMockPost({
title: createRequest.title,
content: createRequest.content,
tags: createRequest.tags
});
const mockResponse: CreatePostResponse = {
success: true,
data: mockPost,
message: '帖子创建成功',
code: 201
};
mockClient.post.mockResolvedValue(mockResponse);
const result = await postApiInstance.createPost(createRequest);
expect(mockClient.post).toHaveBeenCalledWith('/posts', createRequest);
expect(result).toEqual(mockResponse);
});
it('应该处理创建帖子失败的情况', async () => {
const createRequest: CreatePostRequest = {
title: '',
content: '',
tags: [],
isPublic: true
};
const errorResponse = {
success: false,
data: null,
message: '标题和内容不能为空',
code: 400
};
mockClient.post.mockRejectedValue(errorResponse);
await expect(postApiInstance.createPost(createRequest)).rejects.toEqual(errorResponse);
expect(mockClient.post).toHaveBeenCalledWith('/posts', createRequest);
});
});
describe('获取帖子列表功能', () => {
it('应该能够获取帖子列表', async () => {
const getRequest: GetPostsRequest = {
page: 1,
limit: 10,
tag: '测试'
};
const mockPosts = [
createMockPost({ id: 'post-1' }),
createMockPost({ id: 'post-2' })
];
const mockResponse: GetPostsResponse = {
success: true,
data: {
posts: mockPosts,
pagination: {
page: 1,
limit: 10,
total: 100,
totalPages: 10
}
},
message: '获取帖子列表成功',
code: 200
};
mockClient.get.mockResolvedValue(mockResponse);
const result = await postApiInstance.getPosts(getRequest);
expect(mockClient.get).toHaveBeenCalledWith('/posts', { params: getRequest });
expect(result).toEqual(mockResponse);
});
it('应该处理获取帖子列表失败的情况', async () => {
const getRequest: GetPostsRequest = {
page: -1, // 无效的页码
limit: 10
};
const errorResponse = {
success: false,
data: null,
message: '页码必须大于0',
code: 400
};
mockClient.get.mockRejectedValue(errorResponse);
await expect(postApiInstance.getPosts(getRequest)).rejects.toEqual(errorResponse);
expect(mockClient.get).toHaveBeenCalledWith('/posts', { params: getRequest });
});
});
describe('获取帖子详情功能', () => {
it('应该能够获取帖子详情', async () => {
const getRequest: GetPostRequest = { postId: 'post-123' };
const mockPost = createMockPost({ id: 'post-123' });
const mockResponse: GetPostResponse = {
success: true,
data: mockPost,
message: '获取帖子详情成功',
code: 200
};
mockClient.get.mockResolvedValue(mockResponse);
const result = await postApiInstance.getPost(getRequest);
expect(mockClient.get).toHaveBeenCalledWith('/posts/post-123');
expect(result).toEqual(mockResponse);
});
it('应该处理获取不存在帖子的情况', async () => {
const getRequest: GetPostRequest = { postId: 'non-existent-post' };
const errorResponse = {
success: false,
data: null,
message: '帖子不存在',
code: 404
};
mockClient.get.mockRejectedValue(errorResponse);
await expect(postApiInstance.getPost(getRequest)).rejects.toEqual(errorResponse);
expect(mockClient.get).toHaveBeenCalledWith('/posts/non-existent-post');
});
});
describe('点赞帖子功能', () => {
it('应该能够点赞帖子', async () => {
const likeRequest: LikePostRequest = { postId: 'post-123' };
const mockResponse: LikePostResponse = {
success: true,
message: '点赞成功',
code: 200
};
mockClient.put.mockResolvedValue(mockResponse);
const result = await postApiInstance.likePost(likeRequest);
expect(mockClient.put).toHaveBeenCalledWith('/posts/post-123/like');
expect(result).toEqual(mockResponse);
});
it('应该处理点赞不存在帖子的情况', async () => {
const likeRequest: LikePostRequest = { postId: 'non-existent-post' };
const errorResponse = {
success: false,
data: null,
message: '帖子不存在',
code: 404
};
mockClient.put.mockRejectedValue(errorResponse);
await expect(postApiInstance.likePost(likeRequest)).rejects.toEqual(errorResponse);
expect(mockClient.put).toHaveBeenCalledWith('/posts/non-existent-post/like');
});
});
describe('收藏帖子功能', () => {
it('应该能够收藏帖子', async () => {
const bookmarkRequest: BookmarkPostRequest = { postId: 'post-123' };
const mockResponse: BookmarkPostResponse = {
success: true,
message: '收藏成功',
code: 200
};
mockClient.put.mockResolvedValue(mockResponse);
const result = await postApiInstance.bookmarkPost(bookmarkRequest);
expect(mockClient.put).toHaveBeenCalledWith('/posts/post-123/bookmark');
expect(result).toEqual(mockResponse);
});
it('应该处理收藏不存在帖子的情况', async () => {
const bookmarkRequest: BookmarkPostRequest = { postId: 'non-existent-post' };
const errorResponse = {
success: false,
data: null,
message: '帖子不存在',
code: 404
};
mockClient.put.mockRejectedValue(errorResponse);
await expect(postApiInstance.bookmarkPost(bookmarkRequest)).rejects.toEqual(errorResponse);
expect(mockClient.put).toHaveBeenCalledWith('/posts/non-existent-post/bookmark');
});
});
describe('创建评论功能', () => {
it('应该能够创建评论', async () => {
const commentRequest: CreateCommentRequest = {
postId: 'post-123',
content: '这是一个测试评论',
parentId: 'parent-comment-123'
};
const mockComment = createMockPostComment({
postId: commentRequest.postId,
content: commentRequest.content,
parentId: commentRequest.parentId
});
const mockResponse: CreateCommentResponse = {
success: true,
data: mockComment,
message: '评论创建成功',
code: 201
};
mockClient.post.mockResolvedValue(mockResponse);
const result = await postApiInstance.createComment(commentRequest);
expect(mockClient.post).toHaveBeenCalledWith('/posts/post-123/comments', commentRequest);
expect(result).toEqual(mockResponse);
});
it('应该处理创建评论失败的情况', async () => {
const commentRequest: CreateCommentRequest = {
postId: 'post-123',
content: '', // 空评论内容
parentId: 'parent-comment-123'
};
const errorResponse = {
success: false,
data: null,
message: '评论内容不能为空',
code: 400
};
mockClient.post.mockRejectedValue(errorResponse);
await expect(postApiInstance.createComment(commentRequest)).rejects.toEqual(errorResponse);
expect(mockClient.post).toHaveBeenCalledWith('/posts/post-123/comments', commentRequest);
});
});
describe('获取评论列表功能', () => {
it('应该能够获取评论列表', async () => {
const commentsRequest: GetCommentsRequest = {
postId: 'post-123',
page: 1,
limit: 10,
sortBy: 'createdAt',
sortOrder: 'desc'
};
const mockComments = [
createMockPostComment({ id: 'comment-1', postId: 'post-123' }),
createMockPostComment({ id: 'comment-2', postId: 'post-123' })
];
const mockResponse: GetCommentsResponse = {
success: true,
data: {
comments: mockComments,
pagination: {
page: 1,
limit: 10,
total: 50,
totalPages: 5
}
},
message: '获取评论列表成功',
code: 200
};
mockClient.get.mockResolvedValue(mockResponse);
const result = await postApiInstance.getComments(commentsRequest);
expect(mockClient.get).toHaveBeenCalledWith('/posts/post-123/comments', {
params: { page: 1, limit: 10, sortBy: 'createdAt', sortOrder: 'desc' }
});
expect(result).toEqual(mockResponse);
});
it('应该处理获取评论列表失败的情况', async () => {
const commentsRequest: GetCommentsRequest = {
postId: 'post-123',
page: -1, // 无效的页码
limit: 10
};
const errorResponse = {
success: false,
data: null,
message: '页码必须大于0',
code: 400
};
mockClient.get.mockRejectedValue(errorResponse);
await expect(postApiInstance.getComments(commentsRequest)).rejects.toEqual(errorResponse);
expect(mockClient.get).toHaveBeenCalledWith('/posts/post-123/comments', {
params: { page: -1, limit: 10 }
});
});
});
describe('点赞评论功能', () => {
it('应该能够点赞评论', async () => {
const likeCommentRequest: LikeCommentRequest = { commentId: 'comment-123' };
const mockResponse: LikeCommentResponse = {
success: true,
message: '点赞评论成功',
code: 200
};
mockClient.put.mockResolvedValue(mockResponse);
const result = await postApiInstance.likeComment(likeCommentRequest);
expect(mockClient.put).toHaveBeenCalledWith('/comments/comment-123/like');
expect(result).toEqual(mockResponse);
});
it('应该处理点赞不存在评论的情况', async () => {
const likeCommentRequest: LikeCommentRequest = { commentId: 'non-existent-comment' };
const errorResponse = {
success: false,
data: null,
message: '评论不存在',
code: 404
};
mockClient.put.mockRejectedValue(errorResponse);
await expect(postApiInstance.likeComment(likeCommentRequest)).rejects.toEqual(errorResponse);
expect(mockClient.put).toHaveBeenCalledWith('/comments/non-existent-comment/like');
});
});
})