/**
* Tests for AppBreadcrumbs Component
* Verifies breadcrumb generation, navigation, and accessibility
*/
import { render, screen } from '@testing-library/react';
import { AppBreadcrumbs } from '@/components/layout/AppBreadcrumbs';
import { mockUsePathname } from 'next-intl/navigation';
describe('AppBreadcrumbs', () => {
beforeEach(() => {
jest.clearAllMocks();
mockUsePathname.mockReturnValue('/projects');
});
describe('Rendering', () => {
it('renders breadcrumb navigation', () => {
render();
expect(screen.getByTestId('breadcrumbs')).toBeInTheDocument();
});
it('renders with correct aria-label', () => {
render();
const nav = screen.getByTestId('breadcrumbs');
expect(nav).toHaveAttribute('aria-label', 'Breadcrumb');
});
it('renders home icon by default', () => {
render();
expect(screen.getByTestId('breadcrumb-home')).toBeInTheDocument();
});
it('hides home icon when showHome is false', () => {
render();
expect(screen.queryByTestId('breadcrumb-home')).not.toBeInTheDocument();
});
});
describe('Auto-generated Breadcrumbs', () => {
it('generates breadcrumb from pathname', () => {
mockUsePathname.mockReturnValue('/projects');
render();
expect(screen.getByTestId('breadcrumb-projects')).toBeInTheDocument();
});
it('generates nested breadcrumbs', () => {
mockUsePathname.mockReturnValue('/projects/my-project/issues');
render();
expect(screen.getByTestId('breadcrumb-projects')).toBeInTheDocument();
expect(screen.getByTestId('breadcrumb-my-project')).toBeInTheDocument();
expect(screen.getByTestId('breadcrumb-issues')).toBeInTheDocument();
});
it('uses label mappings for known paths', () => {
mockUsePathname.mockReturnValue('/admin/agent-types');
render();
expect(screen.getByText('Admin')).toBeInTheDocument();
expect(screen.getByText('Agent Types')).toBeInTheDocument();
});
it('uses segment as label for unknown paths', () => {
mockUsePathname.mockReturnValue('/custom-path');
render();
expect(screen.getByText('custom-path')).toBeInTheDocument();
});
});
describe('Custom Breadcrumbs', () => {
it('uses provided items instead of auto-generation', () => {
mockUsePathname.mockReturnValue('/some/path');
const items = [
{ label: 'Custom', href: '/custom', current: false },
{ label: 'Path', href: '/custom/path', current: true },
];
render();
expect(screen.getByTestId('breadcrumb-custom')).toBeInTheDocument();
expect(screen.getByTestId('breadcrumb-path')).toBeInTheDocument();
expect(screen.queryByText('some')).not.toBeInTheDocument();
});
});
describe('Active State', () => {
it('marks last item as current page', () => {
mockUsePathname.mockReturnValue('/projects/issues');
render();
const issuesItem = screen.getByTestId('breadcrumb-issues');
expect(issuesItem).toHaveAttribute('aria-current', 'page');
});
it('renders non-current items as links', () => {
mockUsePathname.mockReturnValue('/projects/issues');
render();
const projectsLink = screen.getByTestId('breadcrumb-projects');
expect(projectsLink.tagName).toBe('A');
expect(projectsLink).toHaveAttribute('href', '/projects');
});
it('renders current item as span (not a link)', () => {
mockUsePathname.mockReturnValue('/projects');
render();
const projectsItem = screen.getByTestId('breadcrumb-projects');
expect(projectsItem.tagName).toBe('SPAN');
});
});
describe('Separators', () => {
it('renders chevron separators between items', () => {
mockUsePathname.mockReturnValue('/projects/issues');
render();
// There should be separators: home -> projects -> issues
const separators = screen.getAllByRole('listitem');
expect(separators.length).toBeGreaterThanOrEqual(2);
});
});
describe('Empty State', () => {
it('returns null when no breadcrumbs', () => {
mockUsePathname.mockReturnValue('/');
const { container } = render();
expect(container).toBeEmptyDOMElement();
});
});
describe('Accessibility', () => {
it('home link has accessible label', () => {
render();
const homeLink = screen.getByTestId('breadcrumb-home');
expect(homeLink).toHaveAttribute('aria-label', 'Home');
});
it('links have focus-visible styling', () => {
mockUsePathname.mockReturnValue('/projects/issues');
render();
const projectsLink = screen.getByTestId('breadcrumb-projects');
expect(projectsLink).toHaveClass('focus-visible:ring-2');
});
it('navigation has proper landmark role', () => {
render();
const nav = screen.getByRole('navigation');
expect(nav).toBeInTheDocument();
});
});
describe('Custom className', () => {
it('applies custom className', () => {
render();
const nav = screen.getByTestId('breadcrumbs');
expect(nav).toHaveClass('custom-class');
});
});
});