import { fireEvent, render, screen, within } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import App from '../src/App' import { AppStateProvider, PATTERNS_PATH, activeHref, navigationGroups, patternFromSearch, routeForPath, routes, } from '../src/app' function renderAt(url: string) { window.history.pushState(null, '', url) return render( , ) } /** The sidebar and the overview cards can link to the same page — scope the queries that must land on one of them. */ const sidebar = () => within(document.querySelector('.sidebar') as HTMLElement) const overview = () => within(document.querySelector('.overview-grid') as HTMLElement) beforeEach(() => { localStorage.clear() /* jsdom has no layout — the shell's scroll-to-top effect would hit the "not implemented" hook on every navigation. */ vi.spyOn(window, 'scrollTo').mockImplementation(() => {}) }) afterEach(() => { vi.restoreAllMocks() }) describe('route table', () => { it('keeps every sidebar entry pointed at a route that exists', () => { const known = new Set(routes.map(route => route.path)) for (const group of navigationGroups) { for (const item of group.items) { const [path] = item.href.split('?') expect(known.has(path!)).toBe(true) } } }) it('leaves no route unreachable from the sidebar', () => { const navPaths = new Set( navigationGroups.flatMap(group => group.items.map(item => item.href.split('?')[0]!)), ) for (const route of routes) { expect(navPaths.has(route.path)).toBe(true) } }) it('looks routes up by path and rejects unknown ones', () => { expect(routeForPath('/components/buttons')?.label).toBe('Buttons') expect(routeForPath('/nope')).toBeUndefined() }) }) describe('pattern URLs', () => { it('accepts a known pattern, falls back on anything else', () => { expect(patternFromSearch('?pattern=table')).toBe('table') expect(patternFromSearch('?pattern=space')).toBe('metrics') expect(patternFromSearch('')).toBe('metrics') }) it('marks the matching pattern entry active', () => { expect(activeHref(PATTERNS_PATH, '?pattern=deploy')).toBe('/patterns?pattern=deploy') expect(activeHref(PATTERNS_PATH, '')).toBe('/patterns?pattern=metrics') expect(activeHref('/components/icons', '')).toBe('/components/icons') }) }) describe('routing', () => { it('renders the overview at /', () => { renderAt('/') expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent('Build with clarity.') expect(overview().getByText('Foundations')).toBeInTheDocument() expect(overview().getByRole('link', { name: /Color tokens/ })).toHaveAttribute( 'href', '/foundations/colors', ) }) it('renders the page registered for a URL', () => { for (const route of routes) { const { unmount } = renderAt(route.path) expect(screen.getByText(route.title, { selector: '.section-heading h2' })).toBeInTheDocument() unmount() } }) it('marks the sidebar entry for the current URL as current', () => { renderAt('/foundations/colors') expect(sidebar().getByRole('link', { name: 'Color tokens' })).toHaveAttribute('aria-current', 'page') expect(sidebar().getByRole('link', { name: 'Typography' })).not.toHaveAttribute('aria-current') }) it('navigates on a sidebar click without a full page load', () => { renderAt('/') const link = sidebar().getByRole('link', { name: 'Typography' }) fireEvent.click(link) expect(window.location.pathname).toBe('/foundations/typography') expect(link).toHaveAttribute('aria-current', 'page') expect(screen.getByText('Typography', { selector: '.section-heading h2' })).toBeInTheDocument() }) it('opens the pattern named in the URL', () => { renderAt('/patterns?pattern=table') expect(screen.getByRole('button', { name: /Service Monitor Table/ })).toHaveAttribute('aria-pressed', 'true') expect(screen.getByRole('button', { name: /Metrics Dashboard/ })).toHaveAttribute('aria-pressed', 'false') // Sidebar pattern entries share /patterns and differ only by the query. expect(sidebar().getByRole('link', { name: 'Service Monitor Table' })).toHaveAttribute( 'aria-current', 'page', ) }) it('writes the chosen pattern into the URL', () => { renderAt('/patterns') fireEvent.click(screen.getByRole('button', { name: /Deployment Flow/ })) expect(window.location.search).toBe('?pattern=deploy') }) it('falls back to a 404 page instead of a blank screen', () => { renderAt('/definitely/not/a/route') expect(screen.getByText('Page not found')).toBeInTheDocument() }) })