/** * 帖子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; 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'); }); }); })