import { render, screen } from '@testing-library/react' import { describe, it, expect, vi } from 'vitest' import { AppLayout } from './AppLayout' import type { AuthContext } from '@/hooks/useAuth' // Mock ResizeObserver for sidebar tests globalThis.ResizeObserver = class { observe() {} unobserve() {} disconnect() {} } as any // Mock matchMedia for use-mobile hook used by SidebarProvider Object.defineProperty(window, 'matchMedia', { writable: true, value: vi.fn().mockImplementation((query: string) => ({ matches: false, media: query, onchange: null, addListener: vi.fn(), removeListener: vi.fn(), addEventListener: vi.fn(), removeEventListener: vi.fn(), dispatchEvent: vi.fn(), })), }) vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key }), })) vi.mock('react-router-dom', () => ({ Link: ({ children, to, ...props }: any) => ( {children} ), useLocation: () => ({ pathname: '/' }), })) const mockAuth: AuthContext = { user: { display_name: 'Test' } as any, loading: false, login: vi.fn(), register: vi.fn(), logout: vi.fn(), token: 'test', refetch: vi.fn(), } as unknown as AuthContext describe('AppLayout', () => { it('NAV-01: sidebar element renders with distinct background', () => { render(
content
) // The sidebar renders with data-sidebar="sidebar" -- bg-sidebar token provides pastel background const sidebar = document.querySelector('[data-sidebar="sidebar"]') expect(sidebar).toBeInTheDocument() }) it('NAV-02: gradient wordmark renders in sidebar header', () => { render(
content
) const wordmark = screen.getByTestId('sidebar-wordmark') expect(wordmark).toBeInTheDocument() }) it('NAV-03: active nav item (dashboard at /) has data-active="true"', () => { render(
content
) const dashboardLink = screen.getByRole('link', { name: /nav\.dashboard/i }) // SidebarMenuButton sets data-active on itself; it wraps the Link via asChild const menuButton = dashboardLink.closest('[data-active]') expect(menuButton).toHaveAttribute('data-active', 'true') }) it('NAV-04: SidebarTrigger collapse button is rendered', () => { render(
content
) // SidebarTrigger renders with sr-only text "Toggle Sidebar" const trigger = screen.getByRole('button', { name: /toggle sidebar/i }) expect(trigger).toBeInTheDocument() }) })