| // Personal.test.jsx | |
| import React from 'react'; | |
| import { render, screen, waitFor, act } from '@testing-library/react'; | |
| import { MemoryRouter, useLocation, useNavigate } from 'react-router-dom'; | |
| import Personal from './Personal'; | |
| import { getUserInfo, getDownloadQuota, getDownloadProgress } from '../../api/personal'; | |
| // Mock API 调用 | |
| jest.mock('../../api/personal', () => ({ | |
| getUserInfo: jest.fn(), | |
| getDownloadQuota: jest.fn(), | |
| getDownloadProgress: jest.fn() | |
| })); | |
| // Mock react-router-dom hooks | |
| jest.mock('react-router-dom', () => ({ | |
| ...jest.requireActual('react-router-dom'), | |
| useNavigate: jest.fn(), | |
| useLocation: jest.fn() | |
| })); | |
| describe('Personal Component', () => { | |
| const mockNavigate = jest.fn(); | |
| const mockLocation = { | |
| pathname: '/personal', | |
| state: null | |
| }; | |
| beforeEach(() => { | |
| useNavigate.mockReturnValue(mockNavigate); | |
| useLocation.mockReturnValue(mockLocation); | |
| // 重置所有 mock | |
| jest.clearAllMocks(); | |
| // 设置默认 mock 返回值 | |
| getUserInfo.mockResolvedValue({ | |
| username: 'testuser', | |
| registTime: '2023-01-01', | |
| level: 2, | |
| magicPoints: 1000, | |
| upload: 1024 * 1024 * 5, // 5MB | |
| download: 1024 * 1024 * 2, // 2MB | |
| shareRate: 2.5 | |
| }); | |
| getDownloadQuota.mockResolvedValue({ | |
| total: 1024 * 1024 * 10, // 10MB | |
| used: 1024 * 1024 * 3, // 3MB | |
| remaining: 1024 * 1024 * 7 // 7MB | |
| }); | |
| getDownloadProgress.mockResolvedValue({ | |
| 'task1': 0.25, | |
| 'task2': 0.75 | |
| }); | |
| }); | |
| it('应该正确加载并显示用户数据', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Personal /> | |
| </MemoryRouter> | |
| ); | |
| // 初始加载状态 | |
| expect(screen.getByText('加载中...')).toBeInTheDocument(); | |
| // 等待数据加载完成 | |
| await waitFor(() => { | |
| expect(screen.getByText('testuser')).toBeInTheDocument(); | |
| expect(screen.getByText(/加入时间: 2023-01-01/)).toBeInTheDocument(); | |
| expect(screen.getByText(/会员等级: Lv.2/)).toBeInTheDocument(); | |
| expect(screen.getByText('1000')).toBeInTheDocument(); // 保种积分 | |
| expect(screen.getByText('5.00 MB')).toBeInTheDocument(); // 上传量 | |
| expect(screen.getByText('2.00 MB')).toBeInTheDocument(); // 下载量 | |
| expect(screen.getByText('2.5')).toBeInTheDocument(); // 分享率 | |
| }); | |
| }); | |
| it('应该显示下载额度信息', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Personal /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| expect(screen.getByText(/3.00 MB 已使用/)).toBeInTheDocument(); | |
| expect(screen.getByText(/7.00 MB 剩余/)).toBeInTheDocument(); | |
| expect(screen.getByText(/总额度: 10.00 MB/)).toBeInTheDocument(); | |
| }); | |
| }); | |
| it('应该显示下载进度', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Personal /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| expect(screen.getByText('当前下载进度')).toBeInTheDocument(); | |
| expect(screen.getByText(/任务: task1/)).toBeInTheDocument(); | |
| expect(screen.getByText('25%')).toBeInTheDocument(); | |
| expect(screen.getByText(/任务: task2/)).toBeInTheDocument(); | |
| expect(screen.getByText('75%')).toBeInTheDocument(); | |
| }); | |
| }); | |
| it('应该显示功能卡片并处理点击', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Personal /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| const exchangeCard = screen.getByText('兑换区'); | |
| expect(exchangeCard).toBeInTheDocument(); | |
| // 模拟点击功能卡片 | |
| act(() => { | |
| exchangeCard.closest('.action-card').click(); | |
| }); | |
| expect(mockNavigate).toHaveBeenCalledWith('/personal/Exchange'); | |
| }); | |
| }); | |
| it('应该处理返回按钮点击', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Personal /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| const backButton = screen.getByText(/返回/); | |
| act(() => { | |
| backButton.click(); | |
| }); | |
| expect(mockNavigate).toHaveBeenCalledWith(-1); | |
| }); | |
| }); | |
| it('应该处理从子页面返回的情况', async () => { | |
| useLocation.mockReturnValue({ | |
| pathname: '/personal', | |
| state: { fromSubpage: true, dashboardTab: 'uploads' } | |
| }); | |
| render( | |
| <MemoryRouter> | |
| <Personal /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| const backButton = screen.getByText(/返回/); | |
| act(() => { | |
| backButton.click(); | |
| }); | |
| expect(mockNavigate).toHaveBeenCalledWith('/dashboard/uploads', { replace: true }); | |
| }); | |
| }); | |
| it('应该显示错误信息当API调用失败', async () => { | |
| getUserInfo.mockRejectedValue(new Error('获取用户信息失败')); | |
| render( | |
| <MemoryRouter> | |
| <Personal /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| expect(screen.getByText(/错误: 获取用户信息失败/)).toBeInTheDocument(); | |
| }); | |
| }); | |
| it('应该定期更新下载进度', async () => { | |
| jest.useFakeTimers(); | |
| render( | |
| <MemoryRouter> | |
| <Personal /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| expect(getDownloadProgress).toHaveBeenCalledTimes(1); | |
| }); | |
| // 快进时间 | |
| act(() => { | |
| jest.advanceTimersByTime(10000); | |
| }); | |
| await waitFor(() => { | |
| expect(getDownloadProgress).toHaveBeenCalledTimes(2); | |
| }); | |
| jest.useRealTimers(); | |
| }); | |
| }); |