import { act, render, screen, waitFor } from '@testing-library/react'; import { AuthProvider, useAuth } from './auth-context'; function Probe() { const { admin, loading, error, logout } = useAuth(); return (
{String(loading)}
{admin?.email ?? 'null'}
{error ?? 'null'}
); } let fetchSpy: jest.SpyInstance; beforeEach(() => { fetchSpy = jest.spyOn(global, 'fetch'); }); afterEach(() => { jest.restoreAllMocks(); }); describe('AuthProvider', () => { it('exposes a loading state then sets admin from /api/auth/me', async () => { fetchSpy.mockResolvedValue( new Response(JSON.stringify({ admin: { id: 'a-1', email: 'me@x.com', role: 'OWNER', tenantId: 't1', tenantSlug: 'default', tenantName: 'Default' } }), { status: 200, headers: { 'Content-Type': 'application/json' }, }), ); render( , ); await waitFor(() => expect(screen.getByTestId('admin')).toHaveTextContent('me@x.com')); expect(screen.getByTestId('loading')).toHaveTextContent('false'); }); it('sets admin to null on 401', async () => { fetchSpy.mockResolvedValue( new Response(JSON.stringify({ message: 'Unauthorized' }), { status: 401, headers: { 'Content-Type': 'application/json' }, }), ); render( , ); await waitFor(() => expect(screen.getByTestId('admin')).toHaveTextContent('null')); }); it('calls POST /api/auth/logout when logout is invoked', async () => { fetchSpy .mockResolvedValueOnce( new Response(JSON.stringify({ admin: { id: 'a-1', email: 'me@x.com' } }), { status: 200, headers: { 'Content-Type': 'application/json' }, }), ) .mockResolvedValueOnce(new Response(null, { status: 204 })); render( , ); await waitFor(() => expect(screen.getByTestId('admin')).toHaveTextContent('me@x.com')); await act(async () => { screen.getByText('logout').click(); }); await waitFor(() => expect(fetchSpy).toHaveBeenCalledWith('/api/auth/logout', expect.objectContaining({ method: 'POST' }))); expect(screen.getByTestId('admin')).toHaveTextContent('null'); }); });