| // Upload.test.jsx | |
| import React from 'react'; | |
| import { render, screen, waitFor, fireEvent } from '@testing-library/react'; | |
| import { MemoryRouter, useNavigate, useLocation } from 'react-router-dom'; | |
| import Upload from './Upload'; | |
| import { getUserTorrents, deleteTorrent } from '../../api/personal'; | |
| // Mock API 调用 | |
| jest.mock('../../api/personal', () => ({ | |
| getUserTorrents: jest.fn(), | |
| deleteTorrent: jest.fn() | |
| })); | |
| // Mock react-router-dom hooks | |
| jest.mock('react-router-dom', () => ({ | |
| ...jest.requireActual('react-router-dom'), | |
| useNavigate: jest.fn(), | |
| useLocation: jest.fn() | |
| })); | |
| // Mock window.confirm | |
| global.confirm = jest.fn(() => true); | |
| describe('Upload Component', () => { | |
| const mockNavigate = jest.fn(); | |
| const mockLocation = { | |
| pathname: '/personal/upload', | |
| state: { dashboardTab: 'uploads' } | |
| }; | |
| const mockTorrents = [ | |
| { | |
| id: 1, | |
| torrentName: 'Test Torrent 1', | |
| formattedSize: '1.2 GB', | |
| createTime: '2023-01-01T12:00:00Z', | |
| downloadCount: 10 | |
| }, | |
| { | |
| id: 2, | |
| torrentName: 'Test Torrent 2', | |
| formattedSize: '2.5 GB', | |
| createTime: '2023-01-02T12:00:00Z', | |
| downloadCount: 5 | |
| } | |
| ]; | |
| beforeEach(() => { | |
| useNavigate.mockReturnValue(mockNavigate); | |
| useLocation.mockReturnValue(mockLocation); | |
| jest.clearAllMocks(); | |
| getUserTorrents.mockResolvedValue({ | |
| records: mockTorrents, | |
| total: 10 | |
| }); | |
| deleteTorrent.mockResolvedValue({ success: true }); | |
| }); | |
| it('应该正确加载并显示上传记录', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Upload /> | |
| </MemoryRouter> | |
| ); | |
| // 初始加载状态 | |
| expect(screen.getByText('加载中...')).toBeInTheDocument(); | |
| // 等待数据加载完成 | |
| await waitFor(() => { | |
| expect(screen.getByText('上传记录')).toBeInTheDocument(); | |
| expect(screen.getByText('Test Torrent 1')).toBeInTheDocument(); | |
| expect(screen.getByText('Test Torrent 2')).toBeInTheDocument(); | |
| expect(screen.getByText('1.2 GB')).toBeInTheDocument(); | |
| expect(screen.getByText('2.5 GB')).toBeInTheDocument(); | |
| expect(screen.getAllByText('删除')).toHaveLength(2); | |
| }); | |
| }); | |
| it('应该处理删除操作', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Upload /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| const deleteButtons = screen.getAllByText('删除'); | |
| fireEvent.click(deleteButtons[0]); | |
| }); | |
| expect(global.confirm).toHaveBeenCalledWith('确定要删除这个种子吗?此操作不可撤销!'); | |
| await waitFor(() => { | |
| expect(deleteTorrent).toHaveBeenCalledWith(1); | |
| expect(getUserTorrents).toHaveBeenCalledTimes(2); // 初始加载 + 删除后刷新 | |
| }); | |
| }); | |
| it('应该处理分页变化', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Upload /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| const nextPageButton = screen.getByText('下一页'); | |
| fireEvent.click(nextPageButton); | |
| }); | |
| await waitFor(() => { | |
| expect(getUserTorrents).toHaveBeenLastCalledWith(2, 5); | |
| }); | |
| }); | |
| it('应该处理直接跳转页码', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Upload /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| const pageInput = screen.getByRole('spinbutton'); | |
| fireEvent.change(pageInput, { target: { value: '2' } }); | |
| fireEvent.keyDown(pageInput, { key: 'Enter' }); | |
| }); | |
| await waitFor(() => { | |
| expect(getUserTorrents).toHaveBeenLastCalledWith(2, 5); | |
| }, { timeout: 1000 }); | |
| }); | |
| it('应该处理返回按钮点击', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Upload /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| const backButton = screen.getByText((content) => | |
| content.includes('返回个人中心') | |
| ); | |
| fireEvent.click(backButton); | |
| expect(mockNavigate).toHaveBeenCalledWith('/personal', { | |
| state: { | |
| fromSubpage: true, | |
| dashboardTab: 'uploads' | |
| }, | |
| replace: true | |
| }); | |
| }); | |
| }); | |
| it('应该显示错误信息当API调用失败', async () => { | |
| getUserTorrents.mockRejectedValue(new Error('获取上传记录失败')); | |
| render( | |
| <MemoryRouter> | |
| <Upload /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| expect(screen.getByText('错误: 获取上传记录失败')).toBeInTheDocument(); | |
| }); | |
| }); | |
| it('应该禁用分页按钮当在第一页或最后一页', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Upload /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| const prevButton = screen.getByText('上一页'); | |
| const firstPageButton = screen.getByText('首页'); | |
| expect(prevButton).toBeDisabled(); | |
| expect(firstPageButton).toBeDisabled(); | |
| }); | |
| }); | |
| it('应该显示正确的页码导航', async () => { | |
| // 模拟有更多页的情况 | |
| getUserTorrents.mockResolvedValue({ | |
| records: mockTorrents, | |
| total: 50 | |
| }); | |
| render( | |
| <MemoryRouter> | |
| <Upload /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| expect(screen.getByText('...')).toBeInTheDocument(); | |
| expect(screen.getByText('共 10 页')).toBeInTheDocument(); | |
| }); | |
| }); | |
| }); |