blob: 20fe641369dfed92d9c59d2a5766fa9672c6e688 [file] [log] [blame]
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();
});
});