import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { QualitySelector } from './QualitySelector'; import type { AudioQuality } from './QualitySelector'; describe('QualitySelector', () => { const mockOnQualityChange = vi.fn(); const defaultProps = { currentQuality: 'auto' as AudioQuality, onQualityChange: mockOnQualityChange, }; beforeEach(() => { vi.clearAllMocks(); }); it('should render quality selector', () => { render(); expect(screen.getByLabelText('Qualité audio: Auto')).toBeInTheDocument(); }); it('should display current quality', () => { render(); expect(screen.getByText('Haute')).toBeInTheDocument(); }); it('should open dropdown when button is clicked', async () => { const user = userEvent.setup(); render(); const button = screen.getByLabelText('Qualité audio: Auto'); await user.click(button); await waitFor(() => { expect(screen.getByRole('listbox')).toBeInTheDocument(); }); }); it('should close dropdown when clicking outside', async () => { const user = userEvent.setup(); render(
Outside
, ); const button = screen.getByLabelText('Qualité audio: Auto'); await user.click(button); await waitFor(() => { expect(screen.getByRole('listbox')).toBeInTheDocument(); }); const outside = screen.getByTestId('outside'); await user.click(outside); await waitFor(() => { expect(screen.queryByRole('listbox')).not.toBeInTheDocument(); }); }); it('should call onQualityChange when quality is selected', async () => { const user = userEvent.setup(); render(); const button = screen.getByLabelText('Qualité audio: Auto'); await user.click(button); await waitFor(() => { expect(screen.getByRole('listbox')).toBeInTheDocument(); }); const highOption = screen.getByText('Haute'); await user.click(highOption); expect(mockOnQualityChange).toHaveBeenCalledWith('high'); }); it('should close dropdown after selecting quality', async () => { const user = userEvent.setup(); render(); const button = screen.getByLabelText('Qualité audio: Auto'); await user.click(button); await waitFor(() => { expect(screen.getByRole('listbox')).toBeInTheDocument(); }); const highOption = screen.getByText('Haute'); await user.click(highOption); await waitFor(() => { expect(screen.queryByRole('listbox')).not.toBeInTheDocument(); }); }); it('should display all quality options', async () => { const user = userEvent.setup(); render(); const button = screen.getByLabelText('Qualité audio: Auto'); await user.click(button); await waitFor(() => { const listbox = screen.getByRole('listbox'); expect(listbox).toBeInTheDocument(); }); // Check all options are in the dropdown const listbox = screen.getByRole('listbox'); expect(listbox).toHaveTextContent('Auto'); expect(listbox).toHaveTextContent('Faible'); expect(listbox).toHaveTextContent('Moyenne'); expect(listbox).toHaveTextContent('Haute'); expect(listbox).toHaveTextContent('Sans perte'); }); it('should display quality descriptions', async () => { const user = userEvent.setup(); render(); const button = screen.getByLabelText('Qualité audio: Auto'); await user.click(button); await waitFor(() => { expect(screen.getByText('128 kbps')).toBeInTheDocument(); expect(screen.getByText('192 kbps')).toBeInTheDocument(); expect(screen.getByText('320 kbps')).toBeInTheDocument(); expect(screen.getByText('FLAC / WAV')).toBeInTheDocument(); }); }); it('should highlight current quality', async () => { const user = userEvent.setup(); render(); const button = screen.getByLabelText('Qualité audio: Haute'); await user.click(button); await waitFor(() => { const listbox = screen.getByRole('listbox'); expect(listbox).toBeInTheDocument(); }); // Find the option in the dropdown (not the button) const listbox = screen.getByRole('listbox'); const highOption = Array.from( listbox.querySelectorAll('[role="option"]'), ).find((option) => option.textContent?.includes('Haute')); expect(highOption).toHaveAttribute('aria-selected', 'true'); }); it('should show check icon for current quality', async () => { const user = userEvent.setup(); const { container } = render( , ); const button = screen.getByLabelText('Qualité audio: Haute'); await user.click(button); await waitFor(() => { const listbox = screen.getByRole('listbox'); expect(listbox).toBeInTheDocument(); }); // Check icon should be present for the selected quality const listbox = screen.getByRole('listbox'); const checkIcon = listbox.querySelector('svg.text-blue-600'); expect(checkIcon).toBeInTheDocument(); }); it('should filter available qualities', async () => { const user = userEvent.setup(); const { container } = render( , ); const button = screen.getByLabelText('Qualité audio: Auto'); await user.click(button); await waitFor(() => { const listbox = screen.getByRole('listbox'); expect(listbox).toBeInTheDocument(); }); // Check that only available qualities are shown in the dropdown const listbox = screen.getByRole('listbox'); const options = listbox.querySelectorAll('[role="option"]'); expect(options).toHaveLength(3); // Check specific options are present expect(listbox).toHaveTextContent('Auto'); expect(listbox).toHaveTextContent('Moyenne'); expect(listbox).toHaveTextContent('Haute'); expect(listbox).not.toHaveTextContent('Faible'); expect(listbox).not.toHaveTextContent('Sans perte'); }); it('should be disabled when disabled prop is true', () => { render(); const button = screen.getByLabelText('Qualité audio: Auto'); expect(button).toBeDisabled(); expect(button).toHaveAttribute('aria-disabled', 'true'); }); it('should not open dropdown when disabled', async () => { const user = userEvent.setup(); render(); const button = screen.getByLabelText('Qualité audio: Auto'); await user.click(button); expect(screen.queryByRole('listbox')).not.toBeInTheDocument(); }); it('should apply custom className', () => { const { container } = render( , ); expect(container.firstChild).toHaveClass('custom-class'); }); it('should have accessible attributes', () => { render(); const button = screen.getByLabelText('Qualité audio: Auto'); expect(button).toHaveAttribute('aria-expanded', 'false'); expect(button).toHaveAttribute('aria-haspopup', 'listbox'); }); it('should update aria-expanded when dropdown opens', async () => { const user = userEvent.setup(); render(); const button = screen.getByLabelText('Qualité audio: Auto'); expect(button).toHaveAttribute('aria-expanded', 'false'); await user.click(button); await waitFor(() => { expect(screen.getByRole('listbox')).toBeInTheDocument(); expect(button).toHaveAttribute('aria-expanded', 'true'); }); }); it('should handle all quality types', () => { const { rerender } = render( , ); expect(screen.getByText('Auto')).toBeInTheDocument(); rerender(); expect(screen.getByText('Faible')).toBeInTheDocument(); rerender(); expect(screen.getByText('Moyenne')).toBeInTheDocument(); rerender(); expect(screen.getByText('Haute')).toBeInTheDocument(); rerender(); expect(screen.getByText('Sans perte')).toBeInTheDocument(); }); });