import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, waitFor, fireEvent } from '@testing-library/react'; import { TrackVersionHistory } from './TrackVersionHistory'; import { listVersions, createVersion, restoreVersion, TrackVersionError, } from '../services/trackVersionService'; import { useToast } from '@/hooks/useToast'; // Mock services vi.mock('../services/trackVersionService'); vi.mock('@/hooks/useToast'); describe('TrackVersionHistory', () => { const mockToast = { success: vi.fn(), error: vi.fn(), }; beforeEach(() => { vi.clearAllMocks(); vi.mocked(useToast).mockReturnValue(mockToast); }); const mockVersions = [ { id: 1, track_id: 123, version_number: 1, file_path: '/path/to/v1.mp3', file_size: 1024, changelog: 'Initial version', created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', }, { id: 2, track_id: 123, version_number: 2, file_path: '/path/to/v2.mp3', file_size: 2048, changelog: 'Updated version', created_at: '2024-01-02T00:00:00Z', updated_at: '2024-01-02T00:00:00Z', }, ]; it('should render loading state initially', async () => { vi.mocked(listVersions).mockImplementation( () => new Promise((resolve) => setTimeout(() => resolve(mockVersions), 100)), ); render( , ); expect(screen.getByRole('status')).toBeInTheDocument(); await waitFor(() => { expect(listVersions).toHaveBeenCalledWith(123); }); }); it('should display versions list', async () => { vi.mocked(listVersions).mockResolvedValue(mockVersions); render( , ); await waitFor(() => { expect(screen.getByText('Historique des versions')).toBeInTheDocument(); }); expect(screen.getByText('Version 1')).toBeInTheDocument(); expect(screen.getByText('Version 2')).toBeInTheDocument(); expect(screen.getByText('Initial version')).toBeInTheDocument(); expect(screen.getByText('Updated version')).toBeInTheDocument(); }); it('should display empty state when no versions', async () => { vi.mocked(listVersions).mockResolvedValue([]); render( , ); await waitFor(() => { expect( screen.getByText('Aucune version enregistrée'), ).toBeInTheDocument(); }); }); it('should display error message on load error', async () => { const error = new TrackVersionError('Failed to load', 'SERVER', true); vi.mocked(listVersions).mockRejectedValue(error); render( , ); await waitFor(() => { expect(screen.getByText('Failed to load')).toBeInTheDocument(); }); }); it('should open create version dialog', async () => { vi.mocked(listVersions).mockResolvedValue(mockVersions); render( , ); await waitFor(() => { expect(screen.getByText('Créer une version')).toBeInTheDocument(); }); const createButton = screen.getByText('Créer une version'); fireEvent.click(createButton); await waitFor(() => { expect( screen.getByText('Créer une nouvelle version'), ).toBeInTheDocument(); }); }); it('should create version successfully', async () => { vi.mocked(listVersions).mockResolvedValue(mockVersions); vi.mocked(createVersion).mockResolvedValue({ id: 3, track_id: 123, version_number: 3, file_path: '/path/to/v3.mp3', file_size: 3072, changelog: 'New version', created_at: '2024-01-03T00:00:00Z', updated_at: '2024-01-03T00:00:00Z', }); // Mock window.confirm window.confirm = vi.fn(() => true); render( , ); await waitFor(() => { expect(screen.getByText('Créer une version')).toBeInTheDocument(); }); const createButton = screen.getByText('Créer une version'); fireEvent.click(createButton); await waitFor(() => { expect( screen.getByText('Créer une nouvelle version'), ).toBeInTheDocument(); }); const changelogInput = screen.getByPlaceholderText( "Ex: Correction du mixage, ajout d'effets...", ); fireEvent.change(changelogInput, { target: { value: 'New version' } }); const submitButton = screen.getByText('Créer la version'); fireEvent.click(submitButton); await waitFor(() => { expect(createVersion).toHaveBeenCalledWith(123, { file_path: '/path/to/track.mp3', file_size: 1024, changelog: 'New version', }); }); await waitFor(() => { expect(mockToast.success).toHaveBeenCalledWith( 'Version créée avec succès', ); }); }); it('should handle create version error', async () => { vi.mocked(listVersions).mockResolvedValue(mockVersions); const error = new TrackVersionError('Failed to create', 'SERVER', true); vi.mocked(createVersion).mockRejectedValue(error); render( , ); await waitFor(() => { expect(screen.getByText('Créer une version')).toBeInTheDocument(); }); const createButton = screen.getByText('Créer une version'); fireEvent.click(createButton); await waitFor(() => { expect( screen.getByText('Créer une nouvelle version'), ).toBeInTheDocument(); }); const submitButton = screen.getByText('Créer la version'); fireEvent.click(submitButton); await waitFor(() => { expect(mockToast.error).toHaveBeenCalledWith('Failed to create'); }); }); it('should restore version successfully', async () => { vi.mocked(listVersions).mockResolvedValue(mockVersions); vi.mocked(restoreVersion).mockResolvedValue(); // Mock window.confirm window.confirm = vi.fn(() => true); render( , ); await waitFor(() => { expect(screen.getByText('Version 1')).toBeInTheDocument(); }); const restoreButtons = screen.getAllByText('Restaurer'); fireEvent.click(restoreButtons[0]); // Click first restore button await waitFor(() => { expect(restoreVersion).toHaveBeenCalledWith(123, 1); }); await waitFor(() => { expect(mockToast.success).toHaveBeenCalledWith( 'Version restaurée avec succès', ); }); }); it('should not restore version if user cancels', async () => { vi.mocked(listVersions).mockResolvedValue(mockVersions); // Mock window.confirm to return false window.confirm = vi.fn(() => false); render( , ); await waitFor(() => { expect(screen.getByText('Version 1')).toBeInTheDocument(); }); const restoreButtons = screen.getAllByText('Restaurer'); fireEvent.click(restoreButtons[0]); await waitFor(() => { expect(window.confirm).toHaveBeenCalled(); }); expect(restoreVersion).not.toHaveBeenCalled(); }); it('should handle restore version error', async () => { vi.mocked(listVersions).mockResolvedValue(mockVersions); const error = new TrackVersionError('Failed to restore', 'SERVER', true); vi.mocked(restoreVersion).mockRejectedValue(error); // Mock window.confirm window.confirm = vi.fn(() => true); render( , ); await waitFor(() => { expect(screen.getByText('Version 1')).toBeInTheDocument(); }); const restoreButtons = screen.getAllByText('Restaurer'); fireEvent.click(restoreButtons[0]); await waitFor(() => { expect(mockToast.error).toHaveBeenCalledWith('Failed to restore'); }); }); it('should not show create button when track info is missing', async () => { vi.mocked(listVersions).mockResolvedValue(mockVersions); render(); await waitFor(() => { expect(screen.getByText('Historique des versions')).toBeInTheDocument(); }); expect(screen.queryByText('Créer une version')).not.toBeInTheDocument(); }); it('should format file sizes correctly', async () => { const versionsWithLargeSize = [ { ...mockVersions[0], file_size: 1024 * 1024 * 1024, // 1 GB }, ]; vi.mocked(listVersions).mockResolvedValue(versionsWithLargeSize); render( , ); await waitFor(() => { expect(screen.getByText(/GB/)).toBeInTheDocument(); }); }); });