veza/apps/web/src/components/ErrorBoundary.test.tsx
senke 441cb02233 fix(a11y): fix heading hierarchy h1→h3 gaps on 8 pages
Changed h3 section titles to h2 on pages where they directly follow the page h1:
- Library: empty state heading
- Queue: "Now Playing" + "Up Next"
- Search: discovery sections + results sections
- Profile: "About" + "Links"
- Sessions: card title
- Notifications: date group headers

Also: add 'api' binary to .gitignore

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

132 lines
3.5 KiB
TypeScript

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { ErrorBoundary } from './ErrorBoundary';
// Composant qui lance une erreur pour tester l'ErrorBoundary
const ThrowError = ({ shouldThrow }: { shouldThrow: boolean }) => {
if (shouldThrow) {
throw new Error('Test error');
}
return <div>No error</div>;
};
// Suppression de console.error pour les tests
const originalError = console.error;
beforeEach(() => {
console.error = vi.fn();
});
afterEach(() => {
console.error = originalError;
});
describe('ErrorBoundary', () => {
it('should render children when there is no error', () => {
render(
<ErrorBoundary>
<div>Test content</div>
</ErrorBoundary>,
);
expect(screen.getByText('Test content')).toBeInTheDocument();
});
it('should catch errors and display error UI', () => {
render(
<ErrorBoundary>
<ThrowError shouldThrow={true} />
</ErrorBoundary>,
);
// ErrorDisplay shows fallback message for generic errors
expect(
screen.getByText(/An unexpected error occurred/i),
).toBeInTheDocument();
expect(screen.getByRole('alert')).toBeInTheDocument();
});
it('should display retry button', () => {
render(
<ErrorBoundary>
<ThrowError shouldThrow={true} />
</ErrorBoundary>,
);
const retryButton = screen.getByRole('button', { name: /retry/i });
expect(retryButton).toBeInTheDocument();
});
it('should display home button', () => {
render(
<ErrorBoundary>
<ThrowError shouldThrow={true} />
</ErrorBoundary>,
);
const homeButton = screen.getByRole('button', {
name: /return home/i,
});
expect(homeButton).toBeInTheDocument();
});
it('should reset error state when retry button is clicked', () => {
const { rerender } = render(
<ErrorBoundary>
<ThrowError shouldThrow={true} />
</ErrorBoundary>,
);
expect(
screen.getByText(/An unexpected error occurred/i),
).toBeInTheDocument();
// Rerender avec shouldThrow=false avant le clic pour que le boundary reçu un enfant qui ne lance pas
rerender(
<ErrorBoundary>
<ThrowError shouldThrow={false} />
</ErrorBoundary>,
);
const retryButton = screen.getByRole('button', { name: /retry/i });
fireEvent.click(retryButton);
// Le composant devrait afficher le contenu normal après le reset
expect(screen.getByText('No error')).toBeInTheDocument();
});
it('should use custom fallback when provided', () => {
const customFallback = <div>Custom error message</div>;
render(
<ErrorBoundary fallback={customFallback}>
<ThrowError shouldThrow={true} />
</ErrorBoundary>,
);
expect(screen.getByText('Custom error message')).toBeInTheDocument();
expect(
screen.queryByText(/An unexpected error occurred/i),
).not.toBeInTheDocument();
});
it('should log error to console', () => {
render(
<ErrorBoundary>
<ThrowError shouldThrow={true} />
</ErrorBoundary>,
);
expect(console.error).toHaveBeenCalled();
});
it('should have correct state structure', () => {
const { container } = render(
<ErrorBoundary>
<ThrowError shouldThrow={true} />
</ErrorBoundary>,
);
// L'ErrorBoundary devrait avoir un état d'erreur
expect(container.querySelector('.min-h-screen')).toBeInTheDocument();
});
});