blob: b342387e01305cdba1da3ca26cde84af5bb2ff83 [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();
San3yuan03ab0642025-04-29 18:00:25 +080036 const mockPostRefresh = jest.fn();
37 const mockGetRefresh = jest.fn();
38
San3yuan6f2ed692025-04-16 20:24:49 +080039 beforeEach(() => {
40 // 初始化模拟函数返回值
41 mockUseAppDispatch.mockReturnValue(mockDispatch);
42 mockUseNavigate.mockReturnValue(mockNavigate);
43 mockUseSelector.mockImplementation((selector) => selector({ user: { userName: '' } }));
44
45 // 默认模拟 useApi 返回正常状态
San3yuan03ab0642025-04-29 18:00:25 +080046 mockUseApi
47 .mockReturnValueOnce({
San3yuan6f2ed692025-04-16 20:24:49 +080048 data: { token: 'mock-token' },
49 loading: false,
50 error: null,
San3yuan03ab0642025-04-29 18:00:25 +080051 refresh: mockPostRefresh,
52 })
53 .mockReturnValueOnce({
54 data:{
55 'userId' : '001',
56 'userName' : 'san3yuan',
57 'role' : 'manager',
58 'uploadTraffic' : 0,
59 'downloadTraffic': 0,
60 'downloadPoints' : 0,
61 'avatar' : 'https://www.w3school.com.cn/i/photo/tulip.jpg',
62 },
63 loading: false,
64 error: null,
65 refresh: mockGetRefresh,
66 })
67 ;
San3yuan6f2ed692025-04-16 20:24:49 +080068 });
69
70 afterEach(() => {
71 jest.clearAllMocks();
72 });
73
74 // 测试 1: 基础渲染
75 it('渲染所有输入框和按钮', () => {
76 render(<Login />);
77 expect(screen.getByPlaceholderText('Enter your email')).toBeInTheDocument();
78 expect(screen.getByPlaceholderText('Enter your password')).toBeInTheDocument();
79 expect(screen.getByText('登录')).toBeInTheDocument();
80 expect(screen.getByText('注册')).toBeInTheDocument();
81 expect(screen.getByText('忘记密码')).toBeInTheDocument();
82 });
83
84 // 测试 2: 登录成功流程
85 it('点击登录按钮触发API请求、Redux更新和导航', async () => {
86 // 模拟 API 返回有效数据
San3yuan03ab0642025-04-29 18:00:25 +080087 mockPostRefresh.mockResolvedValue({ token: 'mock-token' });
88 mockGetRefresh.mockResolvedValue({
89 'userId' : '001',
90 'userName' : 'san3yuan',
91 'role' : 'manager',
92 'uploadTraffic' : 0,
93 'downloadTraffic': 0,
94 'downloadPoints' : 0,
95 'avatar' : 'https://www.w3school.com.cn/i/photo/tulip.jpg',
96 });
San3yuan6f2ed692025-04-16 20:24:49 +080097
98 render(<Login />);
San3yuan03ab0642025-04-29 18:00:25 +080099 jest.useFakeTimers();
San3yuan6f2ed692025-04-16 20:24:49 +0800100 fireEvent.click(screen.getByText('登录'));
San3yuan03ab0642025-04-29 18:00:25 +0800101 jest.runAllTimers();
San3yuan6f2ed692025-04-16 20:24:49 +0800102 await waitFor(() => {
103 // 验证 dispatch 调用
San3yuan03ab0642025-04-29 18:00:25 +0800104 expect(mockPostRefresh).toHaveBeenCalled();
105
106 // 验证Redux更新
107 expect(mockDispatch).toHaveBeenNthCalledWith(1, {
San3yuan6f2ed692025-04-16 20:24:49 +0800108 type: 'user/login',
San3yuan03ab0642025-04-29 18:00:25 +0800109 payload: { token: 'mock-token' }
110 });
111
112 // 验证第二次API调用(用户信息)
113 expect(mockGetRefresh).toHaveBeenCalled();
114
115 // 验证用户信息更新
116 expect(mockDispatch).toHaveBeenNthCalledWith(2, {
117 type: 'user/getUserInfo',
118 payload: {
119 'userId' : '001',
120 'userName' : 'san3yuan',
121 'role' : 'manager',
122 'uploadTraffic' : 0,
123 'downloadTraffic': 0,
124 'downloadPoints' : 0,
125 'avatar' : 'https://www.w3school.com.cn/i/photo/tulip.jpg',
126 }
San3yuan6f2ed692025-04-16 20:24:49 +0800127 });
128 });
San3yuan03ab0642025-04-29 18:00:25 +0800129 });
San3yuan6f2ed692025-04-16 20:24:49 +0800130 });