veza/apps/web/src/features/player/components/PlayerError.test.tsx
2025-12-12 21:34:34 -05:00

204 lines
6.1 KiB
TypeScript

import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { PlayerError } from './PlayerError';
describe('PlayerError', () => {
it('should not render when error is null', () => {
const { container } = render(<PlayerError error={null} />);
expect(container.firstChild).toBeNull();
});
it('should render when error is provided', () => {
const error = new Error('Test error');
render(<PlayerError error={error} />);
expect(screen.getByRole('alert')).toBeInTheDocument();
});
it('should display error message', () => {
const error = new Error('Test error');
render(<PlayerError error={error} />);
expect(
screen.getByText('Une erreur est survenue lors de la lecture.'),
).toBeInTheDocument();
});
it('should display error title', () => {
const error = new Error('Test error');
render(<PlayerError error={error} />);
expect(screen.getByText('Erreur de lecture')).toBeInTheDocument();
});
it('should display network error message', () => {
const error = new Error('Network error');
error.name = 'NetworkError';
render(<PlayerError error={error} />);
expect(
screen.getByText(
'Erreur de connexion. Vérifiez votre connexion internet.',
),
).toBeInTheDocument();
});
it('should display decode error message', () => {
const error = new Error('Decode error');
error.name = 'DecodeError';
render(<PlayerError error={error} />);
expect(
screen.getByText(
'Erreur de décodage audio. Le fichier est peut-être corrompu.',
),
).toBeInTheDocument();
});
it('should display source error message', () => {
const error = new Error('Source not found');
error.name = 'NotFoundError';
render(<PlayerError error={error} />);
expect(
screen.getByText(
'Erreur de source audio. Le fichier est introuvable ou inaccessible.',
),
).toBeInTheDocument();
});
it('should display abort error message', () => {
const error = new Error('Abort error');
error.name = 'AbortError';
render(<PlayerError error={error} />);
expect(screen.getByText('Chargement annulé.')).toBeInTheDocument();
});
it('should use custom errorType', () => {
const error = new Error('Test error');
render(<PlayerError error={error} errorType="network" />);
expect(
screen.getByText(
'Erreur de connexion. Vérifiez votre connexion internet.',
),
).toBeInTheDocument();
});
it('should display retry button when onRetry is provided', () => {
const error = new Error('Test error');
const onRetry = vi.fn();
render(<PlayerError error={error} onRetry={onRetry} />);
expect(screen.getByText('Réessayer')).toBeInTheDocument();
});
it('should not display retry button when onRetry is not provided', () => {
const error = new Error('Test error');
render(<PlayerError error={error} />);
expect(screen.queryByText('Réessayer')).not.toBeInTheDocument();
});
it('should not display retry button when showRetry is false', () => {
const error = new Error('Test error');
const onRetry = vi.fn();
render(<PlayerError error={error} onRetry={onRetry} showRetry={false} />);
expect(screen.queryByText('Réessayer')).not.toBeInTheDocument();
});
it('should call onRetry when retry button is clicked', async () => {
const user = userEvent.setup();
const error = new Error('Test error');
const onRetry = vi.fn();
render(<PlayerError error={error} onRetry={onRetry} />);
const retryButton = screen.getByText('Réessayer');
await user.click(retryButton);
expect(onRetry).toHaveBeenCalledTimes(1);
});
it('should use custom retry label', () => {
const error = new Error('Test error');
const onRetry = vi.fn();
render(<PlayerError error={error} onRetry={onRetry} retryLabel="Retry" />);
expect(screen.getByText('Retry')).toBeInTheDocument();
});
it('should apply custom className', () => {
const error = new Error('Test error');
const { container } = render(
<PlayerError error={error} className="custom-class" />,
);
expect(container.firstChild).toHaveClass('custom-class');
});
it('should have accessible attributes', () => {
const error = new Error('Test error');
render(<PlayerError error={error} />);
const alert = screen.getByRole('alert');
expect(alert).toHaveAttribute('aria-live', 'assertive');
});
it('should have accessible retry button', () => {
const error = new Error('Test error');
const onRetry = vi.fn();
const { container } = render(
<PlayerError error={error} onRetry={onRetry} />,
);
const retryButton = screen.getByText('Réessayer');
// Check that aria-label is present on the button element
const buttonElement = container.querySelector('button[aria-label]');
expect(buttonElement).toBeInTheDocument();
expect(buttonElement?.getAttribute('aria-label')).toContain('Réessayer');
});
it('should detect network error from message', () => {
const error = new Error('Network request failed');
render(<PlayerError error={error} />);
expect(
screen.getByText(
'Erreur de connexion. Vérifiez votre connexion internet.',
),
).toBeInTheDocument();
});
it('should detect decode error from message', () => {
const error = new Error('Failed to decode audio data');
render(<PlayerError error={error} />);
expect(
screen.getByText(
'Erreur de décodage audio. Le fichier est peut-être corrompu.',
),
).toBeInTheDocument();
});
it('should detect source error from message', () => {
const error = new Error('Source not found');
render(<PlayerError error={error} />);
expect(
screen.getByText(
'Erreur de source audio. Le fichier est introuvable ou inaccessible.',
),
).toBeInTheDocument();
});
it('should detect abort error from message', () => {
const error = new Error('Request aborted');
render(<PlayerError error={error} />);
expect(screen.getByText('Chargement annulé.')).toBeInTheDocument();
});
});