/** * Tests for AppSidebar (M5-T01, updated M5-T06). * * Strategy: render AppSidebar inside a minimal AppShell (required by * AppShell.Navbar) + MemoryRouter so useLocation() works. * * Coverage: * 1. All four nav items render (Home, Records, Energy, Config). * 2. Home nav item is active when pathname is '/'. * 3. Records nav item is active when pathname is '/records'. * 4. Config nav item is active when pathname is '/config'. * 5. Home is NOT active when on '/records'. * 6. Energy nav item is active when on '/energy'. */ import { describe, it, expect, vi } from 'vitest' import { screen } from '@testing-library/react' import { render } from '@testing-library/react' import { MantineProvider, AppShell } from '@mantine/core' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { MemoryRouter } from 'react-router-dom' import { AppSidebar } from './AppSidebar' // --------------------------------------------------------------------------- // Mock apiClient (LogoutButton calls POST /api/auth/logout) // --------------------------------------------------------------------------- vi.mock('../api/client', () => ({ default: { POST: vi.fn(), GET: vi.fn(), }, ApiError: class ApiError extends Error { status: number body: unknown constructor(status: number, body: unknown) { super(`API error ${status}`) this.name = 'ApiError' this.status = status this.body = body } }, registerLoginRedirect: vi.fn(), })) // --------------------------------------------------------------------------- // Helper: render AppSidebar inside the required AppShell + router providers // --------------------------------------------------------------------------- function renderSidebar(initialPath = '/') { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false } }, }) return render( , ) } // --------------------------------------------------------------------------- // Tests // --------------------------------------------------------------------------- describe('AppSidebar', () => { // ------------------------------------------------------------------------- // 1. All nav items render // ------------------------------------------------------------------------- it('renders Home, Records, Energy, and Config nav items', () => { renderSidebar('/') expect(screen.getByTestId('nav-home')).toBeInTheDocument() expect(screen.getByTestId('nav-records')).toBeInTheDocument() expect(screen.getByTestId('nav-energy')).toBeInTheDocument() expect(screen.getByTestId('nav-config')).toBeInTheDocument() }) // ------------------------------------------------------------------------- // 2. Home active on '/' // ------------------------------------------------------------------------- it('marks Home nav item as active when on "/"', () => { renderSidebar('/') // Mantine NavLink sets data-active="true" on the active item const homeLink = screen.getByTestId('nav-home') expect(homeLink).toHaveAttribute('data-active', 'true') }) // ------------------------------------------------------------------------- // 3. Records active on '/records' // ------------------------------------------------------------------------- it('marks Records nav item as active when on "/records"', () => { renderSidebar('/records') const recordsLink = screen.getByTestId('nav-records') expect(recordsLink).toHaveAttribute('data-active', 'true') }) // ------------------------------------------------------------------------- // 4. Config active on '/config' // ------------------------------------------------------------------------- it('marks Config nav item as active when on "/config"', () => { renderSidebar('/config') const configLink = screen.getByTestId('nav-config') expect(configLink).toHaveAttribute('data-active', 'true') }) // ------------------------------------------------------------------------- // 5. Home NOT active on '/records' (exact match guard) // ------------------------------------------------------------------------- it('does NOT mark Home as active when on "/records"', () => { renderSidebar('/records') const homeLink = screen.getByTestId('nav-home') expect(homeLink).not.toHaveAttribute('data-active', 'true') }) // ------------------------------------------------------------------------- // 6. Energy active on '/energy' // ------------------------------------------------------------------------- it('marks Energy nav item as active when on "/energy"', () => { renderSidebar('/energy') const energyLink = screen.getByTestId('nav-energy') expect(energyLink).toHaveAttribute('data-active', 'true') }) })