blob: 936d9fbe6253bcb8335b281ec58d2326510d921a [file] [log] [blame]
San3yuan6f2ed692025-04-16 20:24:49 +08001import React from 'react';
2import { render, screen, fireEvent, waitFor } from '@testing-library/react';
3import '@testing-library/jest-dom';
4import Login from '../src/views/login/login';
5import { useApi } from '@/hooks/request';
6import { useAppDispatch } from '@/hooks/store';
7import { useNavigate } from 'react-router';
8import { useSelector } from 'react-redux';
9
10
11jest.mock('@/hooks/request', () => ({
12 useApi: jest.fn(),
13}));
14// 模拟所有外部依赖
15jest.mock('@/hooks/store', () => ({
16 useAppDispatch: jest.fn(),
17}));
18
19jest.mock('react-router', () => ({
20 useNavigate: jest.fn(),
21}));
22
23jest.mock('react-redux', () => ({
24 useSelector: jest.fn(),
25}));
26
27// 类型安全:明确模拟函数的返回类型
28const mockUseApi = useApi as jest.MockedFunction<typeof useApi>;
29const mockUseAppDispatch = useAppDispatch as jest.MockedFunction<typeof useAppDispatch>;
30const mockUseNavigate = useNavigate as jest.MockedFunction<typeof useNavigate>;
31const mockUseSelector = useSelector as jest.MockedFunction<typeof useSelector>;
32
33describe('Login Component', () => {
34 const mockDispatch = jest.fn();
35 const mockNavigate = jest.fn();
36 const mockRefresh = jest.fn();
37
38 beforeEach(() => {
39 // 初始化模拟函数返回值
40 mockUseAppDispatch.mockReturnValue(mockDispatch);
41 mockUseNavigate.mockReturnValue(mockNavigate);
42 mockUseSelector.mockImplementation((selector) => selector({ user: { userName: '' } }));
43
44 // 默认模拟 useApi 返回正常状态
45 mockUseApi.mockReturnValue({
46 data: { token: 'mock-token' },
47 loading: false,
48 error: null,
49 refresh: mockRefresh,
50 });
51 });
52
53 afterEach(() => {
54 jest.clearAllMocks();
55 });
56
57 // 测试 1: 基础渲染
58 it('渲染所有输入框和按钮', () => {
59 render(<Login />);
60 expect(screen.getByPlaceholderText('Enter your email')).toBeInTheDocument();
61 expect(screen.getByPlaceholderText('Enter your password')).toBeInTheDocument();
62 expect(screen.getByText('登录')).toBeInTheDocument();
63 expect(screen.getByText('注册')).toBeInTheDocument();
64 expect(screen.getByText('忘记密码')).toBeInTheDocument();
65 });
66
67 // 测试 2: 登录成功流程
68 it('点击登录按钮触发API请求、Redux更新和导航', async () => {
69 // 模拟 API 返回有效数据
70 mockRefresh.mockResolvedValue({ token: 'mock-token' }); // 关键:必须返回 Promise
71 mockUseApi.mockReturnValue({
72 data: { token: 'mock-token' },
73 loading: false,
74 error: null,
75 refresh: mockRefresh,
76 });
77
78 render(<Login />);
79
80 fireEvent.click(screen.getByText('登录'));
81
82 await waitFor(() => {
83 // 验证 dispatch 调用
84 expect(mockDispatch).toHaveBeenCalledWith({
85 type: 'user/login',
86 payload: { token: 'mock-token' },
87 });
88 });
89 });
90
91
92 });