import { describe, it, expect, vi, beforeEach } from 'vitest'; import { renderHook } from '@testing-library/react'; const { mockUseSession, mockUseSWR, mockApiClient } = vi.hoisted(() => ({ mockUseSession: vi.fn(), mockUseSWR: vi.fn(), mockApiClient: { _accessToken: null as string | null, set accessToken(token: string) { this._accessToken = token; }, get hasToken() { return this._accessToken !== null; }, }, })); vi.mock('next-auth/react', () => ({ useSession: mockUseSession, })); vi.mock('swr', () => ({ default: mockUseSWR, })); vi.mock('@/services/api-client', () => ({ apiClient: mockApiClient, })); import { useApi } from '../../src/lib/useApi'; beforeEach(() => { vi.clearAllMocks(); mockApiClient._accessToken = null; }); describe('useApi', () => { it('returns loading state when session is loading', () => { mockUseSession.mockReturnValue({ data: null, status: 'loading' }); mockUseSWR.mockReturnValue({ data: undefined, mutate: vi.fn(), isLoading: false }); const { result } = renderHook(() => useApi()); expect(result.current.isLoading).toBe(true); expect(result.current.isAuthenticated).toBe(false); expect(result.current.householdId).toBeNull(); }); it('returns unauthenticated state', () => { mockUseSession.mockReturnValue({ data: null, status: 'unauthenticated' }); mockUseSWR.mockReturnValue({ data: undefined, mutate: vi.fn(), isLoading: false }); const { result } = renderHook(() => useApi()); expect(result.current.isAuthenticated).toBe(false); expect(result.current.isLoading).toBe(false); }); it('sets token on apiClient when session has accessToken', () => { mockUseSession.mockReturnValue({ data: { accessToken: 'test-jwt' }, status: 'authenticated', }); mockUseSWR.mockReturnValue({ data: { householdIds: ['hh1'], displayName: 'Test' }, mutate: vi.fn(), isLoading: false, }); renderHook(() => useApi()); expect(mockApiClient._accessToken).toBe('test-jwt'); }); it('returns householdId from profile', () => { mockUseSession.mockReturnValue({ data: { accessToken: 'test-jwt' }, status: 'authenticated', }); mockUseSWR.mockReturnValue({ data: { householdIds: ['hh1', 'hh2'], displayName: 'Test' }, mutate: vi.fn(), isLoading: false, }); const { result } = renderHook(() => useApi()); expect(result.current.householdId).toBe('hh1'); expect(result.current.householdIds).toEqual(['hh1', 'hh2']); expect(result.current.isAuthenticated).toBe(true); }); it('returns null householdId when profile has no households', () => { mockUseSession.mockReturnValue({ data: { accessToken: 'test-jwt' }, status: 'authenticated', }); mockUseSWR.mockReturnValue({ data: { householdIds: [] }, mutate: vi.fn(), isLoading: false, }); const { result } = renderHook(() => useApi()); expect(result.current.householdId).toBeNull(); }); it('returns loading when authenticated but profile is still loading', () => { mockUseSession.mockReturnValue({ data: { accessToken: 'test-jwt' }, status: 'authenticated', }); mockUseSWR.mockReturnValue({ data: undefined, mutate: vi.fn(), isLoading: true, }); const { result } = renderHook(() => useApi()); expect(result.current.isLoading).toBe(true); }); it('provides refreshProfile function from SWR mutate', () => { const mutateFn = vi.fn(); mockUseSession.mockReturnValue({ data: { accessToken: 'test-jwt' }, status: 'authenticated', }); mockUseSWR.mockReturnValue({ data: { householdIds: ['hh1'] }, mutate: mutateFn, isLoading: false, }); const { result } = renderHook(() => useApi()); expect(result.current.refreshProfile).toBe(mutateFn); }); });