import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { TrackDownloadButton } from './TrackDownloadButton'; import { downloadTrack, TrackDownloadError, } from '../services/trackDownloadService'; import { useToast } from '@/hooks/useToast'; // Mock dependencies vi.mock('../services/trackDownloadService'); vi.mock('@/hooks/useToast'); describe('TrackDownloadButton', () => { const mockToast = { success: vi.fn(), error: vi.fn(), warning: vi.fn(), info: vi.fn(), toast: vi.fn(), }; beforeEach(() => { vi.clearAllMocks(); vi.mocked(useToast).mockReturnValue(mockToast); }); it('should render download button', () => { render(); expect(screen.getByText('Télécharger')).toBeInTheDocument(); expect(screen.getByRole('button')).toBeInTheDocument(); }); it('should download track when button is clicked', async () => { vi.mocked(downloadTrack).mockResolvedValue(undefined); render(); const button = screen.getByRole('button'); await userEvent.click(button); await waitFor(() => { expect(downloadTrack).toHaveBeenCalledWith(123, { shareToken: undefined, filename: undefined, onProgress: undefined, }); }); expect(mockToast.success).toHaveBeenCalledWith('Téléchargement terminé'); }); it('should download track with share token', async () => { vi.mocked(downloadTrack).mockResolvedValue(undefined); render(); const button = screen.getByRole('button'); await userEvent.click(button); await waitFor(() => { expect(downloadTrack).toHaveBeenCalledWith(123, { shareToken: 'test-token', filename: undefined, onProgress: undefined, }); }); }); it('should show loading state during download', async () => { let resolveDownload: () => void; const downloadPromise = new Promise((resolve) => { resolveDownload = resolve; }); vi.mocked(downloadTrack).mockReturnValue(downloadPromise); render(); const button = screen.getByRole('button'); await userEvent.click(button); await waitFor(() => { expect(screen.getByText(/Téléchargement.../i)).toBeInTheDocument(); }); expect(button).toBeDisabled(); // Résoudre le téléchargement resolveDownload!(); await waitFor(() => { expect(screen.getByText('Télécharger')).toBeInTheDocument(); }); }); it('should show progress bar when showProgress is true', async () => { let progressCallback: (progress: number) => void; const downloadPromise = new Promise((resolve) => { vi.mocked(downloadTrack).mockImplementation((id, options) => { if (options?.onProgress) { progressCallback = options.onProgress; } setTimeout(() => resolve(), 100); return Promise.resolve(); }); }); render(); const button = screen.getByRole('button'); await userEvent.click(button); await waitFor(() => { expect(screen.getByRole('progressbar')).toBeInTheDocument(); }); // Simuler la progression if (progressCallback!) { progressCallback(50); await waitFor(() => { expect(screen.getByText(/50%/i)).toBeInTheDocument(); }); } }); it('should display error message on download failure', async () => { const error = new TrackDownloadError('Download failed', 'NETWORK', true); vi.mocked(downloadTrack).mockRejectedValue(error); render(); const button = screen.getByRole('button'); await userEvent.click(button); await waitFor(() => { expect(screen.getByText('Download failed')).toBeInTheDocument(); }); expect(mockToast.error).toHaveBeenCalledWith('Download failed'); }); it('should call onDownloadStart callback', async () => { const onDownloadStart = vi.fn(); vi.mocked(downloadTrack).mockResolvedValue(undefined); render( , ); const button = screen.getByRole('button'); await userEvent.click(button); await waitFor(() => { expect(onDownloadStart).toHaveBeenCalled(); }); }); it('should call onDownloadComplete callback', async () => { const onDownloadComplete = vi.fn(); vi.mocked(downloadTrack).mockResolvedValue(undefined); render( , ); const button = screen.getByRole('button'); await userEvent.click(button); await waitFor(() => { expect(onDownloadComplete).toHaveBeenCalled(); }); }); it('should call onDownloadError callback on failure', async () => { const onDownloadError = vi.fn(); const error = new TrackDownloadError('Download failed', 'NETWORK', true); vi.mocked(downloadTrack).mockRejectedValue(error); render( , ); const button = screen.getByRole('button'); await userEvent.click(button); await waitFor(() => { expect(onDownloadError).toHaveBeenCalledWith('Download failed'); }); }); it('should use custom filename if provided', async () => { vi.mocked(downloadTrack).mockResolvedValue(undefined); render(); const button = screen.getByRole('button'); await userEvent.click(button); await waitFor(() => { expect(downloadTrack).toHaveBeenCalledWith(123, { shareToken: undefined, filename: 'custom-track.mp3', onProgress: undefined, }); }); }); it('should apply custom variant and size', () => { render(); const button = screen.getByRole('button'); expect(button).toBeInTheDocument(); }); });