/** * Tests pour PlaylistBatchActions * T0506: Create Playlist Batch Operations */ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { PlaylistBatchActions } from './PlaylistBatchActions'; import type { Playlist } from '../types'; // Mock hooks vi.mock('../hooks/usePlaylist', () => ({ useDeletePlaylist: vi.fn(() => ({ mutateAsync: vi.fn().mockResolvedValue(undefined), })), useCreateShareLink: vi.fn(() => ({ mutateAsync: vi .fn() .mockResolvedValue({ share_link: 'https://example.com/share/123' }), })), })); vi.mock('@/hooks/useToast', () => ({ useToast: vi.fn(() => ({ toast: vi.fn(), })), })); // Mock clipboard API Object.assign(navigator, { clipboard: { writeText: vi.fn().mockResolvedValue(undefined), }, }); describe('PlaylistBatchActions', () => { const mockPlaylists: Playlist[] = [ { id: 1, user_id: 1, title: 'Playlist 1', description: 'Description 1', is_public: true, track_count: 5, created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', }, { id: 2, user_id: 1, title: 'Playlist 2', description: 'Description 2', is_public: false, track_count: 10, created_at: '2024-01-02T00:00:00Z', updated_at: '2024-01-02T00:00:00Z', }, ]; const mockOnSelectionClear = vi.fn(); const mockOnPlaylistsDeleted = vi.fn(); beforeEach(() => { vi.clearAllMocks(); }); it('should not render when no playlists are selected', () => { const { container } = render( , ); expect(container.firstChild).toBeNull(); }); it('should render when playlists are selected', () => { render( , ); expect(screen.getByText(/1 playlist sélectionnée/)).toBeInTheDocument(); }); it('should display correct count for multiple playlists', () => { render( , ); expect(screen.getByText(/2 playlists sélectionnées/)).toBeInTheDocument(); }); it('should call onSelectionClear when clear button is clicked', async () => { const user = userEvent.setup(); render( , ); const clearButton = screen.getByLabelText( 'Désélectionner toutes les playlists', ); await user.click(clearButton); expect(mockOnSelectionClear).toHaveBeenCalledTimes(1); }); it('should export playlists to JSON', async () => { const user = userEvent.setup(); const createElementSpy = vi.spyOn(document, 'createElement'); const appendChildSpy = vi.spyOn(document.body, 'appendChild'); const removeChildSpy = vi.spyOn(document.body, 'removeChild'); render( , ); const exportButton = screen.getByLabelText('Exporter en JSON'); await user.click(exportButton); await waitFor(() => { expect(createElementSpy).toHaveBeenCalledWith('a'); expect(appendChildSpy).toHaveBeenCalled(); expect(removeChildSpy).toHaveBeenCalled(); }); }); it('should export playlists to CSV', async () => { const user = userEvent.setup(); const createElementSpy = vi.spyOn(document, 'createElement'); render( , ); const exportButton = screen.getByLabelText('Exporter en CSV'); await user.click(exportButton); await waitFor(() => { expect(createElementSpy).toHaveBeenCalledWith('a'); }); }); it('should show delete confirmation dialog', async () => { const user = userEvent.setup(); render( , ); const deleteButton = screen.getByLabelText( 'Supprimer les playlists sélectionnées', ); await user.click(deleteButton); expect(screen.getByText(/Supprimer les playlists \?/)).toBeInTheDocument(); expect(screen.getByText(/1 playlist/)).toBeInTheDocument(); }); it('should have accessible labels', () => { render( , ); expect(screen.getByRole('region')).toHaveAttribute( 'aria-label', expect.stringContaining('2 playlists sélectionnées'), ); }); });