import React from 'react'; | |
import { render, screen, waitFor, fireEvent } from '@testing-library/react'; | |
import { MemoryRouter, useNavigate, useLocation } from 'react-router-dom'; | |
import Exchange from './Exchange'; | |
import { | |
generateInviteCode, | |
getUserInviteCodes, | |
exchangeUpload, | |
getUserInfo | |
} from '../../api/personal'; | |
// Mock API 调用 | |
jest.mock('../../api/personal', () => ({ | |
generateInviteCode: jest.fn(), | |
getUserInviteCodes: jest.fn(), | |
exchangeUpload: jest.fn(), | |
getUserInfo: jest.fn() | |
})); | |
// Mock react-router-dom hooks | |
jest.mock('react-router-dom', () => ({ | |
...jest.requireActual('react-router-dom'), | |
useNavigate: jest.fn(), | |
useLocation: jest.fn() | |
})); | |
describe('Exchange Component', () => { | |
const mockNavigate = jest.fn(); | |
const mockLocation = { | |
pathname: '/personal/exchange', | |
state: { dashboardTab: 'exchange' } | |
}; | |
const mockUserInfo = { | |
magicPoints: 100, | |
username: 'testuser' | |
}; | |
const mockInviteCodes = [ | |
{ code: 'ABCD-1234', isUsed: false }, | |
{ code: 'EFGH-5678', isUsed: true } | |
]; | |
beforeEach(() => { | |
useNavigate.mockReturnValue(mockNavigate); | |
useLocation.mockReturnValue(mockLocation); | |
jest.clearAllMocks(); | |
// 设置默认 mock 返回值 | |
getUserInfo.mockResolvedValue(mockUserInfo); | |
getUserInviteCodes.mockResolvedValue(mockInviteCodes); | |
generateInviteCode.mockResolvedValue({ code: 'NEW-CODE', isUsed: false }); | |
exchangeUpload.mockResolvedValue({ success: true }); | |
}); | |
it('应该正确加载并显示用户信息和邀请码', async () => { | |
render( | |
<MemoryRouter> | |
<Exchange /> | |
</MemoryRouter> | |
); | |
// 初始加载状态 | |
expect(screen.getByText('加载中...')).toBeInTheDocument(); | |
// 等待数据加载完成 | |
await waitFor(() => { | |
expect(screen.getByText('兑换区')).toBeInTheDocument(); | |
expect(screen.getByText('当前魔力值: 100')).toBeInTheDocument(); | |
expect(screen.getByText('ABCD-1234')).toBeInTheDocument(); | |
expect(screen.getByText('EFGH-5678')).toBeInTheDocument(); | |
expect(screen.getByText('可用')).toBeInTheDocument(); | |
expect(screen.getByText('已使用')).toBeInTheDocument(); | |
}); | |
}); | |
it('应该处理生成邀请码操作', async () => { | |
render( | |
<MemoryRouter> | |
<Exchange /> | |
</MemoryRouter> | |
); | |
await waitFor(() => { | |
// 使用更精确的选择器定位按钮 | |
const generateButtons = screen.getAllByRole('button', { name: '兑换邀请码' }); | |
// 选择第一个按钮(或根据实际情况选择正确的按钮) | |
fireEvent.click(generateButtons[0]); | |
}); | |
expect(generateInviteCode).toHaveBeenCalled(); | |
await waitFor(() => { | |
expect(getUserInfo).toHaveBeenCalledTimes(2); // 初始加载 + 生成后刷新 | |
}); | |
}); | |
it('应该处理兑换上传量操作', async () => { | |
render( | |
<MemoryRouter> | |
<Exchange /> | |
</MemoryRouter> | |
); | |
await waitFor(() => { | |
const input = screen.getByPlaceholderText('输入要兑换的魔力值'); | |
const exchangeButton = screen.getByRole('button', { name: '兑换上传量' }); | |
// 输入有效值 | |
fireEvent.change(input, { target: { value: '50' } }); | |
fireEvent.click(exchangeButton); | |
}); | |
expect(exchangeUpload).toHaveBeenCalledWith(50); | |
await waitFor(() => { | |
expect(getUserInfo).toHaveBeenCalledTimes(2); // 初始加载 + 兑换后刷新 | |
}); | |
}); | |
it('应该处理返回按钮点击', async () => { | |
render( | |
<MemoryRouter> | |
<Exchange /> | |
</MemoryRouter> | |
); | |
await waitFor(() => { | |
const backButton = screen.getByText(/返回个人中心/); | |
fireEvent.click(backButton); | |
expect(mockNavigate).toHaveBeenCalledWith('/personal', { | |
state: { | |
fromSubpage: true, | |
dashboardTab: 'exchange' | |
}, | |
replace: true | |
}); | |
}); | |
}); | |
it('应该显示错误信息当API调用失败', async () => { | |
getUserInfo.mockRejectedValueOnce(new Error('获取用户信息失败')); | |
render( | |
<MemoryRouter> | |
<Exchange /> | |
</MemoryRouter> | |
); | |
await waitFor(() => { | |
expect(screen.getByText('错误: 获取用户信息失败')).toBeInTheDocument(); | |
}); | |
}); | |
it('应该禁用兑换按钮当魔力值不足', async () => { | |
getUserInfo.mockResolvedValueOnce({ magicPoints: 5 }); // 设置魔力值不足 | |
render( | |
<MemoryRouter> | |
<Exchange /> | |
</MemoryRouter> | |
); | |
await waitFor(() => { | |
const inviteButtons = screen.getAllByRole('button', { name: '兑换邀请码' }); | |
expect(inviteButtons[0]).toBeDisabled(); | |
}); | |
}); | |
it('应该正确处理空邀请码列表', async () => { | |
getUserInviteCodes.mockResolvedValueOnce([]); | |
render( | |
<MemoryRouter> | |
<Exchange /> | |
</MemoryRouter> | |
); | |
await waitFor(() => { | |
expect(screen.queryByText('我的邀请码')).not.toBeInTheDocument(); | |
}); | |
}); | |
it('应该显示加载状态', async () => { | |
// 延迟API响应以测试加载状态 | |
getUserInfo.mockImplementation(() => new Promise(() => {})); | |
render( | |
<MemoryRouter> | |
<Exchange /> | |
</MemoryRouter> | |
); | |
expect(screen.getByText('加载中...')).toBeInTheDocument(); | |
}); | |
}); |