个人中心全部,模糊乱序搜索,类型筛选

Change-Id: Id635654fccccaea80bfbf4d1480abd55f7d12046
diff --git a/src/components/Personal/Exchange.test.jsx b/src/components/Personal/Exchange.test.jsx
new file mode 100644
index 0000000..20fe641
--- /dev/null
+++ b/src/components/Personal/Exchange.test.jsx
@@ -0,0 +1,196 @@
+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();

+  });

+});
\ No newline at end of file