// File: frontend/components/auth/__tests__/auth-sync.test.tsx // Change Log: // - 2026-06-13: Initial creation - test coverage for AuthSync component // - 2026-06-13: Refactor to use static ESM imports instead of CommonJS require() to resolve Vitest module path errors import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, renderHook } from '@testing-library/react'; import { AuthSync } from '../auth-sync'; import { useSession, signOut } from 'next-auth/react'; import { useAuthStore } from '@/lib/stores/auth-store'; import { clearAuthTokenCache } from '@/lib/api/client'; // Mock next-auth vi.mock('next-auth/react', () => ({ useSession: vi.fn(), signOut: vi.fn(), })); // Mock auth-store vi.mock('@/lib/stores/auth-store', () => ({ useAuthStore: vi.fn(), })); // Mock clearAuthTokenCache vi.mock('@/lib/api/client', () => ({ clearAuthTokenCache: vi.fn(), })); describe('AuthSync', () => { beforeEach(() => { vi.clearAllMocks(); }); it('should render null (component renders nothing)', () => { vi.mocked(useSession).mockReturnValue({ data: null, status: 'unauthenticated', } as any); vi.mocked(useAuthStore).mockReturnValue({ setAuth: vi.fn(), logout: vi.fn(), } as any); const { container } = render(); expect(container.firstChild).toBeNull(); }); it('should sync user data when authenticated', () => { const mockSetAuth = vi.fn(); const mockLogout = vi.fn(); vi.mocked(useSession).mockReturnValue({ data: { user: { id: 'user-id-1', publicId: '019505a1-7c3e-7000-8000-abc123def456', username: 'testuser', email: 'test@example.com', firstName: 'Test', lastName: 'User', role: 'Admin', permissions: ['read', 'write'], }, accessToken: 'test-token', }, status: 'authenticated', } as any); vi.mocked(useAuthStore).mockReturnValue({ setAuth: mockSetAuth, logout: mockLogout, } as any); render(); expect(mockSetAuth).toHaveBeenCalledWith( { id: 'user-id-1', publicId: '019505a1-7c3e-7000-8000-abc123def456', username: 'testuser', email: 'test@example.com', firstName: 'Test', lastName: 'User', role: 'Admin', permissions: ['read', 'write'], }, 'test-token' ); }); it('should handle user_id fallback when id is missing', () => { const mockSetAuth = vi.fn(); const mockLogout = vi.fn(); vi.mocked(useSession).mockReturnValue({ data: { user: { user_id: 'user-id-2', publicId: '019505a1-7c3e-7000-8000-abc123def457', username: 'testuser2', email: 'test2@example.com', firstName: 'Test2', lastName: 'User2', role: 'User', }, accessToken: 'test-token-2', }, status: 'authenticated', } as any); vi.mocked(useAuthStore).mockReturnValue({ setAuth: mockSetAuth, logout: mockLogout, } as any); render(); expect(mockSetAuth).toHaveBeenCalledWith( expect.objectContaining({ id: 'user-id-2', }), 'test-token-2' ); }); it('should clear auth cache and logout on unauthenticated', () => { const mockSetAuth = vi.fn(); const mockLogout = vi.fn(); vi.mocked(useSession).mockReturnValue({ data: null, status: 'unauthenticated', } as any); vi.mocked(useAuthStore).mockReturnValue({ setAuth: mockSetAuth, logout: mockLogout, } as any); render(); expect(clearAuthTokenCache).toHaveBeenCalled(); expect(mockLogout).toHaveBeenCalled(); }); it('should clear auth cache and sign out on RefreshAccessTokenError', () => { const mockSetAuth = vi.fn(); const mockLogout = vi.fn(); vi.mocked(useSession).mockReturnValue({ data: { error: 'RefreshAccessTokenError', }, status: 'authenticated', } as any); vi.mocked(useAuthStore).mockReturnValue({ setAuth: mockSetAuth, logout: mockLogout, } as any); render(); expect(clearAuthTokenCache).toHaveBeenCalled(); expect(signOut).toHaveBeenCalledWith({ callbackUrl: '/login' }); }); it('should use default values when user fields are missing', () => { const mockSetAuth = vi.fn(); const mockLogout = vi.fn(); vi.mocked(useSession).mockReturnValue({ data: { user: { publicId: '019505a1-7c3e-7000-8000-abc123def458', }, accessToken: 'test-token-3', }, status: 'authenticated', } as any); vi.mocked(useAuthStore).mockReturnValue({ setAuth: mockSetAuth, logout: mockLogout, } as any); render(); expect(mockSetAuth).toHaveBeenCalledWith( expect.objectContaining({ id: '', username: '', email: '', firstName: '', lastName: '', role: 'User', }), 'test-token-3' ); }); it('should use session.user fields when typed user fields are missing', () => { const mockSetAuth = vi.fn(); const mockLogout = vi.fn(); vi.mocked(useSession).mockReturnValue({ data: { user: { publicId: '019505a1-7c3e-7000-8000-abc123def459', username: 'session-username', email: 'session-email@example.com', firstName: 'SessionFirst', lastName: 'SessionLast', role: 'SessionRole', }, accessToken: 'test-token-4', }, status: 'authenticated', } as any); vi.mocked(useAuthStore).mockReturnValue({ setAuth: mockSetAuth, logout: mockLogout, } as any); render(); expect(mockSetAuth).toHaveBeenCalledWith( expect.objectContaining({ username: 'session-username', email: 'session-email@example.com', firstName: 'SessionFirst', lastName: 'SessionLast', role: 'SessionRole', }), 'test-token-4' ); }); });