| import React from 'react'; |
| import { render, screen, fireEvent, waitFor } from '@testing-library/react'; |
| import { MemoryRouter, Route, Routes, useNavigate, useParams, useLocation } from 'react-router-dom'; |
| import AnnouncementDetail from './AnnouncementDetail'; |
| import * as announcementApi from '../api/announcement'; |
| |
| // Mock API 模块 |
| jest.mock('../api/announcement'); |
| |
| // Mock 路由钩子 |
| const mockNavigate = jest.fn(); |
| jest.mock('react-router-dom', () => ({ |
| ...jest.requireActual('react-router-dom'), |
| useNavigate: () => mockNavigate, |
| useParams: jest.fn(), |
| useLocation: jest.fn(), |
| })); |
| |
| describe('AnnouncementDetail 组件', () => { |
| const mockAnnouncement = { |
| id: 1, |
| title: '测试公告标题', |
| content: '这是测试公告内容\n这是第二行内容', |
| createTime: '2023-01-01T00:00:00Z', |
| }; |
| |
| beforeEach(() => { |
| mockNavigate.mockClear(); |
| |
| // 设置模拟的 API 响应 |
| announcementApi.getAnnouncementDetail.mockResolvedValue({ |
| data: { |
| code: 200, |
| data: { |
| announcement: mockAnnouncement, |
| }, |
| }, |
| }); |
| |
| // 模拟钩子 |
| useParams.mockReturnValue({ id: '1' }); |
| useLocation.mockReturnValue({ state: { fromTab: 'announcement' } }); |
| }); |
| |
| const renderComponent = () => { |
| return render( |
| <MemoryRouter initialEntries={['/announcement/1']}> |
| <Routes> |
| <Route path="/announcement/:id" element={<AnnouncementDetail />} /> |
| <Route path="/dashboard/announcement" element={<div>公告列表</div>} /> |
| </Routes> |
| </MemoryRouter> |
| ); |
| }; |
| |
| it('应该正确加载和显示公告详情', async () => { |
| renderComponent(); |
| |
| await waitFor(() => { |
| expect(screen.getByText('测试公告标题')).toBeInTheDocument(); |
| expect(screen.getByText('这是测试公告内容')).toBeInTheDocument(); |
| expect(screen.getByText('这是第二行内容')).toBeInTheDocument(); |
| }); |
| }); |
| |
| it('应该处理公告加载失败的情况', async () => { |
| announcementApi.getAnnouncementDetail.mockResolvedValue({ |
| data: { code: 404, message: '公告不存在' }, |
| }); |
| |
| renderComponent(); |
| |
| await waitFor(() => { |
| expect(screen.getByText('公告不存在')).toBeInTheDocument(); |
| }); |
| }); |
| |
| it('应该能够返回公告区', async () => { |
| renderComponent(); |
| |
| await waitFor(() => { |
| expect(screen.getByText('测试公告标题')).toBeInTheDocument(); |
| }); |
| |
| fireEvent.click(screen.getByRole('button', { name: /返回/i })); |
| |
| // 检查是否导航回公告区 |
| expect(mockNavigate).toHaveBeenCalledWith('/dashboard/announcement'); |
| }); |
| |
| it('应该显示加载错误时的UI', async () => { |
| announcementApi.getAnnouncementDetail.mockRejectedValue(new Error('网络错误')); |
| |
| renderComponent(); |
| |
| await waitFor(() => { |
| expect(screen.getByText('获取公告详情失败')).toBeInTheDocument(); |
| }); |
| }); |
| |
| // 边界测试 - 测试公告ID不存在 |
| it('应该处理不存在的公告ID', async () => { |
| announcementApi.getAnnouncementDetail.mockResolvedValue({ |
| data: { code: 404, message: '公告不存在' }, |
| }); |
| |
| renderComponent(); |
| |
| await waitFor(() => { |
| expect(screen.getByText('公告不存在')).toBeInTheDocument(); |
| }); |
| }); |
| |
| // 边界测试 - 测试其他API错误 |
| it('应该处理服务器错误', async () => { |
| announcementApi.getAnnouncementDetail.mockResolvedValue({ |
| data: { code: 500, message: '服务器错误' }, |
| }); |
| |
| renderComponent(); |
| |
| await waitFor(() => { |
| expect(screen.getByText('服务器错误')).toBeInTheDocument(); |
| }); |
| }); |
| }); |