blob: 6364be2ef411f959c78f25cbbe82aa0fd736b5c9 [file] [log] [blame]
Akane121765b61a72025-05-17 13:52:25 +08001import React from 'react';
2import { render, screen, fireEvent, waitFor } from '@testing-library/react';
3import { MemoryRouter, Route, Routes, useNavigate, useLocation } from 'react-router-dom';
4import HelpDetail from './HelpDetail';
5import * as helpPostApi from '../api/helpPost';
6import * as helpCommentApi from '../api/helpComment';
7
8// Mock API 模块
9jest.mock('../api/helpPost');
10jest.mock('../api/helpComment');
11
12// Mock 路由钩子
13const mockNavigate = jest.fn();
14jest.mock('react-router-dom', () => ({
15 ...jest.requireActual('react-router-dom'),
16 useNavigate: () => mockNavigate,
17 useLocation: jest.fn(),
18}));
19
20describe('HelpDetail 组件', () => {
21 const mockPost = {
22 id: '1',
23 title: '测试求助帖',
24 content: '这是一个测试求助内容',
25 authorId: 'user1',
26 createTime: '2023-01-01T00:00:00Z',
27 likeCount: 5,
28 replyCount: 3,
29 isSolved: false,
30 };
31
32 const mockComments = [
33 {
34 id: 'c1',
35 content: '测试评论1',
36 authorId: 'user2',
37 createTime: '2023-01-01T01:00:00Z',
38 likeCount: 2,
39 replies: [
40 {
41 id: 'c1r1',
42 content: '测试回复1',
43 authorId: 'user3',
44 createTime: '2023-01-01T02:00:00Z',
45 likeCount: 1,
46 }
47 ]
48 }
49 ];
50
51 beforeEach(() => {
52 // 重置 mock 函数
53 mockNavigate.mockClear();
54
55 // 设置模拟的 API 响应
56 helpPostApi.getPostDetail.mockResolvedValue({
57 data: {
58 code: 200,
59 data: {
60 post: mockPost,
61 comments: mockComments,
62 }
63 }
64 });
65
66 // 模拟 useLocation
67 useLocation.mockReturnValue({
68 state: { fromTab: 'help' }
69 });
70
71 // 模拟 localStorage
72 Storage.prototype.getItem = jest.fn((key) => {
73 if (key === 'username') return 'testuser';
74 return null;
75 });
76 });
77
78 const renderComponent = () => {
79 return render(
80 <MemoryRouter initialEntries={['/help/1']}>
81 <Routes>
82 <Route path="/help/:id" element={<HelpDetail />} />
83 {/* 添加一个模拟的求助列表路由用于导航测试 */}
84 <Route path="/dashboard/help" element={<div>求助列表</div>} />
85 </Routes>
86 </MemoryRouter>
87 );
88 };
89
90 it('应该正确加载和显示求助帖详情', async () => {
91 renderComponent();
92
93 // 检查加载状态
94 expect(screen.getByText('加载中...')).toBeInTheDocument();
95
96 // 等待数据加载完成
97 await waitFor(() => {
98 expect(screen.getByText('测试求助帖')).toBeInTheDocument();
99 expect(screen.getByText('这是一个测试求助内容')).toBeInTheDocument();
100 expect(screen.getByText('user1')).toBeInTheDocument();
101 });
102 });
103
104 it('应该能够点赞帖子', async () => {
105 renderComponent();
106
107 await waitFor(() => {
108 expect(screen.getByText('测试求助帖')).toBeInTheDocument();
109 });
110
111 fireEvent.click(screen.getByText(/点赞 \(5\)/));
112
113 await waitFor(() => {
114 expect(helpPostApi.likePost).toHaveBeenCalledWith('1');
115 });
116 });
117
118 it('应该能够提交评论', async () => {
119 renderComponent();
120
121 await waitFor(() => {
122 expect(screen.getByText('测试求助帖')).toBeInTheDocument();
123 });
124
125 const commentInput = screen.getByPlaceholderText('写下你的评论...');
126 fireEvent.change(commentInput, { target: { value: '新评论' } });
127 fireEvent.click(screen.getByText('发表评论'));
128
129 await waitFor(() => {
130 expect(helpPostApi.addPostComment).toHaveBeenCalledWith('1', {
131 content: '新评论',
132 authorId: 'testuser'
133 });
134 });
135 });
136
137 it('应该能够点赞评论', async () => {
138 renderComponent();
139
140 await waitFor(() => {
141 expect(screen.getByText('测试评论1')).toBeInTheDocument();
142 });
143
144 fireEvent.click(screen.getAllByText(/👍 \(2\)/)[0]);
145
146 await waitFor(() => {
147 expect(helpCommentApi.likePostComment).toHaveBeenCalledWith('c1');
148 });
149 });
150
151 it('应该能够打开和关闭回复模态框', async () => {
152 renderComponent();
153
154 await waitFor(() => {
155 expect(screen.getByText('测试评论1')).toBeInTheDocument();
156 });
157
158 // 点击回复按钮
159 fireEvent.click(screen.getAllByText('回复')[0]);
160
161 // 检查模态框是否打开
162 await waitFor(() => {
163 expect(screen.getByText('回复 @user2')).toBeInTheDocument();
164 });
165
166 // 点击关闭按钮
167 fireEvent.click(screen.getByText('×'));
168
169 // 检查模态框是否关闭
170 await waitFor(() => {
171 expect(screen.queryByText('回复 @user2')).not.toBeInTheDocument();
172 });
173 });
174
175 it('应该能够返回求助区', async () => {
176 renderComponent();
177
178 await waitFor(() => {
179 expect(screen.getByText('测试求助帖')).toBeInTheDocument();
180 });
181
182 fireEvent.click(screen.getByRole('button', { name: /返回/i }));
183
184 // 修正后的断言(不再验证 state)
185 expect(mockNavigate).toHaveBeenCalledWith('/dashboard/help');
186 });
187});