blob: 4dc50369b96ff176770e5b29615f5960979921f0 [file] [log] [blame]
import { render, screen } from '@testing-library/react';
import WorkPage from '../../feature/work/WorkPage';
import { Provider } from 'react-redux';
import { store } from '../../store/store';
import { MemoryRouter, Route, Routes, useNavigate } from 'react-router';
import { act } from 'react-dom/test-utils';
import WorkAPI from '../../api/workApi';
import type { Work } from '../../api/otherType';
import '@testing-library/jest-dom';
// 模拟整个WorkAPI类
jest.mock('../../api/workApi', () => {
return {
__esModule: true,
default: {
getWorkById: jest.fn(),
likeWork: jest.fn(),
// 添加其他可能用到的方法
getBugReports: jest.fn(),
getDiscussions: jest.fn()
}
}
});
// 模拟子组件
jest.mock('../../components/BugReportSection', () => () => (
<div data-testid="bug-report-mock">BugReportSection Mock</div>
));
jest.mock('../../components/DiscussionSection', () => () => (
<div data-testid="discussion-mock">DiscussionSection Mock</div>
));
// 模拟react-router-dom的useNavigate
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => jest.fn()
}));
describe('WorkPage Component', () => {
const mockWork: Work = {
id: 1,
title: '测试作品',
author: '测试作者',
categoryName: '测试分类',
views: 100,
likes: 50,
createTime: '2023-01-01T00:00:00Z',
description: '测试描述',
content: '测试内容',
size: '',
data: function (): unknown {
throw new Error('Function not implemented.');
},
artist: '',
quality: '',
genre: [],
authorId: 0,
categoryId: 0,
coverUrl: '',
attachments: [],
bugCount: 0,
discussionCount: 0
};
beforeEach(() => {
// 重置所有模拟
jest.clearAllMocks();
// 设置默认模拟实现
(WorkAPI.getWorkById as jest.Mock).mockResolvedValue(mockWork);
(WorkAPI.likeWork as jest.Mock).mockResolvedValue({});
});
it('renders loading spinner initially', async () => {
// 延迟API响应以测试加载状态
let resolvePromise: (value: Work) => void;
(WorkAPI.getWorkById as jest.Mock).mockImplementation(
() => new Promise<Work>((resolve) => {
resolvePromise = resolve;
})
);
render(
<MemoryRouter initialEntries={['/works/1']}>
<Provider store={store}>
<Routes>
<Route path="/works/:id" element={<WorkPage />} />
</Routes>
</Provider>
</MemoryRouter>
);
// 验证加载状态
expect(screen.getByRole('status')).toBeInTheDocument();
expect(screen.getByText(/加载/)).toBeInTheDocument();
// 完成API请求
await act(async () => {
resolvePromise(mockWork);
});
// 验证加载完成后内容
expect(await screen.findByText('测试作品')).toBeInTheDocument();
});
it('renders work details after loading', async () => {
render(
<MemoryRouter initialEntries={['/works/1']}>
<Provider store={store}>
<Routes>
<Route path="/works/:id" element={<WorkPage />} />
</Routes>
</Provider>
</MemoryRouter>
);
// 等待数据加载完成
expect(await screen.findByText('测试作品')).toBeInTheDocument();
// 验证头部信息
expect(screen.getByText('作者: 测试作者')).toBeInTheDocument();
expect(screen.getByText('测试分类')).toHaveClass('ant-tag');
expect(screen.getByText('浏览: 100')).toBeInTheDocument();
expect(screen.getByText('点赞: 50')).toBeInTheDocument();
expect(screen.getByText(/2023/)).toBeInTheDocument();
// 验证作品内容
expect(screen.getByRole('heading', { level: 4, name: '作品描述' })).toBeInTheDocument();
expect(screen.getByText('测试描述')).toBeInTheDocument();
expect(screen.getByRole('heading', { level: 4, name: '作品内容' })).toBeInTheDocument();
expect(screen.getByText('测试内容')).toBeInTheDocument();
// 验证标签页
expect(screen.getByRole('tab', { name: '作品详情' })).toBeInTheDocument();
expect(screen.getByRole('tab', { name: /Bug反馈/ })).toBeInTheDocument();
expect(screen.getByRole('tab', { name: /交流区/ })).toBeInTheDocument();
});
it('handles back button click', async () => {
const mockNavigate = jest.fn();
(useNavigate as jest.Mock).mockReturnValue(mockNavigate);
render(
<MemoryRouter initialEntries={['/works/1']}>
<Provider store={store}>
<Routes>
<Route path="/works/:id" element={<WorkPage />} />
</Routes>
</Provider>
</MemoryRouter>
);
// 等待数据加载完成
await screen.findByText('测试作品');
// 点击返回按钮
const backButton = screen.getByRole('button', { name: '返回' });
await act(async () => {
backButton.click();
});
// 验证导航被调用
expect(mockNavigate).toHaveBeenCalledWith(-1);
});
it('handles like button click', async () => {
render(
<MemoryRouter initialEntries={['/works/1']}>
<Provider store={store}>
<Routes>
<Route path="/works/:id" element={<WorkPage />} />
</Routes>
</Provider>
</MemoryRouter>
);
// 等待数据加载完成
await screen.findByText('测试作品');
// 点击点赞按钮
const likeButton = screen.getByRole('button', { name: '点赞' });
await act(async () => {
likeButton.click();
});
// 验证API调用
expect(WorkAPI.likeWork).toHaveBeenCalledTimes(1);
expect(WorkAPI.likeWork).toHaveBeenCalledWith(1);
// 验证UI反馈
expect(await screen.findByText('点赞成功')).toBeInTheDocument();
});
it('shows error message when work loading fails', async () => {
const errorMessage = '加载失败';
(WorkAPI.getWorkById as jest.Mock).mockRejectedValue(new Error(errorMessage));
const mockNavigate = jest.fn();
(useNavigate as jest.Mock).mockReturnValue(mockNavigate);
render(
<MemoryRouter initialEntries={['/works/1']}>
<Provider store={store}>
<Routes>
<Route path="/works/:id" element={<WorkPage />} />
</Routes>
</Provider>
</MemoryRouter>
);
// 验证错误消息
expect(await screen.findByText('作品不存在')).toBeInTheDocument();
// 验证导航到首页
expect(mockNavigate).toHaveBeenCalledWith('/');
});
it('switches between tabs correctly', async () => {
render(
<MemoryRouter initialEntries={['/works/1']}>
<Provider store={store}>
<Routes>
<Route path="/works/:id" element={<WorkPage />} />
</Routes>
</Provider>
</MemoryRouter>
);
// 等待数据加载完成
await screen.findByText('测试作品');
// 初始显示作品详情
expect(screen.getByText('测试描述')).toBeInTheDocument();
expect(screen.queryByTestId('bug-report-mock')).not.toBeInTheDocument();
expect(screen.queryByTestId('discussion-mock')).not.toBeInTheDocument();
// 点击Bug反馈标签
const bugTab = screen.getByRole('tab', { name: /Bug反馈/ });
await act(async () => {
bugTab.click();
});
// 验证Bug反馈内容显示
expect(screen.queryByText('测试描述')).not.toBeInTheDocument();
expect(screen.getByTestId('bug-report-mock')).toBeInTheDocument();
// 点击交流区标签
const discussionTab = screen.getByRole('tab', { name: /交流区/ });
await act(async () => {
discussionTab.click();
});
// 验证交流区内容显示
expect(screen.queryByTestId('bug-report-mock')).not.toBeInTheDocument();
expect(screen.getByTestId('discussion-mock')).toBeInTheDocument();
// 切换回作品详情
const detailsTab = screen.getByRole('tab', { name: '作品详情' });
await act(async () => {
detailsTab.click();
});
// 验证作品详情再次显示
expect(screen.getByText('测试描述')).toBeInTheDocument();
expect(screen.queryByTestId('discussion-mock')).not.toBeInTheDocument();
});
});