import { describe, it, expect, vi } from 'vitest'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { TrackListRow } from './TrackListRow'; import type { Track } from '../../player/types'; const mockTrack: Track = { id: 1, title: 'Test Track', artist: 'Test Artist', album: 'Test Album', duration: 180, url: 'https://example.com/track.mp3', cover: 'https://example.com/cover.jpg', genre: 'Rock', }; describe('TrackListRow', () => { const mockOnTrackClick = vi.fn(); const mockOnTrackPlay = vi.fn(); const mockOnTrackLike = vi.fn(); const mockOnTrackMore = vi.fn(); const mockOnTrackSelect = vi.fn(); beforeEach(() => { vi.clearAllMocks(); }); it('should render track row', () => { render(); expect(screen.getByText('Test Track')).toBeInTheDocument(); }); it('should display track title', () => { render(); expect(screen.getByText('Test Track')).toBeInTheDocument(); }); it('should display track artist when showMetadata is true', () => { render(); // In list format, artist is displayed with album, so we check for text containing artist expect(screen.getByText(/Test Artist/)).toBeInTheDocument(); }); it('should display track album when showMetadata is true', () => { render(); expect(screen.getByText(/Test Album/)).toBeInTheDocument(); }); it('should display track artist and album separately in table format', () => { render( , ); expect(screen.getByText('Test Artist')).toBeInTheDocument(); expect(screen.getByText('Test Album')).toBeInTheDocument(); }); it('should display cover image when showCover is true', () => { render(); const image = screen.getByAltText('Cover de Test Track'); expect(image).toBeInTheDocument(); expect(image).toHaveAttribute('src', mockTrack.cover); }); it('should display placeholder when cover is missing', () => { const trackWithoutCover = { ...mockTrack, cover: undefined }; const { container } = render( , ); const musicIcon = container.querySelector('svg'); expect(musicIcon).toBeInTheDocument(); }); it('should display duration when showDuration is true', () => { render(); expect(screen.getByText('3:00')).toBeInTheDocument(); }); it('should call onTrackClick when row is clicked', async () => { const user = userEvent.setup(); render(); const row = screen.getByRole('listitem'); await user.click(row); expect(mockOnTrackClick).toHaveBeenCalledWith(mockTrack); }); it('should call onTrackPlay when play button is clicked', async () => { const user = userEvent.setup(); render(); const row = screen.getByRole('listitem'); await user.hover(row); await waitFor(() => { const playButtons = screen.queryAllByLabelText(/Lire/); if (playButtons.length > 0) { expect(playButtons[0]).toBeInTheDocument(); } }); const playButtons = screen.queryAllByLabelText(/Lire/); if (playButtons.length > 0) { await user.click(playButtons[0]); expect(mockOnTrackPlay).toHaveBeenCalledWith(mockTrack); } }); it('should call onTrackLike when like button is clicked', async () => { const user = userEvent.setup(); render(); const row = screen.getByRole('listitem'); await user.hover(row); await waitFor(() => { const likeButtons = screen.queryAllByLabelText(/favoris/); if (likeButtons.length > 0) { expect(likeButtons[0]).toBeInTheDocument(); } }); const likeButtons = screen.queryAllByLabelText(/Ajouter.*favoris/); if (likeButtons.length > 0) { await user.click(likeButtons[0]); expect(mockOnTrackLike).toHaveBeenCalledWith(mockTrack); } }); it('should call onTrackMore when more button is clicked', async () => { const user = userEvent.setup(); render(); const row = screen.getByRole('listitem'); await user.hover(row); await waitFor(() => { const moreButtons = screen.queryAllByLabelText(/Plus d'options/); if (moreButtons.length > 0) { expect(moreButtons[0]).toBeInTheDocument(); } }); const moreButtons = screen.queryAllByLabelText(/Plus d'options/); if (moreButtons.length > 0) { await user.click(moreButtons[0]); expect(mockOnTrackMore).toHaveBeenCalledWith(mockTrack); } }); it('should call onTrackSelect when checkbox is clicked', async () => { const user = userEvent.setup(); render( , ); const checkbox = screen.getByLabelText(/Sélectionner/); await user.click(checkbox); expect(mockOnTrackSelect).toHaveBeenCalledWith(mockTrack.id, true); }); it('should display selected state when isSelected is true', () => { const { container } = render( , ); const checkbox = screen.getByLabelText(/Sélectionner/); expect(checkbox).toBeChecked(); }); it('should highlight selected row', () => { const { container } = render( , ); const row = container.querySelector('.bg-blue-50, .dark:bg-blue-900/20'); expect(row).toBeInTheDocument(); }); it('should display liked state when isLiked is true', () => { render( , ); const likedButtons = screen.queryAllByLabelText(/Retirer.*favoris/); expect(likedButtons.length).toBeGreaterThanOrEqual(0); }); it('should display playing state when isPlaying is true', () => { render( , ); const pauseButtons = screen.queryAllByLabelText(/Mettre en pause/); expect(pauseButtons.length).toBeGreaterThanOrEqual(0); }); it('should not call onTrackClick when action button is clicked', async () => { const user = userEvent.setup(); render( , ); const row = screen.getByRole('listitem'); await user.hover(row); await waitFor(() => { const likeButtons = screen.queryAllByLabelText(/favoris/); if (likeButtons.length > 0) { expect(likeButtons[0]).toBeInTheDocument(); } }); const likeButtons = screen.queryAllByLabelText(/Ajouter.*favoris/); if (likeButtons.length > 0) { await user.click(likeButtons[0]); expect(mockOnTrackLike).toHaveBeenCalled(); expect(mockOnTrackClick).not.toHaveBeenCalled(); } }); it('should render in table format when format is table', () => { render(); const row = screen.getByRole('row'); expect(row).toBeInTheDocument(); }); it('should render in list format when format is list', () => { render(); const row = screen.getByRole('listitem'); expect(row).toBeInTheDocument(); }); it('should apply custom className', () => { const { container } = render( , ); const row = container.querySelector('[role="listitem"]'); expect(row).toHaveClass('custom-class'); }); it('should have hover effects', async () => { const user = userEvent.setup(); render(); const row = screen.getByRole('listitem'); await user.hover(row); await waitFor(() => { // Hover should trigger state change expect(row).toBeInTheDocument(); }); }); it('should hide actions when showActions is false', () => { render( , ); const playButtons = screen.queryAllByLabelText(/Lire/); const likeButtons = screen.queryAllByLabelText(/favoris/); expect(playButtons.length).toBe(0); expect(likeButtons.length).toBe(0); }); it('should handle track without artist', () => { const trackWithoutArtist = { ...mockTrack, artist: undefined }; render(); expect(screen.getByText('Test Track')).toBeInTheDocument(); }); });