import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { render, screen, waitFor } from '@testing-library/react'; import { MemoryRouter, Route, Routes } from 'react-router-dom'; import { ProtectedRoute } from '@/components/ProtectedRoute'; import { ToastProvider } from '@/hooks/useToast'; import { AuthProvider } from '@/hooks/useAuth'; import { setToken } from '@/api/client'; import { ToastViewport } from '@/components/Toast'; // Mock the auth API so AuthProvider hydrates without network. vi.mock('@/api/auth', () => ({ login: vi.fn(), logout: vi.fn(), fetchMe: vi.fn(), })); import { fetchMe } from '@/api/auth'; function setup() { return render( LOGIN PAGE} /> ENGAGEMENTS} /> }> ADMIN AREA} /> , ); } describe('ProtectedRoute', () => { beforeEach(() => { localStorage.clear(); vi.mocked(fetchMe).mockReset(); }); afterEach(() => { setToken(null); }); it('redirects unauthenticated users to /login', async () => { // No token → unauthenticated, no /me call. setup(); expect(await screen.findByText('LOGIN PAGE')).toBeInTheDocument(); }); it('admins reach the admin page', async () => { setToken('fake-token'); vi.mocked(fetchMe).mockResolvedValue({ id: 1, username: 'alice', role: 'admin', created_at: '2026-01-01', }); setup(); expect(await screen.findByText('ADMIN AREA')).toBeInTheDocument(); }); it('non-admins get redirected and see an access denied toast', async () => { setToken('fake-token'); vi.mocked(fetchMe).mockResolvedValue({ id: 2, username: 'bob', role: 'soc', created_at: '2026-01-01', }); setup(); expect(await screen.findByText('ENGAGEMENTS')).toBeInTheDocument(); await waitFor(() => { expect(screen.getByTestId('toast')).toHaveTextContent('Accès refusé'); }); }); });