From 852c7ecefffc5b2a08b559a7e755290405f1b6cf Mon Sep 17 00:00:00 2001 From: Felipe Cardoso Date: Mon, 3 Nov 2025 14:27:25 +0100 Subject: [PATCH] Migrate auth hooks to `AuthContext` and update tests for compatibility - Refactored `useIsAuthenticated` and `useCurrentUser` to use `useAuth` from `AuthContext` instead of `useAuthStore`. - Updated test setups to inject `AuthProvider` with mocked store hooks for improved test isolation and consistency. - Replaced legacy `useAuthStore` mocks with `AuthContext`-compatible implementations in affected tests. --- frontend/src/lib/api/hooks/useAuth.ts | 5 +-- .../settings/profile/page.test.tsx | 32 ++++++++++++++++- frontend/tests/lib/api/hooks/useAuth.test.tsx | 35 ++++++++++--------- 3 files changed, 53 insertions(+), 19 deletions(-) diff --git a/frontend/src/lib/api/hooks/useAuth.ts b/frontend/src/lib/api/hooks/useAuth.ts index ca20b36..054e8ec 100755 --- a/frontend/src/lib/api/hooks/useAuth.ts +++ b/frontend/src/lib/api/hooks/useAuth.ts @@ -22,6 +22,7 @@ import { } from '../client'; import { useAuthStore } from '@/lib/stores/authStore'; import type { User } from '@/lib/stores/authStore'; +import { useAuth } from '@/lib/auth/AuthContext'; import { parseAPIError, getGeneralError } from '../errors'; import { isTokenWithUser } from '../types'; import config from '@/config/app.config'; @@ -481,7 +482,7 @@ export function usePasswordChange(onSuccess?: (message: string) => void) { * @returns boolean indicating authentication status */ export function useIsAuthenticated(): boolean { - return useAuthStore((state) => state.isAuthenticated); + return useAuth((state) => state.isAuthenticated); } /** @@ -489,7 +490,7 @@ export function useIsAuthenticated(): boolean { * @returns Current user or null */ export function useCurrentUser(): User | null { - return useAuthStore((state) => state.user); + return useAuth((state) => state.user); } /** diff --git a/frontend/tests/app/(authenticated)/settings/profile/page.test.tsx b/frontend/tests/app/(authenticated)/settings/profile/page.test.tsx index 7077f2d..729842a 100644 --- a/frontend/tests/app/(authenticated)/settings/profile/page.test.tsx +++ b/frontend/tests/app/(authenticated)/settings/profile/page.test.tsx @@ -6,12 +6,40 @@ import { render, screen } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import ProfileSettingsPage from '@/app/(authenticated)/settings/profile/page'; +import { AuthProvider } from '@/lib/auth/AuthContext'; import { useAuthStore } from '@/lib/stores/authStore'; // Mock authStore jest.mock('@/lib/stores/authStore'); const mockUseAuthStore = useAuthStore as jest.MockedFunction; +// Mock store hook for AuthProvider +const mockStoreHook = ((selector?: (state: any) => any) => { + const state = { + isAuthenticated: true, + user: { + id: '1', + email: 'test@example.com', + first_name: 'Test', + last_name: 'User', + is_active: true, + is_superuser: false, + created_at: '2024-01-01T00:00:00Z', + }, + accessToken: 'token', + refreshToken: 'refresh', + isLoading: false, + tokenExpiresAt: null, + setAuth: jest.fn(), + setTokens: jest.fn(), + setUser: jest.fn(), + clearAuth: jest.fn(), + loadAuthFromStorage: jest.fn(), + isTokenExpired: jest.fn(() => false), + }; + return selector ? selector(state) : state; +}) as any; + describe('ProfileSettingsPage', () => { const queryClient = new QueryClient({ defaultOptions: { @@ -44,7 +72,9 @@ describe('ProfileSettingsPage', () => { const renderWithProvider = (component: React.ReactElement) => { return render( - {component} + + {component} + ); }; diff --git a/frontend/tests/lib/api/hooks/useAuth.test.tsx b/frontend/tests/lib/api/hooks/useAuth.test.tsx index 93360b5..4113bf0 100644 --- a/frontend/tests/lib/api/hooks/useAuth.test.tsx +++ b/frontend/tests/lib/api/hooks/useAuth.test.tsx @@ -11,28 +11,29 @@ import { useCurrentUser, useIsAdmin, } from '@/lib/api/hooks/useAuth'; +import { AuthProvider } from '@/lib/auth/AuthContext'; -// Mock auth store -let mockAuthState: { - isAuthenticated: boolean; - user: any; - accessToken: string | null; - refreshToken: string | null; -} = { +// Mock auth state (Context-injected) +let mockAuthState: any = { isAuthenticated: false, user: null, accessToken: null, refreshToken: null, + isLoading: false, + tokenExpiresAt: null, + // Action stubs (unused in these tests) + setAuth: jest.fn(), + setTokens: jest.fn(), + setUser: jest.fn(), + clearAuth: jest.fn(), + loadAuthFromStorage: jest.fn(), + isTokenExpired: jest.fn(() => false), }; -jest.mock('@/lib/stores/authStore', () => ({ - useAuthStore: (selector?: (state: any) => any) => { - if (selector) { - return selector(mockAuthState); - } - return mockAuthState; - }, -})); +// Mock store hook compatible with AuthContext (Zustand-like hook) +const mockStoreHook = ((selector?: (state: any) => any) => { + return selector ? selector(mockAuthState) : mockAuthState; +}) as any; // Mock router jest.mock('next/navigation', () => ({ @@ -51,7 +52,9 @@ const createWrapper = () => { return ({ children }: { children: React.ReactNode }) => ( - {children} + + {children} + ); };