191 lines
5 KiB
TypeScript
191 lines
5 KiB
TypeScript
/**
|
|
* 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(
|
|
<PlaylistBatchActions
|
|
selectedPlaylists={[]}
|
|
onSelectionClear={mockOnSelectionClear}
|
|
/>,
|
|
);
|
|
expect(container.firstChild).toBeNull();
|
|
});
|
|
|
|
it('should render when playlists are selected', () => {
|
|
render(
|
|
<PlaylistBatchActions
|
|
selectedPlaylists={[mockPlaylists[0]]}
|
|
onSelectionClear={mockOnSelectionClear}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.getByText(/1 playlist sélectionnée/)).toBeInTheDocument();
|
|
});
|
|
|
|
it('should display correct count for multiple playlists', () => {
|
|
render(
|
|
<PlaylistBatchActions
|
|
selectedPlaylists={mockPlaylists}
|
|
onSelectionClear={mockOnSelectionClear}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.getByText(/2 playlists sélectionnées/)).toBeInTheDocument();
|
|
});
|
|
|
|
it('should call onSelectionClear when clear button is clicked', async () => {
|
|
const user = userEvent.setup();
|
|
render(
|
|
<PlaylistBatchActions
|
|
selectedPlaylists={[mockPlaylists[0]]}
|
|
onSelectionClear={mockOnSelectionClear}
|
|
/>,
|
|
);
|
|
|
|
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(
|
|
<PlaylistBatchActions
|
|
selectedPlaylists={[mockPlaylists[0]]}
|
|
onSelectionClear={mockOnSelectionClear}
|
|
/>,
|
|
);
|
|
|
|
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(
|
|
<PlaylistBatchActions
|
|
selectedPlaylists={[mockPlaylists[0]]}
|
|
onSelectionClear={mockOnSelectionClear}
|
|
/>,
|
|
);
|
|
|
|
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(
|
|
<PlaylistBatchActions
|
|
selectedPlaylists={[mockPlaylists[0]]}
|
|
onSelectionClear={mockOnSelectionClear}
|
|
onPlaylistsDeleted={mockOnPlaylistsDeleted}
|
|
/>,
|
|
);
|
|
|
|
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(
|
|
<PlaylistBatchActions
|
|
selectedPlaylists={mockPlaylists}
|
|
onSelectionClear={mockOnSelectionClear}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.getByRole('region')).toHaveAttribute(
|
|
'aria-label',
|
|
expect.stringContaining('2 playlists sélectionnées'),
|
|
);
|
|
});
|
|
});
|