import { render, screen, within } from '@testing-library/react'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import App from './App'; import { clearToken, setToken } from './lib/auth-storage'; // Stub the network layer so stub screens render without real requests. vi.mock('./lib/api', async () => { const actual = await vi.importActual('./lib/api'); return { ...actual, apiFetch: vi.fn().mockResolvedValue([]), }; }); function renderApp() { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); return render( , ); } describe('App', () => { afterEach(() => { clearToken(); }); it('shows the login screen when there is no token', () => { clearToken(); renderApp(); expect(screen.getByText('E-mailadres')).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Inloggen' })).toBeInTheDocument(); }); it('shows the tab bar when a token is present', () => { setToken('tok'); renderApp(); const tabbar = within(screen.getByRole('navigation')); expect(tabbar.getByText('Stopwatch')).toBeInTheDocument(); expect(tabbar.getByText('Geschiedenis')).toBeInTheDocument(); expect(tabbar.getByText('Account')).toBeInTheDocument(); }); it('lifecycle: unauthenticated renders Login (no nav); authenticated renders Stopwatch under the tab bar', () => { // No token -> the Login screen, and no tab bar navigation. clearToken(); const { unmount } = renderApp(); expect(screen.getByText('E-mailadres')).toBeInTheDocument(); expect(screen.queryByRole('navigation')).not.toBeInTheDocument(); unmount(); // Token present -> the Stopwatch screen is mounted at "/" beside the tab bar. setToken('tok'); renderApp(); expect(screen.getByText('Type zool')).toBeInTheDocument(); expect(within(screen.getByRole('navigation')).getByText('Stopwatch')).toBeInTheDocument(); expect(screen.queryByText('E-mailadres')).not.toBeInTheDocument(); }); });