import { describe, it, expect, vi, beforeEach } from 'vitest' import { wrapCollection } from '../fixtures/mockData' // --------------------------------------------------------------------------- // Import under test (AFTER all vi.mock calls) // --------------------------------------------------------------------------- import { useDocuments } from '~/composables/useDocuments' // --------------------------------------------------------------------------- // Mocks — API layer // --------------------------------------------------------------------------- const mockGet = vi.fn() const mockPatch = vi.fn() const mockPostFormData = vi.fn() const mockDel = vi.fn() vi.mock('~/composables/useApi', () => ({ useApi: () => ({ get: mockGet, post: vi.fn(), patch: mockPatch, put: vi.fn(), delete: mockDel, postFormData: mockPostFormData, }), })) // --------------------------------------------------------------------------- // Mocks — Toast // --------------------------------------------------------------------------- const mockShowSuccess = vi.fn() const mockShowError = vi.fn() vi.mock('~/composables/useToast', () => ({ useToast: () => ({ showSuccess: mockShowSuccess, showError: mockShowError, showInfo: vi.fn(), showToast: vi.fn(), toasts: { value: [] }, clearAll: vi.fn(), }), })) // --------------------------------------------------------------------------- // Test data // --------------------------------------------------------------------------- const mockDocument = { id: 'doc-001', name: 'photo.jpg', filename: 'photo.jpg', mimeType: 'image/jpeg', size: 12345, fileUrl: '/files/photo.jpg', downloadUrl: '/files/photo.jpg/download', createdAt: '2025-01-10T08:00:00+00:00', } const mockDocument2 = { id: 'doc-002', name: 'schema.pdf', filename: 'schema.pdf', mimeType: 'application/pdf', size: 54321, fileUrl: '/files/schema.pdf', downloadUrl: '/files/schema.pdf/download', createdAt: '2025-01-11T09:00:00+00:00', } // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- function createMockFile(name: string, type = 'image/jpeg'): File { return new File(['content'], name, { type }) } // --------------------------------------------------------------------------- // beforeEach // --------------------------------------------------------------------------- beforeEach(() => { vi.clearAllMocks() }) // --------------------------------------------------------------------------- // uploadDocuments — FormData is built correctly // --------------------------------------------------------------------------- describe('uploadDocuments', () => { it('builds FormData with file and context fields', async () => { mockPostFormData.mockResolvedValue({ success: true, data: mockDocument }) const { uploadDocuments } = useDocuments() const file = createMockFile('photo.jpg') await uploadDocuments({ files: [file], context: { pieceId: 'piece-001', composantId: 'comp-001' }, }) expect(mockPostFormData).toHaveBeenCalledTimes(1) const [endpoint, formData] = mockPostFormData.mock.calls[0]! expect(endpoint).toBe('/documents') expect(formData).toBeInstanceOf(FormData) expect(formData.get('file')).toBe(file) expect(formData.get('name')).toBe('photo.jpg') expect(formData.get('pieceId')).toBe('piece-001') expect(formData.get('composantId')).toBe('comp-001') }) it('uploads multiple files separately', async () => { mockPostFormData .mockResolvedValueOnce({ success: true, data: mockDocument }) .mockResolvedValueOnce({ success: true, data: mockDocument2 }) const { uploadDocuments } = useDocuments() const file1 = createMockFile('photo.jpg') const file2 = createMockFile('schema.pdf', 'application/pdf') const result = await uploadDocuments({ files: [file1, file2], context: { machineId: 'machine-001' }, }) expect(mockPostFormData).toHaveBeenCalledTimes(2) // First call const [, formData1] = mockPostFormData.mock.calls[0]! expect(formData1.get('name')).toBe('photo.jpg') expect(formData1.get('machineId')).toBe('machine-001') // Second call const [, formData2] = mockPostFormData.mock.calls[1]! expect(formData2.get('name')).toBe('schema.pdf') expect(formData2.get('machineId')).toBe('machine-001') expect(result.success).toBe(true) expect(Array.isArray(result.data) ? result.data : []).toHaveLength(2) }) it('appends type to FormData when provided in context', async () => { mockPostFormData.mockResolvedValue({ success: true, data: mockDocument }) const { uploadDocuments } = useDocuments() const file = createMockFile('facture.pdf', 'application/pdf') await uploadDocuments({ files: [file], context: { siteId: 'site-001', type: 'facture' }, }) const [, formData] = mockPostFormData.mock.calls[0]! expect(formData.get('type')).toBe('facture') expect(formData.get('siteId')).toBe('site-001') }) it('returns error when no files provided', async () => { const { uploadDocuments } = useDocuments() const result = await uploadDocuments({ files: [], context: {} }) expect(result.success).toBe(false) expect(mockPostFormData).not.toHaveBeenCalled() }) }) // --------------------------------------------------------------------------- // loadDocumentsByComponent // --------------------------------------------------------------------------- describe('loadDocumentsByComponent', () => { it('calls correct endpoint /documents/composant/{id}', async () => { mockGet.mockResolvedValue({ success: true, data: wrapCollection([mockDocument]) }) const { loadDocumentsByComponent } = useDocuments() const result = await loadDocumentsByComponent('comp-001') expect(mockGet).toHaveBeenCalledTimes(1) expect(mockGet).toHaveBeenCalledWith('/documents/composant/comp-001') expect(result.success).toBe(true) }) it('returns error for empty componentId', async () => { const { loadDocumentsByComponent } = useDocuments() const result = await loadDocumentsByComponent('') expect(mockGet).not.toHaveBeenCalled() expect(result.success).toBe(false) }) }) // --------------------------------------------------------------------------- // loadDocumentsByPiece // --------------------------------------------------------------------------- describe('loadDocumentsByPiece', () => { it('calls correct endpoint /documents/piece/{id}', async () => { mockGet.mockResolvedValue({ success: true, data: wrapCollection([mockDocument]) }) const { loadDocumentsByPiece } = useDocuments() const result = await loadDocumentsByPiece('piece-001') expect(mockGet).toHaveBeenCalledTimes(1) expect(mockGet).toHaveBeenCalledWith('/documents/piece/piece-001') expect(result.success).toBe(true) }) it('returns error for empty pieceId', async () => { const { loadDocumentsByPiece } = useDocuments() const result = await loadDocumentsByPiece('') expect(mockGet).not.toHaveBeenCalled() expect(result.success).toBe(false) }) }) // --------------------------------------------------------------------------- // loadDocumentsByMachine // --------------------------------------------------------------------------- describe('loadDocumentsByMachine', () => { it('calls correct endpoint /documents/machine/{id}', async () => { mockGet.mockResolvedValue({ success: true, data: wrapCollection([mockDocument]) }) const { loadDocumentsByMachine } = useDocuments() const result = await loadDocumentsByMachine('machine-001') expect(mockGet).toHaveBeenCalledTimes(1) expect(mockGet).toHaveBeenCalledWith('/documents/machine/machine-001') expect(result.success).toBe(true) }) it('returns error for empty machineId', async () => { const { loadDocumentsByMachine } = useDocuments() const result = await loadDocumentsByMachine('') expect(mockGet).not.toHaveBeenCalled() expect(result.success).toBe(false) }) }) // --------------------------------------------------------------------------- // loadDocumentsByProduct // --------------------------------------------------------------------------- describe('loadDocumentsByProduct', () => { it('calls correct endpoint /documents/product/{id}', async () => { mockGet.mockResolvedValue({ success: true, data: wrapCollection([mockDocument]) }) const { loadDocumentsByProduct } = useDocuments() const result = await loadDocumentsByProduct('prod-001') expect(mockGet).toHaveBeenCalledTimes(1) expect(mockGet).toHaveBeenCalledWith('/documents/product/prod-001') expect(result.success).toBe(true) }) it('returns error for empty productId', async () => { const { loadDocumentsByProduct } = useDocuments() const result = await loadDocumentsByProduct('') expect(mockGet).not.toHaveBeenCalled() expect(result.success).toBe(false) }) }) // --------------------------------------------------------------------------- // deleteDocument // --------------------------------------------------------------------------- describe('deleteDocument', () => { it('calls DELETE on correct endpoint', async () => { mockDel.mockResolvedValue({ success: true }) const { deleteDocument } = useDocuments() const result = await deleteDocument('doc-001') expect(mockDel).toHaveBeenCalledTimes(1) expect(mockDel).toHaveBeenCalledWith('/documents/doc-001') expect(result.success).toBe(true) }) it('removes from store when updateStore is true', async () => { mockGet.mockResolvedValue({ success: true, data: wrapCollection([mockDocument, mockDocument2]), }) mockDel.mockResolvedValue({ success: true }) const { loadDocuments, deleteDocument, documents } = useDocuments() // Load documents into store first await loadDocuments({ force: true }) expect(documents.value).toHaveLength(2) // Delete with updateStore: true await deleteDocument('doc-001', { updateStore: true }) expect(documents.value).toHaveLength(1) expect(documents.value[0]!.id).toBe('doc-002') }) it('shows success toast on successful delete', async () => { mockDel.mockResolvedValue({ success: true }) const { deleteDocument } = useDocuments() await deleteDocument('doc-001') expect(mockShowSuccess).toHaveBeenCalledWith('Document supprimé') }) })