veza/apps/web/src/features/player/components/QualitySelector.test.tsx
senke 2efaa1432b test: fix and improve unit tests across multiple features
Fix mocking issues, add missing test cases, and align tests with
current component APIs for analytics, chat, marketplace, player,
playlists, settings, tracks, and auth features.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 23:34:42 +01:00

276 lines
8.8 KiB
TypeScript

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(<QualitySelector {...defaultProps} />);
expect(screen.getByLabelText('Qualité audio: Auto')).toBeInTheDocument();
});
it('should display current quality', () => {
render(<QualitySelector {...defaultProps} currentQuality="high" />);
expect(screen.getByText('Haute')).toBeInTheDocument();
});
it('should open dropdown when button is clicked', async () => {
const user = userEvent.setup();
render(<QualitySelector {...defaultProps} />);
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(
<div>
<QualitySelector {...defaultProps} />
<div data-testid="outside">Outside</div>
</div>,
);
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(<QualitySelector {...defaultProps} />);
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(<QualitySelector {...defaultProps} />);
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(<QualitySelector {...defaultProps} />);
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(<QualitySelector {...defaultProps} />);
const button = screen.getByLabelText('Qualité audio: Auto');
await user.click(button);
await waitFor(() => {
expect(screen.getByText('128 kbps')).toBeInTheDocument();
expect(screen.getByText('256 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(<QualitySelector {...defaultProps} currentQuality="high" />);
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(
<QualitySelector {...defaultProps} currentQuality="high" />,
);
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[class*="text-muted"]');
expect(checkIcon).toBeInTheDocument();
});
it('should filter available qualities', async () => {
const user = userEvent.setup();
const { container } = render(
<QualitySelector
{...defaultProps}
availableQualities={['auto', 'medium', 'high']}
/>,
);
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(<QualitySelector {...defaultProps} disabled={true} />);
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(<QualitySelector {...defaultProps} disabled={true} />);
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(
<QualitySelector {...defaultProps} className="custom-class" />,
);
expect(container.firstChild).toHaveClass('custom-class');
});
it('should have accessible attributes', () => {
render(<QualitySelector {...defaultProps} />);
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(<QualitySelector {...defaultProps} />);
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(
<QualitySelector {...defaultProps} currentQuality="auto" />,
);
expect(screen.getByText('Auto')).toBeInTheDocument();
rerender(<QualitySelector {...defaultProps} currentQuality="low" />);
expect(screen.getByText('Faible')).toBeInTheDocument();
rerender(<QualitySelector {...defaultProps} currentQuality="medium" />);
expect(screen.getByText('Moyenne')).toBeInTheDocument();
rerender(<QualitySelector {...defaultProps} currentQuality="high" />);
expect(screen.getByText('Haute')).toBeInTheDocument();
rerender(<QualitySelector {...defaultProps} currentQuality="lossless" />);
expect(screen.getByText('Sans perte')).toBeInTheDocument();
});
});