刘嘉昕 | 8a3c6ab | 2025-06-09 17:44:13 +0800 | [diff] [blame^] | 1 | import { describe, it, expect, vi, beforeEach } from 'vitest'; |
| 2 | import { render, screen, waitFor } from '@testing-library/react'; |
| 3 | import userEvent from '@testing-library/user-event'; |
| 4 | import { MemoryRouter, useParams, useNavigate, useLocation } from 'react-router-dom'; |
| 5 | import TorrentDetailcomplain from '../components/TorrentDetailcomplain'; |
| 6 | import axios from 'axios'; |
| 7 | |
| 8 | // 模拟 axios |
| 9 | vi.mock('axios'); |
| 10 | |
| 11 | // 模拟 react-router-dom 的 hooks |
| 12 | vi.mock('react-router-dom', async () => { |
| 13 | const actual = await vi.importActual('react-router-dom'); |
| 14 | return { |
| 15 | ...actual, |
| 16 | useParams: vi.fn(), |
| 17 | useNavigate: vi.fn(), |
| 18 | useLocation: vi.fn(), |
| 19 | }; |
| 20 | }); |
| 21 | |
| 22 | describe('TorrentDetailcomplain 组件', () => { |
| 23 | const mockTorrent = { |
| 24 | torrentid: 1, |
| 25 | filename: '测试种子文件', |
| 26 | torrentSize: 1024 * 1024 * 10, // 10MB |
| 27 | uploader_id: 123, |
| 28 | uploadTime: '2023-01-01T12:00:00', |
| 29 | downloadCount: 100, |
| 30 | promotionid: 1, |
| 31 | description: '这是一个测试种子', |
| 32 | coverImagePath: 'http://example.com/cover.jpg', |
| 33 | }; |
| 34 | |
| 35 | const mockNavigate = vi.fn(); |
| 36 | const mockLocation = { |
| 37 | state: { |
| 38 | duser: 456, |
| 39 | torrentid: 1, |
| 40 | }, |
| 41 | }; |
| 42 | |
| 43 | beforeEach(() => { |
| 44 | vi.clearAllMocks(); |
| 45 | |
| 46 | // 设置模拟的路由 hooks |
| 47 | vi.mocked(useParams).mockReturnValue({ id: '1' }); |
| 48 | vi.mocked(useNavigate).mockReturnValue(mockNavigate); |
| 49 | vi.mocked(useLocation).mockReturnValue(mockLocation); |
| 50 | |
| 51 | // 模拟 axios.get 返回种子详情 |
| 52 | axios.get.mockResolvedValueOnce({ data: mockTorrent }); |
| 53 | }); |
| 54 | |
| 55 | it('应该正确渲染而不崩溃', async () => { |
| 56 | render( |
| 57 | <MemoryRouter> |
| 58 | <TorrentDetailcomplain /> |
| 59 | </MemoryRouter> |
| 60 | ); |
| 61 | |
| 62 | // 等待数据加载 |
| 63 | await waitFor(() => { |
| 64 | expect(screen.getByText('种子详情')).toBeInTheDocument(); |
| 65 | }); |
| 66 | |
| 67 | // 验证一些基本元素是否存在 |
| 68 | expect(screen.getByText('ID: 1')).toBeInTheDocument(); |
| 69 | expect(screen.getByText('文件名: 测试种子文件')).toBeInTheDocument(); |
| 70 | expect(screen.getByText('大小: 10.00 MB')).toBeInTheDocument(); |
| 71 | expect(screen.getByText('上传者ID: 123')).toBeInTheDocument(); |
| 72 | expect(screen.getByText('上传时间: 2023/01/01 12:00')).toBeInTheDocument(); |
| 73 | expect(screen.getByText('下载次数: 100')).toBeInTheDocument(); |
| 74 | expect(screen.getByText('促销: 上传加倍')).toBeInTheDocument(); |
| 75 | expect(screen.getByText('描述: 这是一个测试种子')).toBeInTheDocument(); |
| 76 | }); |
| 77 | |
| 78 | it('应该加载种子详情数据', async () => { |
| 79 | render( |
| 80 | <MemoryRouter> |
| 81 | <TorrentDetailcomplain /> |
| 82 | </MemoryRouter> |
| 83 | ); |
| 84 | |
| 85 | // 等待数据加载 |
| 86 | await waitFor(() => { |
| 87 | expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/torrent/1'); |
| 88 | }); |
| 89 | }); |
| 90 | |
| 91 | it('应该正确显示封面图片', async () => { |
| 92 | render( |
| 93 | <MemoryRouter> |
| 94 | <TorrentDetailcomplain /> |
| 95 | </MemoryRouter> |
| 96 | ); |
| 97 | |
| 98 | // 等待数据加载 |
| 99 | await waitFor(() => { |
| 100 | expect(screen.getByText('种子详情')).toBeInTheDocument(); |
| 101 | }); |
| 102 | |
| 103 | // 验证封面图片是否渲染 |
| 104 | const image = screen.getByAltText('种子封面'); |
| 105 | expect(image).toBeInTheDocument(); |
| 106 | expect(image).toHaveAttribute('src', 'http://example.com/cover.jpg'); |
| 107 | }); |
| 108 | |
| 109 | it('应该正确处理删除种子按钮点击', async () => { |
| 110 | // 模拟 confirm 对话框 |
| 111 | vi.mocked(axios.delete).mockResolvedValueOnce({}); |
| 112 | |
| 113 | render( |
| 114 | <MemoryRouter> |
| 115 | <TorrentDetailcomplain /> |
| 116 | </MemoryRouter> |
| 117 | ); |
| 118 | |
| 119 | // 等待数据加载 |
| 120 | await waitFor(() => { |
| 121 | expect(screen.getByText('种子详情')).toBeInTheDocument(); |
| 122 | }); |
| 123 | |
| 124 | // 点击删除按钮 |
| 125 | const deleteButton = screen.getByText('删除'); |
| 126 | userEvent.click(deleteButton); |
| 127 | |
| 128 | // 验证 confirm 对话框是否被调用 |
| 129 | // 注意:由于我们使用了 antd 的 Modal.confirm,我们需要检查 axios.delete 是否被调用 |
| 130 | // 这里我们直接验证 axios.delete 是否被调用 |
| 131 | await waitFor(() => { |
| 132 | expect(axios.delete).toHaveBeenCalledWith('http://localhost:8080/torrent/delete/1', { |
| 133 | params: { userid: 1 }, |
| 134 | }); |
| 135 | }); |
| 136 | |
| 137 | // 验证导航是否被调用 |
| 138 | await waitFor(() => { |
| 139 | expect(mockNavigate).toHaveBeenCalledWith(-1); |
| 140 | }); |
| 141 | |
| 142 | // 验证成功消息是否被调用 |
| 143 | expect(vi.mocked(message.success)).toHaveBeenCalledWith('种子删除成功'); |
| 144 | }); |
| 145 | |
| 146 | it('应该正确处理下载种子按钮点击', async () => { |
| 147 | render( |
| 148 | <MemoryRouter> |
| 149 | <TorrentDetailcomplain /> |
| 150 | </MemoryRouter> |
| 151 | ); |
| 152 | |
| 153 | // 等待数据加载 |
| 154 | await waitFor(() => { |
| 155 | expect(screen.getByText('种子详情')).toBeInTheDocument(); |
| 156 | }); |
| 157 | |
| 158 | // 点击下载按钮 |
| 159 | const downloadButton = screen.getByText('下载'); |
| 160 | userEvent.click(downloadButton); |
| 161 | |
| 162 | // 验证 axios.get 是否被调用(注意:我们实际上使用了 window.open) |
| 163 | // 由于我们直接使用了 window.open,我们需要验证它是否被调用 |
| 164 | // 这里我们无法直接验证 window.open,但可以验证没有错误发生 |
| 165 | // 我们可以验证组件没有崩溃 |
| 166 | expect(screen.getByText('种子详情')).toBeInTheDocument(); |
| 167 | }); |
| 168 | |
| 169 | it('应该正确处理扣除保种积分按钮点击', async () => { |
| 170 | // 模拟 axios.post |
| 171 | vi.mocked(axios.post).mockResolvedValueOnce({ data: { success: true } }); |
| 172 | |
| 173 | render( |
| 174 | <MemoryRouter> |
| 175 | <TorrentDetailcomplain /> |
| 176 | </MemoryRouter> |
| 177 | ); |
| 178 | |
| 179 | // 等待数据加载 |
| 180 | await waitFor(() => { |
| 181 | expect(screen.getByText('种子详情')).toBeInTheDocument(); |
| 182 | }); |
| 183 | |
| 184 | // 点击扣除保种积分按钮 |
| 185 | const creditButton = screen.getByText('扣除保种积分'); |
| 186 | userEvent.click(creditButton); |
| 187 | |
| 188 | // 验证 axios.post 是否被调用 |
| 189 | await waitFor(() => { |
| 190 | expect(axios.post).toHaveBeenCalledWith( |
| 191 | 'http://localhost:8080/torrent/deducecredit', |
| 192 | 'manageid=1&userid=456&credit=3', |
| 193 | { |
| 194 | headers: { |
| 195 | 'Content-Type': 'application/x-www-form-urlencoded', |
| 196 | }, |
| 197 | } |
| 198 | ); |
| 199 | }); |
| 200 | |
| 201 | // 验证成功消息是否被调用 |
| 202 | expect(vi.mocked(message.success)).toHaveBeenCalledWith('成功扣除 3 保种积分'); |
| 203 | }); |
| 204 | |
| 205 | it('应该正确处理删除种子失败的情况', async () => { |
| 206 | // 模拟 axios.delete 失败 |
| 207 | vi.mocked(axios.delete).mockRejectedValueOnce({ |
| 208 | response: { |
| 209 | status: 403, |
| 210 | data: '无权删除此种子', |
| 211 | }, |
| 212 | }); |
| 213 | |
| 214 | render( |
| 215 | <MemoryRouter> |
| 216 | <TorrentDetailcomplain /> |
| 217 | </MemoryRouter> |
| 218 | ); |
| 219 | |
| 220 | // 等待数据加载 |
| 221 | await waitFor(() => { |
| 222 | expect(screen.getByText('种子详情')).toBeInTheDocument(); |
| 223 | }); |
| 224 | |
| 225 | // 点击删除按钮 |
| 226 | const deleteButton = screen.getByText('删除'); |
| 227 | userEvent.click(deleteButton); |
| 228 | |
| 229 | // 验证 axios.delete 是否被调用 |
| 230 | await waitFor(() => { |
| 231 | expect(axios.delete).toHaveBeenCalledWith('http://localhost:8080/torrent/delete/1', { |
| 232 | params: { userid: 1 }, |
| 233 | }); |
| 234 | }); |
| 235 | |
| 236 | // 验证错误消息是否被调用 |
| 237 | expect(vi.mocked(message.error)).toHaveBeenCalledWith('无权删除此种子'); |
| 238 | }); |
| 239 | |
| 240 | it('应该正确处理下载种子失败的情况', async () => { |
| 241 | // 模拟 window.open 失败(我们无法直接模拟 window.open,所以这个测试可能有限) |
| 242 | // 由于我们直接使用了 window.open,我们无法直接测试它的失败情况 |
| 243 | // 我们可以测试组件在点击按钮后没有崩溃 |
| 244 | render( |
| 245 | <MemoryRouter> |
| 246 | <TorrentDetailcomplain /> |
| 247 | </MemoryRouter> |
| 248 | ); |
| 249 | |
| 250 | // 等待数据加载 |
| 251 | await waitFor(() => { |
| 252 | expect(screen.getByText('种子详情')).toBeInTheDocument(); |
| 253 | }); |
| 254 | |
| 255 | // 点击下载按钮 |
| 256 | const downloadButton = screen.getByText('下载'); |
| 257 | userEvent.click(downloadButton); |
| 258 | |
| 259 | // 验证组件没有崩溃 |
| 260 | expect(screen.getByText('种子详情')).toBeInTheDocument(); |
| 261 | }); |
| 262 | |
| 263 | it('应该正确处理扣除保种积分失败的情况', async () => { |
| 264 | // 模拟 axios.post 失败 |
| 265 | vi.mocked(axios.post).mockRejectedValueOnce({ |
| 266 | response: { |
| 267 | status: 500, |
| 268 | data: { message: '服务器错误' }, |
| 269 | }, |
| 270 | }); |
| 271 | |
| 272 | render( |
| 273 | <MemoryRouter> |
| 274 | <TorrentDetailcomplain /> |
| 275 | </MemoryRouter> |
| 276 | ); |
| 277 | |
| 278 | // 等待数据加载 |
| 279 | await waitFor(() => { |
| 280 | expect(screen.getByText('种子详情')).toBeInTheDocument(); |
| 281 | }); |
| 282 | |
| 283 | // 点击扣除保种积分按钮 |
| 284 | const creditButton = screen.getByText('扣除保种积分'); |
| 285 | userEvent.click(creditButton); |
| 286 | |
| 287 | // 验证 axios.post 是否被调用 |
| 288 | await waitFor(() => { |
| 289 | expect(axios.post).toHaveBeenCalledWith( |
| 290 | 'http://localhost:8080/torrent/deducecredit', |
| 291 | 'manageid=1&userid=456&credit=3', |
| 292 | { |
| 293 | headers: { |
| 294 | 'Content-Type': 'application/x-www-form-urlencoded', |
| 295 | }, |
| 296 | } |
| 297 | ); |
| 298 | }); |
| 299 | |
| 300 | // 验证错误消息是否被调用 |
| 301 | expect(vi.mocked(message.error)).toHaveBeenCalledWith('服务器错误: 服务器错误'); |
| 302 | }); |
| 303 | |
| 304 | it('应该正确处理种子不存在的情况', async () => { |
| 305 | // 模拟 axios.get 返回 404 |
| 306 | axios.get.mockRejectedValueOnce({ |
| 307 | response: { |
| 308 | status: 404, |
| 309 | }, |
| 310 | }); |
| 311 | |
| 312 | render( |
| 313 | <MemoryRouter> |
| 314 | <TorrentDetailcomplain /> |
| 315 | </MemoryRouter> |
| 316 | ); |
| 317 | |
| 318 | // 等待错误状态 |
| 319 | await waitFor(() => { |
| 320 | expect(screen.queryByText('种子详情')).not.toBeInTheDocument(); |
| 321 | }); |
| 322 | |
| 323 | // 验证错误消息是否显示 |
| 324 | expect(screen.getByText('种子不存在')).toBeInTheDocument(); |
| 325 | expect(screen.getByText('抱歉,您查找的种子不存在或已被删除。')).toBeInTheDocument(); |
| 326 | }); |
| 327 | |
| 328 | it('应该正确处理网络错误的情况', async () => { |
| 329 | // 模拟 axios.get 网络错误 |
| 330 | axios.get.mockRejectedValueOnce({ |
| 331 | message: '网络错误', |
| 332 | }); |
| 333 | |
| 334 | render( |
| 335 | <MemoryRouter> |
| 336 | <TorrentDetailcomplain /> |
| 337 | </MemoryRouter> |
| 338 | ); |
| 339 | |
| 340 | // 等待错误状态 |
| 341 | await waitFor(() => { |
| 342 | expect(screen.queryByText('种子详情')).not.toBeInTheDocument(); |
| 343 | }); |
| 344 | |
| 345 | // 验证错误消息是否显示 |
| 346 | expect(screen.getByText('网络错误,请稍后重试')).toBeInTheDocument(); |
| 347 | }); |
| 348 | }); |