blob: 31abe4839190f9483eee4ec79c712a18e6e62c7a [file] [log] [blame]
Akane12173a7bb972025-06-01 01:05:27 +08001import React from 'react';
2import { render, screen, waitFor, fireEvent } from '@testing-library/react';
3import { MemoryRouter, useNavigate, useLocation } from 'react-router-dom';
4import Exchange from './Exchange';
5import {
6 generateInviteCode,
7 getUserInviteCodes,
8 exchangeUpload,
9 getUserInfo
10} from '../../api/personal';
11
12// Mock API 调用
13jest.mock('../../api/personal', () => ({
14 generateInviteCode: jest.fn(),
15 getUserInviteCodes: jest.fn(),
16 exchangeUpload: jest.fn(),
17 getUserInfo: jest.fn()
18}));
19
20// Mock react-router-dom hooks
21jest.mock('react-router-dom', () => ({
22 ...jest.requireActual('react-router-dom'),
23 useNavigate: jest.fn(),
24 useLocation: jest.fn()
25}));
26
27describe('Exchange Component', () => {
28 const mockNavigate = jest.fn();
29 const mockLocation = {
30 pathname: '/personal/exchange',
31 state: { dashboardTab: 'exchange' }
32 };
33
34 const mockUserInfo = {
35 magicPoints: 100,
36 username: 'testuser'
37 };
38
39 const mockInviteCodes = [
40 { code: 'ABCD-1234', isUsed: false },
41 { code: 'EFGH-5678', isUsed: true }
42 ];
43
44 beforeEach(() => {
45 useNavigate.mockReturnValue(mockNavigate);
46 useLocation.mockReturnValue(mockLocation);
47 jest.clearAllMocks();
48
49 // 设置默认 mock 返回值
50 getUserInfo.mockResolvedValue(mockUserInfo);
51 getUserInviteCodes.mockResolvedValue(mockInviteCodes);
52 generateInviteCode.mockResolvedValue({ code: 'NEW-CODE', isUsed: false });
53 exchangeUpload.mockResolvedValue({ success: true });
54 });
55
56 it('应该正确加载并显示用户信息和邀请码', async () => {
57 render(
58 <MemoryRouter>
59 <Exchange />
60 </MemoryRouter>
61 );
62
63 // 初始加载状态
64 expect(screen.getByText('加载中...')).toBeInTheDocument();
65
66 // 等待数据加载完成
67 await waitFor(() => {
68 expect(screen.getByText('兑换区')).toBeInTheDocument();
69 expect(screen.getByText('当前魔力值: 100')).toBeInTheDocument();
70 expect(screen.getByText('ABCD-1234')).toBeInTheDocument();
71 expect(screen.getByText('EFGH-5678')).toBeInTheDocument();
72 expect(screen.getByText('可用')).toBeInTheDocument();
73 expect(screen.getByText('已使用')).toBeInTheDocument();
74 });
75 });
76
77 it('应该处理生成邀请码操作', async () => {
78 render(
79 <MemoryRouter>
80 <Exchange />
81 </MemoryRouter>
82 );
83
84 await waitFor(() => {
85 // 使用更精确的选择器定位按钮
86 const generateButtons = screen.getAllByRole('button', { name: '兑换邀请码' });
87 // 选择第一个按钮(或根据实际情况选择正确的按钮)
88 fireEvent.click(generateButtons[0]);
89 });
90
91 expect(generateInviteCode).toHaveBeenCalled();
92 await waitFor(() => {
93 expect(getUserInfo).toHaveBeenCalledTimes(2); // 初始加载 + 生成后刷新
94 });
95 });
96
97 it('应该处理兑换上传量操作', async () => {
98 render(
99 <MemoryRouter>
100 <Exchange />
101 </MemoryRouter>
102 );
103
104 await waitFor(() => {
105 const input = screen.getByPlaceholderText('输入要兑换的魔力值');
106 const exchangeButton = screen.getByRole('button', { name: '兑换上传量' });
107
108 // 输入有效值
109 fireEvent.change(input, { target: { value: '50' } });
110 fireEvent.click(exchangeButton);
111 });
112
113 expect(exchangeUpload).toHaveBeenCalledWith(50);
114 await waitFor(() => {
115 expect(getUserInfo).toHaveBeenCalledTimes(2); // 初始加载 + 兑换后刷新
116 });
117 });
118
119
120 it('应该处理返回按钮点击', async () => {
121 render(
122 <MemoryRouter>
123 <Exchange />
124 </MemoryRouter>
125 );
126
127 await waitFor(() => {
DREW5b1883e2025-06-07 10:41:32 +0800128 const backButton = screen.getByText(/返回个人中心/);
Akane12173a7bb972025-06-01 01:05:27 +0800129 fireEvent.click(backButton);
130
131 expect(mockNavigate).toHaveBeenCalledWith('/personal', {
132 state: {
133 fromSubpage: true,
134 dashboardTab: 'exchange'
135 },
136 replace: true
137 });
138 });
139 });
140
141 it('应该显示错误信息当API调用失败', async () => {
142 getUserInfo.mockRejectedValueOnce(new Error('获取用户信息失败'));
143
144 render(
145 <MemoryRouter>
146 <Exchange />
147 </MemoryRouter>
148 );
149
150 await waitFor(() => {
151 expect(screen.getByText('错误: 获取用户信息失败')).toBeInTheDocument();
152 });
153 });
154
155 it('应该禁用兑换按钮当魔力值不足', async () => {
156 getUserInfo.mockResolvedValueOnce({ magicPoints: 5 }); // 设置魔力值不足
157
158 render(
159 <MemoryRouter>
160 <Exchange />
161 </MemoryRouter>
162 );
163
164 await waitFor(() => {
165 const inviteButtons = screen.getAllByRole('button', { name: '兑换邀请码' });
166 expect(inviteButtons[0]).toBeDisabled();
167 });
168 });
169
170 it('应该正确处理空邀请码列表', async () => {
171 getUserInviteCodes.mockResolvedValueOnce([]);
172
173 render(
174 <MemoryRouter>
175 <Exchange />
176 </MemoryRouter>
177 );
178
179 await waitFor(() => {
180 expect(screen.queryByText('我的邀请码')).not.toBeInTheDocument();
181 });
182 });
183
184 it('应该显示加载状态', async () => {
185 // 延迟API响应以测试加载状态
186 getUserInfo.mockImplementation(() => new Promise(() => {}));
187
188 render(
189 <MemoryRouter>
190 <Exchange />
191 </MemoryRouter>
192 );
193
194 expect(screen.getByText('加载中...')).toBeInTheDocument();
195 });
196});