完成上传下载连接,公告管理与详情页面,求种区页面,轮播图折扣显示,修改部分bug

Change-Id: I86fc294e32911cb3426a8b16f90aca371f975c11
diff --git a/src/components/RequestDetail.test.jsx b/src/components/RequestDetail.test.jsx
new file mode 100644
index 0000000..8ec34c2
--- /dev/null
+++ b/src/components/RequestDetail.test.jsx
@@ -0,0 +1,209 @@
+import React from 'react';
+import { render, screen, fireEvent, waitFor } from '@testing-library/react';
+import { MemoryRouter, Route, Routes } from 'react-router-dom';
+import RequestDetail from './RequestDetail';
+import { isFormData } from 'axios';
+
+const mockNavigate = jest.fn();
+
+
+// 明确 mock API 模块
+jest.mock('../api/requestPost', () => ({
+  getRequestPostDetail: jest.fn(),
+  addRequestPostComment: jest.fn(),
+  likeRequestPost: jest.fn(),
+  deleteRequestPost: jest.fn()
+}));
+
+jest.mock('../api/requestComment', () => ({
+  likeRequestPostComment: jest.fn(),
+  getRequestCommentReplies: jest.fn(),
+  addRequestCommentReply: jest.fn(),
+  deleteRequestComment: jest.fn()
+}));
+
+jest.mock('react-router-dom', () => ({
+  ...jest.requireActual('react-router-dom'),
+  useNavigate: () => mockNavigate,
+  useLocation: jest.fn()
+}));
+
+// 导入 mock 后的 API
+import * as requestPostApi from '../api/requestPost';
+import * as requestCommentApi from '../api/requestComment';
+
+describe('RequestDetail 组件', () => {
+  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(() => {
+    jest.clearAllMocks();
+    
+    requestPostApi.getRequestPostDetail.mockResolvedValue({
+      data: {
+        code: 200,
+        data: {
+          post: mockPost,
+          comments: mockComments,
+        }
+      }
+    });
+
+    // 模拟 useLocation
+    require('react-router-dom').useLocation.mockReturnValue({
+      state: { fromTab: 'request' }
+    });
+
+    // 模拟 localStorage
+    Storage.prototype.getItem = jest.fn((key) => {
+      if (key === 'username') return 'testuser';
+      return null;
+    });
+  });
+
+  const renderComponent = () => {
+    return render(
+      <MemoryRouter initialEntries={['/request/1']}>
+        <Routes>
+          <Route path="/request/:id" element={<RequestDetail />} />
+          {/* 添加一个模拟的求助列表路由用于导航测试 */}
+          <Route path="/dashboard/request" element={<div>求助列表</div>} />
+        </Routes>
+      </MemoryRouter>
+    );
+  };
+
+  it('应该正确加载和显示求助帖详情', async () => {
+    renderComponent();
+
+    // 检查加载状态
+    expect(screen.getByText('加载中...')).toBeInTheDocument();
+
+    // 增加超时时间
+    await waitFor(() => {
+        expect(screen.getByText(mockPost.title)).toBeInTheDocument();
+    }, { timeout: 3000 });
+
+    // 等待数据加载完成
+     await waitFor(() => {
+      expect(screen.getByText(mockPost.title)).toBeInTheDocument();
+      expect(screen.getByText(mockPost.content)).toBeInTheDocument();
+      expect(screen.getByText(mockPost.authorId)).toBeInTheDocument();
+    });
+  });
+  
+  it('应该能够点赞帖子', async () => {
+    renderComponent();
+
+    await waitFor(() => {
+      expect(screen.getByText(mockPost.title)).toBeInTheDocument();
+    });
+
+    const likeButton = screen.getByRole('button', { name: /点赞 \(\d+\)/ });
+    fireEvent.click(likeButton);
+
+    await waitFor(() => {
+      expect(requestPostApi.likeRequestPost).toHaveBeenCalledWith('1');
+    });
+  });
+
+  it('应该能够提交评论', async () => {
+    renderComponent();
+
+    await waitFor(() => {
+      expect(screen.getByText(mockPost.title)).toBeInTheDocument();
+    });
+
+    const commentInput = screen.getByPlaceholderText('写下你的评论...');
+    fireEvent.change(commentInput, { target: { value: '新评论' } });
+    
+    const submitButton = screen.getByRole('button', { name: '发表评论' });
+    fireEvent.click(submitButton);
+
+    await waitFor(() => {
+      expect(requestPostApi.addRequestPostComment).toHaveBeenCalled();
+    });
+  });
+
+  it('应该能够点赞评论', async () => {
+    renderComponent();
+
+    await waitFor(() => {
+      expect(screen.getByText(mockComments[0].content)).toBeInTheDocument();
+    });
+
+    const likeButtons = screen.getAllByRole('button', { name: /👍 \(\d+\)/ });
+    fireEvent.click(likeButtons[0]);
+
+    await waitFor(() => {
+      expect(requestCommentApi.likeRequestPostComment).toHaveBeenCalledWith('c1');
+    });
+  });
+
+  it('应该能够打开和关闭回复模态框', async () => {
+    renderComponent();
+
+    await waitFor(() => {
+      expect(screen.getByText(mockComments[0].content)).toBeInTheDocument();
+    });
+
+    // 点击回复按钮
+    const replyButtons = screen.getAllByRole('button', { name: '回复' });
+    fireEvent.click(replyButtons[0]);
+
+    // 检查模态框是否打开
+    await waitFor(() => {
+      expect(screen.getByText(`回复 @${mockComments[0].authorId}`)).toBeInTheDocument();
+    });
+
+    // 点击关闭按钮
+    const closeButton = screen.getByRole('button', { name: '×' });
+    fireEvent.click(closeButton);
+
+    // 检查模态框是否关闭
+    await waitFor(() => {
+      expect(screen.queryByText(`回复 @${mockComments[0].authorId}`)).not.toBeInTheDocument();
+    });
+  });
+
+  it('应该能够返回求助区', async () => {
+    renderComponent();
+  
+    await waitFor(() => {
+      expect(screen.getByText(mockPost.title)).toBeInTheDocument();
+    });
+  
+    const backButton = screen.getByRole('button', { name: /返回/i });
+    fireEvent.click(backButton);
+  
+    expect(mockNavigate).toHaveBeenCalledWith('/dashboard/request');
+
+  });
+});
\ No newline at end of file