import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { MemoryRouter } from 'react-router-dom' import { Layout } from './Layout' vi.mock('../hooks/useTheme', () => ({ useTheme: () => ({ theme: 'dark' as const, toggle: vi.fn() }), })) const mockUseAuth = vi.fn() vi.mock('../contexts/AuthContext', () => ({ useAuth: () => mockUseAuth(), })) const loggedOutAuth = { user: null, session: null, loading: false, isAdmin: false, signInWithEmail: vi.fn(), signUpWithEmail: vi.fn(), signInWithGoogle: vi.fn(), signInWithDiscord: vi.fn(), signOut: vi.fn(), } const adminAuth = { ...loggedOutAuth, user: { email: 'admin@example.com' }, session: {}, isAdmin: true, } function renderLayout(initialPath = '/') { return render( ) } describe('Layout', () => { describe('when logged out', () => { beforeEach(() => mockUseAuth.mockReturnValue(loggedOutAuth)) it('renders logged-out navigation links', () => { renderLayout() expect(screen.getAllByRole('link', { name: /^home$/i })[0]).toBeInTheDocument() expect(screen.getAllByRole('link', { name: /^runs$/i })[0]).toBeInTheDocument() expect(screen.getAllByRole('link', { name: /genlockes/i })[0]).toBeInTheDocument() expect(screen.getAllByRole('link', { name: /stats/i })[0]).toBeInTheDocument() }) it('does not show authenticated links', () => { renderLayout() expect(screen.queryByRole('link', { name: /new run/i })).not.toBeInTheDocument() expect(screen.queryByRole('link', { name: /my runs/i })).not.toBeInTheDocument() expect(screen.queryByRole('link', { name: /admin/i })).not.toBeInTheDocument() }) it('shows sign-in link', () => { renderLayout() expect(screen.getByRole('link', { name: /sign in/i })).toBeInTheDocument() }) }) describe('when logged in as admin', () => { beforeEach(() => mockUseAuth.mockReturnValue(adminAuth)) it('renders authenticated navigation links', () => { renderLayout() expect(screen.getAllByRole('link', { name: /new run/i })[0]).toBeInTheDocument() expect(screen.getAllByRole('link', { name: /my runs/i })[0]).toBeInTheDocument() expect(screen.getAllByRole('link', { name: /genlockes/i })[0]).toBeInTheDocument() expect(screen.getAllByRole('link', { name: /stats/i })[0]).toBeInTheDocument() expect(screen.getAllByRole('link', { name: /admin/i })[0]).toBeInTheDocument() }) it('shows the mobile dropdown when the hamburger is clicked', async () => { renderLayout() const hamburger = screen.getByRole('button', { name: /toggle menu/i }) await userEvent.click(hamburger) expect(screen.getAllByRole('link', { name: /my runs/i }).length).toBeGreaterThan(1) }) }) it('renders the brand logo link', () => { mockUseAuth.mockReturnValue(loggedOutAuth) renderLayout() expect(screen.getByRole('link', { name: /ant/i })).toBeInTheDocument() }) it('renders the theme toggle button', () => { mockUseAuth.mockReturnValue(loggedOutAuth) renderLayout() expect(screen.getAllByRole('button', { name: /switch to light mode/i })[0]).toBeInTheDocument() }) it('initially hides the mobile dropdown menu', () => { mockUseAuth.mockReturnValue(loggedOutAuth) renderLayout() expect(screen.getByRole('button', { name: /toggle menu/i })).toBeInTheDocument() }) it('renders the footer with PokeDB attribution', () => { mockUseAuth.mockReturnValue(loggedOutAuth) renderLayout() expect(screen.getByRole('link', { name: /pokedb/i })).toBeInTheDocument() }) })