blob: 936d9fbe6253bcb8335b281ec58d2326510d921a [file] [log] [blame]
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import Login from '../src/views/login/login';
import { useApi } from '@/hooks/request';
import { useAppDispatch } from '@/hooks/store';
import { useNavigate } from 'react-router';
import { useSelector } from 'react-redux';
jest.mock('@/hooks/request', () => ({
useApi: jest.fn(),
}));
// 模拟所有外部依赖
jest.mock('@/hooks/store', () => ({
useAppDispatch: jest.fn(),
}));
jest.mock('react-router', () => ({
useNavigate: jest.fn(),
}));
jest.mock('react-redux', () => ({
useSelector: jest.fn(),
}));
// 类型安全:明确模拟函数的返回类型
const mockUseApi = useApi as jest.MockedFunction<typeof useApi>;
const mockUseAppDispatch = useAppDispatch as jest.MockedFunction<typeof useAppDispatch>;
const mockUseNavigate = useNavigate as jest.MockedFunction<typeof useNavigate>;
const mockUseSelector = useSelector as jest.MockedFunction<typeof useSelector>;
describe('Login Component', () => {
const mockDispatch = jest.fn();
const mockNavigate = jest.fn();
const mockRefresh = jest.fn();
beforeEach(() => {
// 初始化模拟函数返回值
mockUseAppDispatch.mockReturnValue(mockDispatch);
mockUseNavigate.mockReturnValue(mockNavigate);
mockUseSelector.mockImplementation((selector) => selector({ user: { userName: '' } }));
// 默认模拟 useApi 返回正常状态
mockUseApi.mockReturnValue({
data: { token: 'mock-token' },
loading: false,
error: null,
refresh: mockRefresh,
});
});
afterEach(() => {
jest.clearAllMocks();
});
// 测试 1: 基础渲染
it('渲染所有输入框和按钮', () => {
render(<Login />);
expect(screen.getByPlaceholderText('Enter your email')).toBeInTheDocument();
expect(screen.getByPlaceholderText('Enter your password')).toBeInTheDocument();
expect(screen.getByText('登录')).toBeInTheDocument();
expect(screen.getByText('注册')).toBeInTheDocument();
expect(screen.getByText('忘记密码')).toBeInTheDocument();
});
// 测试 2: 登录成功流程
it('点击登录按钮触发API请求、Redux更新和导航', async () => {
// 模拟 API 返回有效数据
mockRefresh.mockResolvedValue({ token: 'mock-token' }); // 关键:必须返回 Promise
mockUseApi.mockReturnValue({
data: { token: 'mock-token' },
loading: false,
error: null,
refresh: mockRefresh,
});
render(<Login />);
fireEvent.click(screen.getByText('登录'));
await waitFor(() => {
// 验证 dispatch 调用
expect(mockDispatch).toHaveBeenCalledWith({
type: 'user/login',
payload: { token: 'mock-token' },
});
});
});
});