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();
});
});
});