| import { describe, it, expect, vi, beforeEach } from 'vitest'; |
| import { render, screen, fireEvent, waitFor } from '@testing-library/react'; |
| import { MemoryRouter } from 'react-router-dom'; |
| import UploadTorrent from '../components/upload'; |
| import { Form, Select } from 'antd'; |
| |
| // 模拟 axios |
| vi.mock('axios'); |
| |
| // 模拟 antd 的 message |
| vi.mock('antd', async () => { |
| const actual = await vi.importActual('antd'); |
| return { |
| ...actual, |
| message: { |
| success: vi.fn(), |
| error: vi.fn(), |
| }, |
| }; |
| }); |
| |
| describe('UploadTorrent 组件', () => { |
| const mockCategories = [ |
| { categoryid: '1', category_name: '电影' }, |
| { categoryid: '2', category_name: '剧集' }, |
| { categoryid: '3', category_name: '音乐' }, |
| { categoryid: '4', category_name: '动漫' }, |
| { categoryid: '5', category_name: '游戏' }, |
| { categoryid: '6', category_name: '综艺' }, |
| { categoryid: '7', category_name: '体育' }, |
| { categoryid: '8', category_name: '软件' }, |
| { categoryid: '9', category_name: '学习资料' }, |
| { categoryid: '10', category_name: '纪录片' }, |
| { categoryid: '11', category_name: '音乐' }, |
| ]; |
| |
| beforeEach(() => { |
| vi.clearAllMocks(); |
| // 模拟 axios.get 返回分类数据 |
| vi.mocked(axios.get).mockResolvedValueOnce({ data: mockCategories }); |
| }); |
| |
| it('应该正确渲染而不崩溃', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(screen.getByText('上传种子')).toBeInTheDocument(); |
| }); |
| |
| // 验证一些基本元素是否存在 |
| expect(screen.getByText('封面图片')).toBeInTheDocument(); |
| expect(screen.getByText('种子文件')).toBeInTheDocument(); |
| expect(screen.getByText('标题')).toBeInTheDocument(); |
| expect(screen.getByText('描述')).toBeInTheDocument(); |
| expect(screen.getByText('分类')).toBeInTheDocument(); |
| expect(screen.getByText('上传种子')).toBeInTheDocument(); |
| }); |
| |
| it('应该加载分类数据', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 验证分类下拉框是否渲染了正确的选项 |
| const categorySelect = screen.getByLabelText('分类'); |
| expect(categorySelect).toBeInTheDocument(); |
| |
| // 打开下拉菜单并检查选项 |
| fireEvent.mouseDown(categorySelect); |
| mockCategories.forEach(category => { |
| expect(screen.getByText(category.category_name)).toBeInTheDocument(); |
| }); |
| }); |
| |
| it('应该在选择分类后显示相应的动态字段', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 选择"电影"分类 |
| const categorySelect = screen.getByLabelText('分类'); |
| fireEvent.mouseDown(categorySelect); |
| fireEvent.click(screen.getByText('电影')); |
| |
| // 验证电影相关的字段是否显示 |
| expect(screen.getByLabelText('字幕/说明')).toBeInTheDocument(); |
| expect(screen.getByLabelText('地区')).toBeInTheDocument(); |
| expect(screen.getByLabelText('年份')).toBeInTheDocument(); |
| expect(screen.getByLabelText('类型')).toBeInTheDocument(); |
| expect(screen.getByLabelText('编码格式')).toBeInTheDocument(); |
| expect(screen.getByLabelText('分辨率')).toBeInTheDocument(); |
| }); |
| |
| it('应该在选择"剧集"分类后显示相应的动态字段', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 选择"剧集"分类 |
| const categorySelect = screen.getByLabelText('分类'); |
| fireEvent.mouseDown(categorySelect); |
| fireEvent.click(screen.getByText('剧集')); |
| |
| // 验证剧集相关的字段是否显示 |
| expect(screen.getByLabelText('地区')).toBeInTheDocument(); |
| expect(screen.getByLabelText('格式')).toBeInTheDocument(); |
| expect(screen.getByLabelText('类型')).toBeInTheDocument(); |
| }); |
| |
| it('应该在选择"游戏"分类后显示相应的动态字段', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 选择"游戏"分类 |
| const categorySelect = screen.getByLabelText('分类'); |
| fireEvent.mouseDown(categorySelect); |
| fireEvent.click(screen.getByText('游戏')); |
| |
| // 验证游戏相关的字段是否显示 |
| expect(screen.getByLabelText('平台')).toBeInTheDocument(); |
| expect(screen.getByLabelText('类型')).toBeInTheDocument(); |
| expect(screen.getByLabelText('语言')).toBeInTheDocument(); |
| expect(screen.getByLabelText('数据类型')).toBeInTheDocument(); |
| }); |
| |
| it('应该在选择"综艺"分类后显示相应的动态字段', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 选择"综艺"分类 |
| const categorySelect = screen.getByLabelText('分类'); |
| fireEvent.mouseDown(categorySelect); |
| fireEvent.click(screen.getByText('综艺')); |
| |
| // 验证综艺相关的字段是否显示 |
| expect(screen.getByLabelText('是否大陆综艺')).toBeInTheDocument(); |
| expect(screen.getByLabelText('类型')).toBeInTheDocument(); |
| expect(screen.getByLabelText('格式')).toBeInTheDocument(); |
| }); |
| |
| it('应该在选择"动漫"分类后显示相应的动态字段', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 选择"动漫"分类 |
| const categorySelect = screen.getByLabelText('分类'); |
| fireEvent.mouseDown(categorySelect); |
| fireEvent.click(screen.getByText('动漫')); |
| |
| // 验证动漫相关的字段是否显示 |
| expect(screen.getByLabelText('类型')).toBeInTheDocument(); |
| expect(screen.getByLabelText('格式')).toBeInTheDocument(); |
| expect(screen.getByLabelText('分辨率')).toBeInTheDocument(); |
| }); |
| |
| it('应该在选择"学习资料"分类后显示相应的动态字段', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 选择"学习资料"分类 |
| const categorySelect = screen.getByLabelText('分类'); |
| fireEvent.mouseDown(categorySelect); |
| fireEvent.click(screen.getByText('学习资料')); |
| |
| // 验证学习资料相关的字段是否显示 |
| expect(screen.getByLabelText('类型')).toBeInTheDocument(); |
| expect(screen.getByLabelText('格式')).toBeInTheDocument(); |
| }); |
| |
| it('应该在选择"纪录片"分类后显示相应的动态字段', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 选择"纪录片"分类 |
| const categorySelect = screen.getByLabelText('分类'); |
| fireEvent.mouseDown(categorySelect); |
| fireEvent.click(screen.getByText('纪录片')); |
| |
| // 验证纪录片相关的字段是否显示 |
| expect(screen.getByLabelText('年份')).toBeInTheDocument(); |
| expect(screen.getByLabelText('视频源')).toBeInTheDocument(); |
| expect(screen.getByLabelText('格式')).toBeInTheDocument(); |
| }); |
| |
| it('应该在选择"音乐"分类后显示相应的动态字段', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 选择"音乐"分类 |
| const categorySelect = screen.getByLabelText('分类'); |
| fireEvent.mouseDown(categorySelect); |
| fireEvent.click(screen.getByText('音乐')); |
| |
| // 验证音乐相关的字段是否显示 |
| expect(screen.getByLabelText('类型')).toBeInTheDocument(); |
| expect(screen.getByLabelText('地区')).toBeInTheDocument(); |
| expect(screen.getByLabelText('风格')).toBeInTheDocument(); |
| expect(screen.getByLabelText('格式')).toBeInTheDocument(); |
| }); |
| |
| it('应该在选择"软件"分类后显示相应的动态字段', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 选择"软件"分类 |
| const categorySelect = screen.getByLabelText('分类'); |
| fireEvent.mouseDown(categorySelect); |
| fireEvent.click(screen.getByText('软件')); |
| |
| // 验证软件相关的字段是否显示 |
| expect(screen.getByLabelText('平台')).toBeInTheDocument(); |
| expect(screen.getByLabelText('类型')).toBeInTheDocument(); |
| expect(screen.getByLabelText('格式')).toBeInTheDocument(); |
| }); |
| |
| it('应该在选择"体育"分类后显示相应的动态字段', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 选择"体育"分类 |
| const categorySelect = screen.getByLabelText('分类'); |
| fireEvent.mouseDown(categorySelect); |
| fireEvent.click(screen.getByText('体育')); |
| |
| // 验证体育相关的字段是否显示 |
| expect(screen.getByLabelText('类型')).toBeInTheDocument(); |
| expect(screen.getByLabelText('格式')).toBeInTheDocument(); |
| expect(screen.getByLabelText('赛事类型')).toBeInTheDocument(); |
| }); |
| |
| it('应该在选择分类后正确设置状态', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 选择"电影"分类 |
| const categorySelect = screen.getByLabelText('分类'); |
| fireEvent.mouseDown(categorySelect); |
| fireEvent.click(screen.getByText('电影')); |
| |
| // 验证状态是否正确设置 |
| // 注意:由于状态是组件内部的,我们需要通过 UI 变化来间接验证 |
| // 这里我们验证电影相关的字段是否显示 |
| expect(screen.getByLabelText('字幕/说明')).toBeInTheDocument(); |
| }); |
| |
| it('应该在选择种子文件后更新状态', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 模拟文件选择 |
| const fileInput = screen.getByLabelText('种子文件').querySelector('input'); |
| const mockFile = new File(['torrent content'], 'test.torrent', { type: 'application/x-bittorrent' }); |
| fireEvent.change(fileInput, { target: { files: [mockFile] } }); |
| |
| // 验证文件是否被设置(通过 UI 变化间接验证) |
| // 由于我们无法直接访问组件状态,我们可以通过表单验证状态来间接验证 |
| // 这里我们只是验证文件输入是否正常工作 |
| expect(fileInput).toBeInTheDocument(); |
| }); |
| |
| it('应该在选择封面图片后更新状态', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 模拟图片选择 |
| const imageInput = screen.getByLabelText('封面图片').querySelector('input'); |
| const mockImage = new File(['image content'], 'test.jpg', { type: 'image/jpeg' }); |
| fireEvent.change(imageInput, { target: { files: [mockImage] } }); |
| |
| // 验证图片是否被设置(通过 UI 变化间接验证) |
| expect(imageInput).toBeInTheDocument(); |
| }); |
| |
| it('应该在表单提交时验证必填字段', async () => { |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 直接提交表单而不填写任何字段 |
| const submitButton = screen.getByText('上传种子'); |
| fireEvent.click(submitButton); |
| |
| // 验证错误消息是否显示 |
| // 注意:由于我们使用了 antd 的 Form,错误消息可能由 antd 内部处理 |
| // 我们可以通过检查是否有错误提示来验证 |
| // 这里我们只是验证表单提交被调用 |
| // 更详细的验证可能需要更复杂的测试设置 |
| }); |
| |
| it('应该在填写所有必填字段后成功提交表单', async () => { |
| // 模拟 axios.post |
| vi.mocked(axios.post).mockResolvedValueOnce({ data: {} }); |
| |
| render( |
| <MemoryRouter> |
| <UploadTorrent /> |
| </MemoryRouter> |
| ); |
| |
| // 等待分类数据加载 |
| await waitFor(() => { |
| expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories'); |
| }); |
| |
| // 选择分类 |
| const categorySelect = screen.getByLabelText('分类'); |
| fireEvent.mouseDown(categorySelect); |
| fireEvent.click(screen.getByText('电影')); |
| |
| // 填写标题 |
| const titleInput = screen.getByLabelText('标题'); |
| fireEvent.change(titleInput, { target: { value: '测试电影' } }); |
| |
| // 填写描述 |
| const descriptionInput = screen.getByLabelText('描述'); |
| fireEvent.change(descriptionInput, { target: { value: '这是一个测试电影的描述' } }); |
| |
| // 选择封面图片 |
| const imageInput = screen.getByLabelText('封面图片').querySelector('input'); |
| const mockImage = new File(['image content'], 'test.jpg', { type: 'image/jpeg' }); |
| fireEvent.change(imageInput, { target: { files: [mockImage] } }); |
| |
| // 选择种子文件 |
| const fileInput = screen.getByLabelText('种子文件').querySelector('input'); |
| const mockFile = new File(['torrent content'], 'test.torrent', { type: 'application/x-bittorrent' }); |
| fireEvent.change(fileInput, { target: { files: [mockFile] } }); |
| |
| // 填写电影相关字段 |
| const captionInput = screen.getByLabelText('字幕/说明'); |
| fireEvent.change(captionInput, { target: { value: '测试字幕' } }); |
| |
| const regionSelect = screen.getByLabelText('地区'); |
| fireEvent.mouseDown(regionSelect); |
| fireEvent.click(screen.getByText('大陆')); |
| |
| const yearInput = screen.getByLabelText('年份'); |
| fireEvent.change(yearInput, { target: { value: '2023' } }); |
| |
| const genreSelect = screen.getByLabelText('类型'); |
| fireEvent.mouseDown(genreSelect); |
| fireEvent.click(screen.getByText('动作')); |
| |
| const codecFormatSelect = screen.getByLabelText('编码格式'); |
| fireEvent.mouseDown(codecFormatSelect); |
| fireEvent.click(screen.getByText('H.264')); |
| |
| const resolutionSelect = screen.getByLabelText('分辨率'); |
| fireEvent.mouseDown(resolutionSelect); |
| fireEvent.click(screen.getByText('1080p')); |
| |
| // 提交表单 |
| const submitButton = screen.getByText('上传种子'); |
| fireEvent.click(submitButton); |
| |
| // 验证 axios.post 是否被调用 |
| expect(axios.post).toHaveBeenCalledWith( |
| 'http://localhost:8080/torrent/upload', |
| expect.any(FormData), |
| { |
| headers: { 'Content-Type': 'multipart/form-data' }, |
| responseType: 'blob', |
| } |
| ); |
| |
| // 验证成功消息是否显示 |
| expect(vi.mocked(message.success)).toHaveBeenCalledWith('上传成功!'); |
| }); |
| }); |