/** * 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'); }); }); });