Akane1217 | 65b61a7 | 2025-05-17 13:52:25 +0800 | [diff] [blame] | 1 | import React from 'react';
|
| 2 | import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
| 3 | import { MemoryRouter, Route, Routes, useNavigate, useLocation } from 'react-router-dom';
|
| 4 | import HelpDetail from './HelpDetail';
|
| 5 | import * as helpPostApi from '../api/helpPost';
|
| 6 | import * as helpCommentApi from '../api/helpComment';
|
| 7 |
|
| 8 | // Mock API 模块
|
| 9 | jest.mock('../api/helpPost');
|
| 10 | jest.mock('../api/helpComment');
|
| 11 |
|
| 12 | // Mock 路由钩子
|
| 13 | const mockNavigate = jest.fn();
|
| 14 | jest.mock('react-router-dom', () => ({
|
| 15 | ...jest.requireActual('react-router-dom'),
|
| 16 | useNavigate: () => mockNavigate,
|
| 17 | useLocation: jest.fn(),
|
| 18 | }));
|
| 19 |
|
| 20 | describe('HelpDetail 组件', () => {
|
| 21 | const mockPost = {
|
| 22 | id: '1',
|
| 23 | title: '测试求助帖',
|
| 24 | content: '这是一个测试求助内容',
|
| 25 | authorId: 'user1',
|
| 26 | createTime: '2023-01-01T00:00:00Z',
|
| 27 | likeCount: 5,
|
| 28 | replyCount: 3,
|
| 29 | isSolved: false,
|
| 30 | };
|
| 31 |
|
| 32 | const mockComments = [
|
| 33 | {
|
| 34 | id: 'c1',
|
| 35 | content: '测试评论1',
|
| 36 | authorId: 'user2',
|
| 37 | createTime: '2023-01-01T01:00:00Z',
|
| 38 | likeCount: 2,
|
| 39 | replies: [
|
| 40 | {
|
| 41 | id: 'c1r1',
|
| 42 | content: '测试回复1',
|
| 43 | authorId: 'user3',
|
| 44 | createTime: '2023-01-01T02:00:00Z',
|
| 45 | likeCount: 1,
|
| 46 | }
|
| 47 | ]
|
| 48 | }
|
| 49 | ];
|
| 50 |
|
| 51 | beforeEach(() => {
|
| 52 | // 重置 mock 函数
|
| 53 | mockNavigate.mockClear();
|
| 54 |
|
| 55 | // 设置模拟的 API 响应
|
DREW | ae420b2 | 2025-06-02 14:07:20 +0800 | [diff] [blame^] | 56 | helpPostApi.getHelpPostDetail.mockResolvedValue({
|
Akane1217 | 65b61a7 | 2025-05-17 13:52:25 +0800 | [diff] [blame] | 57 | data: {
|
| 58 | code: 200,
|
| 59 | data: {
|
| 60 | post: mockPost,
|
| 61 | comments: mockComments,
|
| 62 | }
|
| 63 | }
|
| 64 | });
|
| 65 |
|
| 66 | // 模拟 useLocation
|
| 67 | useLocation.mockReturnValue({
|
| 68 | state: { fromTab: 'help' }
|
| 69 | });
|
| 70 |
|
| 71 | // 模拟 localStorage
|
| 72 | Storage.prototype.getItem = jest.fn((key) => {
|
| 73 | if (key === 'username') return 'testuser';
|
| 74 | return null;
|
| 75 | });
|
| 76 | });
|
| 77 |
|
| 78 | const renderComponent = () => {
|
| 79 | return render(
|
| 80 | <MemoryRouter initialEntries={['/help/1']}>
|
| 81 | <Routes>
|
| 82 | <Route path="/help/:id" element={<HelpDetail />} />
|
| 83 | {/* 添加一个模拟的求助列表路由用于导航测试 */}
|
| 84 | <Route path="/dashboard/help" element={<div>求助列表</div>} />
|
| 85 | </Routes>
|
| 86 | </MemoryRouter>
|
| 87 | );
|
| 88 | };
|
| 89 |
|
| 90 | it('应该正确加载和显示求助帖详情', async () => {
|
| 91 | renderComponent();
|
| 92 |
|
| 93 | // 检查加载状态
|
| 94 | expect(screen.getByText('加载中...')).toBeInTheDocument();
|
| 95 |
|
| 96 | // 等待数据加载完成
|
| 97 | await waitFor(() => {
|
| 98 | expect(screen.getByText('测试求助帖')).toBeInTheDocument();
|
| 99 | expect(screen.getByText('这是一个测试求助内容')).toBeInTheDocument();
|
| 100 | expect(screen.getByText('user1')).toBeInTheDocument();
|
| 101 | });
|
| 102 | });
|
| 103 |
|
| 104 | it('应该能够点赞帖子', async () => {
|
| 105 | renderComponent();
|
| 106 |
|
| 107 | await waitFor(() => {
|
| 108 | expect(screen.getByText('测试求助帖')).toBeInTheDocument();
|
| 109 | });
|
| 110 |
|
| 111 | fireEvent.click(screen.getByText(/点赞 \(5\)/));
|
| 112 |
|
| 113 | await waitFor(() => {
|
DREW | ae420b2 | 2025-06-02 14:07:20 +0800 | [diff] [blame^] | 114 | expect(helpPostApi.likeHelpPost).toHaveBeenCalledWith('1');
|
Akane1217 | 65b61a7 | 2025-05-17 13:52:25 +0800 | [diff] [blame] | 115 | });
|
| 116 | });
|
| 117 |
|
| 118 | it('应该能够提交评论', async () => {
|
DREW | ae420b2 | 2025-06-02 14:07:20 +0800 | [diff] [blame^] | 119 | renderComponent();
|
Akane1217 | 65b61a7 | 2025-05-17 13:52:25 +0800 | [diff] [blame] | 120 |
|
DREW | ae420b2 | 2025-06-02 14:07:20 +0800 | [diff] [blame^] | 121 | await waitFor(() => {
|
| 122 | expect(screen.getByText('测试求助帖')).toBeInTheDocument();
|
Akane1217 | 65b61a7 | 2025-05-17 13:52:25 +0800 | [diff] [blame] | 123 | });
|
| 124 |
|
DREW | ae420b2 | 2025-06-02 14:07:20 +0800 | [diff] [blame^] | 125 | const commentInput = screen.getByPlaceholderText('写下你的评论...');
|
| 126 | fireEvent.change(commentInput, { target: { value: '新评论' } });
|
| 127 | fireEvent.click(screen.getByText('发表评论'));
|
| 128 |
|
| 129 | await waitFor(() => {
|
| 130 | expect(helpPostApi.addHelpPostComment).toHaveBeenCalled();
|
| 131 |
|
| 132 | const calledArgs = helpPostApi.addHelpPostComment.mock.calls[0];
|
| 133 | expect(calledArgs[0]).toBe('1'); // postId
|
| 134 | const formData = calledArgs[1];
|
| 135 |
|
| 136 | expect(formData instanceof FormData).toBe(true);
|
| 137 | expect(formData.get('authorId')).toBe('testuser');
|
| 138 | expect(formData.get('content')).toBe('新评论');
|
| 139 | });
|
| 140 | });
|
Akane1217 | 65b61a7 | 2025-05-17 13:52:25 +0800 | [diff] [blame] | 141 | it('应该能够点赞评论', async () => {
|
| 142 | renderComponent();
|
| 143 |
|
| 144 | await waitFor(() => {
|
| 145 | expect(screen.getByText('测试评论1')).toBeInTheDocument();
|
| 146 | });
|
| 147 |
|
| 148 | fireEvent.click(screen.getAllByText(/👍 \(2\)/)[0]);
|
| 149 |
|
| 150 | await waitFor(() => {
|
DREW | ae420b2 | 2025-06-02 14:07:20 +0800 | [diff] [blame^] | 151 | expect(helpCommentApi.likeHelpPostComment).toHaveBeenCalledWith('c1');
|
Akane1217 | 65b61a7 | 2025-05-17 13:52:25 +0800 | [diff] [blame] | 152 | });
|
| 153 | });
|
| 154 |
|
| 155 | it('应该能够打开和关闭回复模态框', async () => {
|
| 156 | renderComponent();
|
| 157 |
|
| 158 | await waitFor(() => {
|
| 159 | expect(screen.getByText('测试评论1')).toBeInTheDocument();
|
| 160 | });
|
| 161 |
|
| 162 | // 点击回复按钮
|
| 163 | fireEvent.click(screen.getAllByText('回复')[0]);
|
| 164 |
|
| 165 | // 检查模态框是否打开
|
| 166 | await waitFor(() => {
|
| 167 | expect(screen.getByText('回复 @user2')).toBeInTheDocument();
|
| 168 | });
|
| 169 |
|
| 170 | // 点击关闭按钮
|
| 171 | fireEvent.click(screen.getByText('×'));
|
| 172 |
|
| 173 | // 检查模态框是否关闭
|
| 174 | await waitFor(() => {
|
| 175 | expect(screen.queryByText('回复 @user2')).not.toBeInTheDocument();
|
| 176 | });
|
| 177 | });
|
| 178 |
|
| 179 | it('应该能够返回求助区', async () => {
|
| 180 | renderComponent();
|
| 181 |
|
| 182 | await waitFor(() => {
|
| 183 | expect(screen.getByText('测试求助帖')).toBeInTheDocument();
|
| 184 | });
|
| 185 |
|
| 186 | fireEvent.click(screen.getByRole('button', { name: /返回/i }));
|
| 187 |
|
| 188 | // 修正后的断言(不再验证 state)
|
| 189 | expect(mockNavigate).toHaveBeenCalledWith('/dashboard/help');
|
| 190 | });
|
| 191 | }); |