import { render, screen, waitFor, fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { vi, test, expect, beforeEach } from 'vitest'; import UploadButton from '../../src/components/UploadButton'; import { uploadDocument } from '../../src/api/client'; vi.mock('../../src/api/client'); beforeEach(() => { vi.mocked(uploadDocument).mockReset(); }); test('opens the upload modal when the button is clicked', async () => { const user = userEvent.setup(); render(); expect(screen.queryByTestId('upload-modal')).not.toBeInTheDocument(); await user.click(screen.getByRole('button', { name: '上传文档' })); expect(screen.getByTestId('upload-modal')).toBeInTheDocument(); }); test('selecting a file through the hidden input uploads it', async () => { vi.mocked(uploadDocument).mockResolvedValue({ key: '产品文档/新文档.md', name: '新文档.md', size: 42 }); const onUploaded = vi.fn(); const user = userEvent.setup(); render(); await user.click(screen.getByRole('button', { name: '上传文档' })); const file = new File(['# 新文档'], '新文档.md', { type: 'text/markdown' }); const input = screen.getByTestId('upload-file-input'); await user.upload(input, file); expect(uploadDocument).toHaveBeenCalledWith(file, '产品文档'); await waitFor(() => { expect(onUploaded).toHaveBeenCalledWith({ key: '产品文档/新文档.md', name: '新文档.md', size: 42 }); }); }); test('a failed upload shows an error message and keeps the modal open for retry', async () => { vi.mocked(uploadDocument).mockRejectedValue(new Error('Failed to upload document: 400')); const onUploaded = vi.fn(); const user = userEvent.setup(); render(); await user.click(screen.getByRole('button', { name: '上传文档' })); const file = new File(['data'], '恶意程序.exe', { type: 'application/octet-stream' }); const input = screen.getByTestId('upload-file-input'); await user.upload(input, file); await waitFor(() => { expect(screen.getByTestId('upload-error')).toHaveTextContent('Failed to upload document: 400'); }); expect(screen.getByTestId('upload-modal')).toBeInTheDocument(); expect(onUploaded).not.toHaveBeenCalled(); }); test('dropping a file onto the dropzone uploads it', async () => { vi.mocked(uploadDocument).mockResolvedValue({ key: '产品文档/拖拽文档.md', name: '拖拽文档.md', size: 10 }); const onUploaded = vi.fn(); const user = userEvent.setup(); render(); await user.click(screen.getByRole('button', { name: '上传文档' })); const file = new File(['内容'], '拖拽文档.md', { type: 'text/markdown' }); const dropzone = screen.getByTestId('dropzone'); fireEvent.drop(dropzone, { dataTransfer: { files: [file] }, }); expect(uploadDocument).toHaveBeenCalledWith(file, '产品文档'); await waitFor(() => { expect(onUploaded).toHaveBeenCalledWith({ key: '产品文档/拖拽文档.md', name: '拖拽文档.md', size: 10 }); }); });