| import React from 'react'; | |
| import { render, screen, fireEvent, waitFor } from '@testing-library/react'; | |
| import { MemoryRouter, Route, Routes, useNavigate, useLocation } from 'react-router-dom'; | |
| import HelpDetail from './HelpDetail'; | |
| import * as helpPostApi from '../api/helpPost'; | |
| import * as helpCommentApi from '../api/helpComment'; | |
| // Mock API 模块 | |
| jest.mock('../api/helpPost'); | |
| jest.mock('../api/helpComment'); | |
| // Mock 路由钩子 | |
| const mockNavigate = jest.fn(); | |
| jest.mock('react-router-dom', () => ({ | |
| ...jest.requireActual('react-router-dom'), | |
| useNavigate: () => mockNavigate, | |
| useLocation: jest.fn(), | |
| })); | |
| describe('HelpDetail 组件', () => { | |
| const mockPost = { | |
| id: '1', | |
| title: '测试求助帖', | |
| content: '这是一个测试求助内容', | |
| authorId: 'user1', | |
| createTime: '2023-01-01T00:00:00Z', | |
| likeCount: 5, | |
| replyCount: 3, | |
| isSolved: false, | |
| }; | |
| const mockComments = [ | |
| { | |
| id: 'c1', | |
| content: '测试评论1', | |
| authorId: 'user2', | |
| createTime: '2023-01-01T01:00:00Z', | |
| likeCount: 2, | |
| replies: [ | |
| { | |
| id: 'c1r1', | |
| content: '测试回复1', | |
| authorId: 'user3', | |
| createTime: '2023-01-01T02:00:00Z', | |
| likeCount: 1, | |
| } | |
| ] | |
| } | |
| ]; | |
| beforeEach(() => { | |
| // 重置 mock 函数 | |
| mockNavigate.mockClear(); | |
| // 设置模拟的 API 响应 | |
| helpPostApi.getPostDetail.mockResolvedValue({ | |
| data: { | |
| code: 200, | |
| data: { | |
| post: mockPost, | |
| comments: mockComments, | |
| } | |
| } | |
| }); | |
| // 模拟 useLocation | |
| useLocation.mockReturnValue({ | |
| state: { fromTab: 'help' } | |
| }); | |
| // 模拟 localStorage | |
| Storage.prototype.getItem = jest.fn((key) => { | |
| if (key === 'username') return 'testuser'; | |
| return null; | |
| }); | |
| }); | |
| const renderComponent = () => { | |
| return render( | |
| <MemoryRouter initialEntries={['/help/1']}> | |
| <Routes> | |
| <Route path="/help/:id" element={<HelpDetail />} /> | |
| {/* 添加一个模拟的求助列表路由用于导航测试 */} | |
| <Route path="/dashboard/help" element={<div>求助列表</div>} /> | |
| </Routes> | |
| </MemoryRouter> | |
| ); | |
| }; | |
| it('应该正确加载和显示求助帖详情', async () => { | |
| renderComponent(); | |
| // 检查加载状态 | |
| expect(screen.getByText('加载中...')).toBeInTheDocument(); | |
| // 等待数据加载完成 | |
| await waitFor(() => { | |
| expect(screen.getByText('测试求助帖')).toBeInTheDocument(); | |
| expect(screen.getByText('这是一个测试求助内容')).toBeInTheDocument(); | |
| expect(screen.getByText('user1')).toBeInTheDocument(); | |
| }); | |
| }); | |
| it('应该能够点赞帖子', async () => { | |
| renderComponent(); | |
| await waitFor(() => { | |
| expect(screen.getByText('测试求助帖')).toBeInTheDocument(); | |
| }); | |
| fireEvent.click(screen.getByText(/点赞 \(5\)/)); | |
| await waitFor(() => { | |
| expect(helpPostApi.likePost).toHaveBeenCalledWith('1'); | |
| }); | |
| }); | |
| it('应该能够提交评论', async () => { | |
| renderComponent(); | |
| await waitFor(() => { | |
| expect(screen.getByText('测试求助帖')).toBeInTheDocument(); | |
| }); | |
| const commentInput = screen.getByPlaceholderText('写下你的评论...'); | |
| fireEvent.change(commentInput, { target: { value: '新评论' } }); | |
| fireEvent.click(screen.getByText('发表评论')); | |
| await waitFor(() => { | |
| expect(helpPostApi.addPostComment).toHaveBeenCalledWith('1', { | |
| content: '新评论', | |
| authorId: 'testuser' | |
| }); | |
| }); | |
| }); | |
| it('应该能够点赞评论', async () => { | |
| renderComponent(); | |
| await waitFor(() => { | |
| expect(screen.getByText('测试评论1')).toBeInTheDocument(); | |
| }); | |
| fireEvent.click(screen.getAllByText(/👍 \(2\)/)[0]); | |
| await waitFor(() => { | |
| expect(helpCommentApi.likePostComment).toHaveBeenCalledWith('c1'); | |
| }); | |
| }); | |
| it('应该能够打开和关闭回复模态框', async () => { | |
| renderComponent(); | |
| await waitFor(() => { | |
| expect(screen.getByText('测试评论1')).toBeInTheDocument(); | |
| }); | |
| // 点击回复按钮 | |
| fireEvent.click(screen.getAllByText('回复')[0]); | |
| // 检查模态框是否打开 | |
| await waitFor(() => { | |
| expect(screen.getByText('回复 @user2')).toBeInTheDocument(); | |
| }); | |
| // 点击关闭按钮 | |
| fireEvent.click(screen.getByText('×')); | |
| // 检查模态框是否关闭 | |
| await waitFor(() => { | |
| expect(screen.queryByText('回复 @user2')).not.toBeInTheDocument(); | |
| }); | |
| }); | |
| it('应该能够返回求助区', async () => { | |
| renderComponent(); | |
| await waitFor(() => { | |
| expect(screen.getByText('测试求助帖')).toBeInTheDocument(); | |
| }); | |
| fireEvent.click(screen.getByRole('button', { name: /返回/i })); | |
| // 修正后的断言(不再验证 state) | |
| expect(mockNavigate).toHaveBeenCalledWith('/dashboard/help'); | |
| }); | |
| }); |