import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen } from '@testing-library/react'; import { AudioPlayer } from './AudioPlayer'; import { usePlayer } from '../hooks/usePlayer'; // Mock dependencies vi.mock('../hooks/usePlayer', () => ({ usePlayer: vi.fn(), })); describe('AudioPlayer', () => { const mockPlayer = { currentTrack: null, isPlaying: false, currentTime: 0, duration: 0, volume: 100, muted: false, queue: [], currentIndex: -1, repeat: 'off' as const, shuffle: false, play: vi.fn(), pause: vi.fn(), resume: vi.fn(), stop: vi.fn(), next: vi.fn(), previous: vi.fn(), seek: vi.fn(), setVolume: vi.fn(), toggleMute: vi.fn(), toggleShuffle: vi.fn(), setRepeat: vi.fn(), addToQueue: vi.fn(), clearQueue: vi.fn(), }; beforeEach(() => { vi.clearAllMocks(); vi.mocked(usePlayer).mockReturnValue(mockPlayer); }); it('should render audio player', () => { render(); expect(screen.getByTestId('audio-player')).toBeInTheDocument(); }); it('should render audio element', () => { render(); const audioElement = screen.getByTestId('audio-element'); expect(audioElement).toBeInTheDocument(); expect(audioElement.tagName).toBe('AUDIO'); }); it('should pass audio ref to usePlayer hook', () => { render(); // usePlayer should be called with a ref object expect(usePlayer).toHaveBeenCalled(); const callArgs = vi.mocked(usePlayer).mock.calls[0][0]; expect(callArgs).toBeDefined(); expect(callArgs?.current).toBeInstanceOf(HTMLAudioElement); }); it('should display no track message when no track is selected', () => { render(); expect(screen.getByText('Aucune piste sélectionnée')).toBeInTheDocument(); }); it('should display current track when track is playing', () => { const track = { id: 1, title: 'Test Track', duration: 180, url: 'https://example.com/track.mp3', }; vi.mocked(usePlayer).mockReturnValue({ ...mockPlayer, currentTrack: track, }); render(); expect(screen.getByText('Test Track')).toBeInTheDocument(); }); it('should display artist when available', () => { const track = { id: 1, title: 'Test Track', artist: 'Test Artist', duration: 180, url: 'https://example.com/track.mp3', }; vi.mocked(usePlayer).mockReturnValue({ ...mockPlayer, currentTrack: track, }); render(); expect(screen.getByText('Test Artist')).toBeInTheDocument(); }); it('should apply custom className', () => { const { container } = render(); expect(container.firstChild).toHaveClass('custom-class'); }); it('should set preload attribute on audio element', () => { render(); const audioElement = screen.getByTestId( 'audio-element', ) as HTMLAudioElement; expect(audioElement.preload).toBe('auto'); }); it('should set autoplay attribute on audio element', () => { render(); const audioElement = screen.getByTestId( 'audio-element', ) as HTMLAudioElement; expect(audioElement.autoplay).toBe(true); }); it('should have default preload value', () => { render(); const audioElement = screen.getByTestId( 'audio-element', ) as HTMLAudioElement; expect(audioElement.preload).toBe('metadata'); }); it('should have default autoplay value', () => { render(); const audioElement = screen.getByTestId( 'audio-element', ) as HTMLAudioElement; expect(audioElement.autoplay).toBe(false); }); it('should hide audio element visually', () => { render(); const audioElement = screen.getByTestId('audio-element'); expect(audioElement).toHaveStyle({ display: 'none' }); }); it('should handle queue with multiple tracks', () => { const track1 = { id: 1, title: 'Track 1', duration: 180, url: 'https://example.com/track1.mp3', }; const track2 = { id: 2, title: 'Track 2', duration: 200, url: 'https://example.com/track2.mp3', }; vi.mocked(usePlayer).mockReturnValue({ ...mockPlayer, currentTrack: track1, queue: [track1, track2], currentIndex: 0, }); render(); expect(screen.getByText('Track 1')).toBeInTheDocument(); }); it('should handle compact mode', () => { const track = { id: 1, title: 'Test Track', duration: 180, url: 'https://example.com/track.mp3', }; vi.mocked(usePlayer).mockReturnValue({ ...mockPlayer, currentTrack: track, }); render(); expect(screen.getByTestId('audio-player')).toBeInTheDocument(); expect(screen.getByText('Test Track')).toBeInTheDocument(); }); it('should handle error state', () => { const track = { id: 1, title: 'Test Track', duration: 180, url: 'https://example.com/track.mp3', }; vi.mocked(usePlayer).mockReturnValue({ ...mockPlayer, currentTrack: track, }); // Mock error state - this would be set by the component internally render(); // Error component should be renderable expect(screen.getByTestId('audio-player')).toBeInTheDocument(); }); it('should handle loading state', () => { const track = { id: 1, title: 'Test Track', duration: 180, url: 'https://example.com/track.mp3', }; vi.mocked(usePlayer).mockReturnValue({ ...mockPlayer, currentTrack: track, }); render(); // Loading component should be renderable expect(screen.getByTestId('audio-player')).toBeInTheDocument(); }); it('should handle queue navigation with next button', () => { const track1 = { id: 1, title: 'Track 1', duration: 180, url: 'https://example.com/track1.mp3', }; const track2 = { id: 2, title: 'Track 2', duration: 200, url: 'https://example.com/track2.mp3', }; vi.mocked(usePlayer).mockReturnValue({ ...mockPlayer, currentTrack: track1, queue: [track1, track2], currentIndex: 0, }); render(); // Next button should be enabled when there are more tracks expect(mockPlayer.next).toBeDefined(); }); it('should handle queue navigation with previous button', () => { const track1 = { id: 1, title: 'Track 1', duration: 180, url: 'https://example.com/track1.mp3', }; const track2 = { id: 2, title: 'Track 2', duration: 200, url: 'https://example.com/track2.mp3', }; vi.mocked(usePlayer).mockReturnValue({ ...mockPlayer, currentTrack: track2, queue: [track1, track2], currentIndex: 1, }); render(); // Previous button should be enabled when not at first track expect(mockPlayer.previous).toBeDefined(); }); it('should disable next button when at end of queue', () => { const track = { id: 1, title: 'Track 1', duration: 180, url: 'https://example.com/track1.mp3', }; vi.mocked(usePlayer).mockReturnValue({ ...mockPlayer, currentTrack: track, queue: [track], currentIndex: 0, }); render(); // Next should not be available when at end expect(mockPlayer.next).toBeDefined(); }); it('should disable previous button when at start of queue', () => { const track = { id: 1, title: 'Track 1', duration: 180, url: 'https://example.com/track1.mp3', }; vi.mocked(usePlayer).mockReturnValue({ ...mockPlayer, currentTrack: track, queue: [track], currentIndex: 0, }); render(); // Previous should not be available when at start expect(mockPlayer.previous).toBeDefined(); }); });