import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { useFileManagement } from '../../src/hooks/useFileManagement'; // Mock API客户端 vi.mock('../../src/api/fileClient', () => ({ fileClient: { $get: vi.fn(), ':id': { $put: vi.fn(), $delete: vi.fn(), }, }, })); // Mock toast vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), warning: vi.fn(), }, })); describe('useFileManagement', () => { let queryClient: QueryClient; beforeEach(() => { queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false }, }, }); vi.clearAllMocks(); }); const wrapper = ({ children }: { children: React.ReactNode }) => ( {children} ); const mockFiles = [ { id: 1, name: 'test-file-1.jpg', type: 'image/jpeg', size: 1024, fullUrl: 'http://example.com/test-file-1.jpg', uploadTime: '2024-01-01T00:00:00Z', }, { id: 2, name: 'test-file-2.pdf', type: 'application/pdf', size: 2048, fullUrl: 'http://example.com/test-file-2.pdf', uploadTime: '2024-01-01T00:00:00Z', }, ]; it('应该初始化文件管理钩子', () => { const { result } = renderHook(() => useFileManagement(), { wrapper }); expect(result.current.files).toEqual([]); expect(result.current.isLoading).toBe(true); expect(result.current.searchText).toBe(''); }); it('应该获取文件列表', async () => { const { fileClient } = require('../../src/api/fileClient'); fileClient.$get.mockResolvedValue({ ok: true, json: async () => ({ data: mockFiles, pagination: { current: 1, pageSize: 10, total: 2 } }) }); const { result } = renderHook(() => useFileManagement(), { wrapper }); await waitFor(() => { expect(result.current.isLoading).toBe(false); }); expect(result.current.files).toEqual(mockFiles); expect(result.current.pagination.total).toBe(2); }); it('应该处理搜索', async () => { const { fileClient } = require('../../src/api/fileClient'); fileClient.$get.mockResolvedValue({ ok: true, json: async () => ({ data: [mockFiles[0]], pagination: { current: 1, pageSize: 10, total: 1 } }) }); const { result } = renderHook(() => useFileManagement(), { wrapper }); result.current.handleSearch('test'); await waitFor(() => { expect(result.current.searchText).toBe('test'); }); expect(fileClient.$get).toHaveBeenCalledWith({ query: { page: 1, pageSize: 10, keyword: 'test' } }); }); it('应该处理分页', async () => { const { fileClient } = require('../../src/api/fileClient'); fileClient.$get.mockResolvedValue({ ok: true, json: async () => ({ data: mockFiles, pagination: { current: 2, pageSize: 5, total: 2 } }) }); const { result } = renderHook(() => useFileManagement(), { wrapper }); result.current.handlePageChange(2, 5); await waitFor(() => { expect(result.current.pagination.current).toBe(2); expect(result.current.pagination.pageSize).toBe(5); }); }); it('应该更新文件信息', async () => { const { fileClient } = require('../../src/api/fileClient'); const { toast } = require('sonner'); fileClient[':id'].$put.mockResolvedValue({ ok: true, json: async () => ({ id: 1, name: 'updated-file.jpg', description: 'Updated description' }) }); const { result } = renderHook(() => useFileManagement(), { wrapper }); await result.current.updateFile({ id: 1, data: { name: 'updated-file.jpg', description: 'Updated description' } }); expect(fileClient[':id'].$put).toHaveBeenCalledWith({ param: { id: 1 }, json: { name: 'updated-file.jpg', description: 'Updated description' } }); expect(toast.success).toHaveBeenCalledWith('文件信息更新成功'); }); it('应该删除文件', async () => { const { fileClient } = require('../../src/api/fileClient'); const { toast } = require('sonner'); fileClient[':id'].$delete.mockResolvedValue({ ok: true }); const { result } = renderHook(() => useFileManagement(), { wrapper }); await result.current.deleteFile(1); expect(fileClient[':id'].$delete).toHaveBeenCalledWith({ param: { id: 1 } }); expect(toast.success).toHaveBeenCalledWith('文件删除成功'); }); it('应该检查文件是否可预览', () => { const { result } = renderHook(() => useFileManagement(), { wrapper }); expect(result.current.isPreviewable('image/jpeg')).toBe(true); expect(result.current.isPreviewable('video/mp4')).toBe(true); expect(result.current.isPreviewable('application/pdf')).toBe(false); expect(result.current.isPreviewable(null)).toBe(false); }); it('应该处理文件预览', () => { const { result } = renderHook(() => useFileManagement(), { wrapper }); const windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => null); const file = { id: 1, name: 'test.jpg', type: 'image/jpeg', fullUrl: 'http://example.com/test.jpg' } as any; result.current.handlePreview(file); expect(windowOpenSpy).toHaveBeenCalledWith('http://example.com/test.jpg', '_blank'); windowOpenSpy.mockRestore(); }); it('应该处理文件下载', () => { const { result } = renderHook(() => useFileManagement(), { wrapper }); const createElementSpy = vi.spyOn(document, 'createElement'); const appendChildSpy = vi.spyOn(document.body, 'appendChild'); const removeChildSpy = vi.spyOn(document.body, 'removeChild'); const file = { id: 1, name: 'test.jpg', fullUrl: 'http://example.com/test.jpg' } as any; result.current.handleDownload(file); expect(createElementSpy).toHaveBeenCalledWith('a'); expect(appendChildSpy).toHaveBeenCalled(); expect(removeChildSpy).toHaveBeenCalled(); createElementSpy.mockRestore(); appendChildSpy.mockRestore(); removeChildSpy.mockRestore(); }); });