| // Setting.test.jsx | |
| import React from 'react'; | |
| import { render, screen, waitFor, fireEvent } from '@testing-library/react'; | |
| import { MemoryRouter, useNavigate, useLocation } from 'react-router-dom'; | |
| import Setting from './Setting'; | |
| import { getUserInfo, updatePassword } from '../../api/personal'; | |
| // Mock API 调用 | |
| jest.mock('../../api/personal', () => ({ | |
| getUserInfo: jest.fn(), | |
| updatePassword: jest.fn() | |
| })); | |
| // Mock react-router-dom hooks | |
| jest.mock('react-router-dom', () => ({ | |
| ...jest.requireActual('react-router-dom'), | |
| useNavigate: jest.fn(), | |
| useLocation: jest.fn() | |
| })); | |
| describe('Setting Component', () => { | |
| const mockNavigate = jest.fn(); | |
| const mockLocation = { | |
| pathname: '/personal/setting', | |
| state: { dashboardTab: 'settings' } | |
| }; | |
| beforeEach(() => { | |
| useNavigate.mockReturnValue(mockNavigate); | |
| useLocation.mockReturnValue(mockLocation); | |
| // 重置所有 mock | |
| jest.clearAllMocks(); | |
| // 设置默认 mock 返回值 | |
| getUserInfo.mockResolvedValue({ | |
| username: 'testuser', | |
| email: 'test@example.com' | |
| }); | |
| updatePassword.mockResolvedValue({ success: true }); | |
| }); | |
| it('应该正确加载并显示用户信息', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Setting /> | |
| </MemoryRouter> | |
| ); | |
| await waitFor(() => { | |
| expect(screen.getByText('个人设置')).toBeInTheDocument(); | |
| expect(screen.getByText('账户信息')).toBeInTheDocument(); | |
| expect(screen.getByText('用户名:')).toBeInTheDocument(); | |
| expect(screen.getByText('testuser')).toBeInTheDocument(); | |
| expect(screen.getByRole('heading', { name: '修改密码' })).toBeInTheDocument(); | |
| }); | |
| }); | |
| it('应该处理密码修改表单提交', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Setting /> | |
| </MemoryRouter> | |
| ); | |
| // 填写表单 | |
| fireEvent.change(screen.getByLabelText('原密码:'), { | |
| target: { value: 'oldpassword123' } | |
| }); | |
| fireEvent.change(screen.getByLabelText('新密码:'), { | |
| target: { value: 'newpassword123' } | |
| }); | |
| fireEvent.change(screen.getByLabelText('确认新密码:'), { | |
| target: { value: 'newpassword123' } | |
| }); | |
| // 提交表单 | |
| fireEvent.click(screen.getByRole('button', { name: '修改密码' })); | |
| await waitFor(() => { | |
| expect(updatePassword).toHaveBeenCalledWith('oldpassword123', 'newpassword123'); | |
| expect(screen.getByText('密码修改成功')).toBeInTheDocument(); | |
| }); | |
| }); | |
| it('应该处理API错误', async () => { | |
| updatePassword.mockRejectedValue(new Error('原密码不正确')); | |
| render( | |
| <MemoryRouter> | |
| <Setting /> | |
| </MemoryRouter> | |
| ); | |
| // 填写表单 | |
| fireEvent.change(screen.getByLabelText('原密码:'), { | |
| target: { value: 'wrongpassword' } | |
| }); | |
| fireEvent.change(screen.getByLabelText('新密码:'), { | |
| target: { value: 'newpassword123' } | |
| }); | |
| fireEvent.change(screen.getByLabelText('确认新密码:'), { | |
| target: { value: 'newpassword123' } | |
| }); | |
| // 提交表单 | |
| fireEvent.click(screen.getByRole('button', { name: '修改密码' })); | |
| await waitFor(() => { | |
| expect(screen.getByText('原密码不正确')).toBeInTheDocument(); | |
| }); | |
| }); | |
| it('应该显示加载状态', async () => { | |
| // 延迟API响应以测试加载状态 | |
| updatePassword.mockImplementation(() => new Promise(() => {})); | |
| render( | |
| <MemoryRouter> | |
| <Setting /> | |
| </MemoryRouter> | |
| ); | |
| // 填写表单 | |
| fireEvent.change(screen.getByLabelText('原密码:'), { | |
| target: { value: 'oldpassword123' } | |
| }); | |
| fireEvent.change(screen.getByLabelText('新密码:'), { | |
| target: { value: 'newpassword123' } | |
| }); | |
| fireEvent.change(screen.getByLabelText('确认新密码:'), { | |
| target: { value: 'newpassword123' } | |
| }); | |
| // 提交表单 | |
| fireEvent.click(screen.getByRole('button', { name: '修改密码' })); | |
| // 检查加载状态 | |
| expect(screen.getByText('处理中...')).toBeInTheDocument(); | |
| expect(screen.getByRole('button', { name: '处理中...' })).toBeDisabled(); | |
| }); | |
| it('应该处理返回按钮点击', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Setting /> | |
| </MemoryRouter> | |
| ); | |
| const backButton = screen.getByText(/返回个人中心/); | |
| fireEvent.click(backButton); | |
| expect(mockNavigate).toHaveBeenCalledWith('/personal', { | |
| state: { | |
| fromSubpage: true, | |
| dashboardTab: 'settings' | |
| }, | |
| replace: true | |
| }); | |
| }); | |
| it('应该清空表单并显示成功消息', async () => { | |
| render( | |
| <MemoryRouter> | |
| <Setting /> | |
| </MemoryRouter> | |
| ); | |
| // 填写表单 | |
| fireEvent.change(screen.getByLabelText('原密码:'), { | |
| target: { value: 'oldpassword123' } | |
| }); | |
| fireEvent.change(screen.getByLabelText('新密码:'), { | |
| target: { value: 'newpassword123' } | |
| }); | |
| fireEvent.change(screen.getByLabelText('确认新密码:'), { | |
| target: { value: 'newpassword123' } | |
| }); | |
| // 提交表单 | |
| fireEvent.click(screen.getByRole('button', { name: '修改密码' })); | |
| await waitFor(() => { | |
| // 检查表单是否清空 | |
| expect(screen.getByLabelText('原密码:')).toHaveValue(''); | |
| expect(screen.getByLabelText('新密码:')).toHaveValue(''); | |
| expect(screen.getByLabelText('确认新密码:')).toHaveValue(''); | |
| // 检查成功消息 | |
| expect(screen.getByText('密码修改成功')).toBeInTheDocument(); | |
| }); | |
| }); | |
| }); |