import { RegisterCandidateData } from '../auth'; // Mock fetch globally const mockFetch = jest.fn(); global.fetch = mockFetch; // Mock localStorage const localStorageMock = { getItem: jest.fn(), setItem: jest.fn(), removeItem: jest.fn(), clear: jest.fn(), }; Object.defineProperty(window, 'localStorage', { value: localStorageMock }); // Mock config module to avoid initConfig fetching jest.mock('../config', () => ({ getApiUrl: jest.fn().mockReturnValue('http://test-api.com'), initConfig: jest.fn().mockResolvedValue({}), getConfig: jest.fn().mockReturnValue({}), })); describe('Auth Module', () => { let authModule: typeof import('../auth'); beforeEach(() => { jest.resetModules(); mockFetch.mockReset(); localStorageMock.getItem.mockReset(); localStorageMock.setItem.mockReset(); localStorageMock.removeItem.mockReset(); // Re-import the module fresh authModule = require('../auth'); }); describe('registerCandidate', () => { const validData: RegisterCandidateData = { name: 'John Doe', email: 'john@example.com', password: 'password123', username: 'johndoe', phone: '+5511999999999', }; it('should register candidate successfully', async () => { const mockResponse = { token: 'mock-jwt-token', user: { id: '123', name: 'John Doe', email: 'john@example.com', roles: ['CANDIDATE'], }, }; mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockResponse, }); await expect(authModule.registerCandidate(validData)).resolves.not.toThrow(); expect(mockFetch).toHaveBeenCalledWith( expect.stringContaining('/auth/register'), expect.objectContaining({ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(validData), }) ); }); it('should throw error when email already exists', async () => { const errorResponse = { message: 'email already registered' }; mockFetch.mockResolvedValueOnce({ ok: false, status: 409, json: async () => errorResponse, }); await expect(authModule.registerCandidate(validData)).rejects.toThrow( 'email already registered' ); }); it('should throw error with status code when no message provided', async () => { mockFetch.mockResolvedValueOnce({ ok: false, status: 500, json: async () => ({}), }); await expect(authModule.registerCandidate(validData)).rejects.toThrow( 'Erro no registro: 500' ); }); it('should handle network errors gracefully', async () => { mockFetch.mockRejectedValueOnce(new Error('Network error')); await expect(authModule.registerCandidate(validData)).rejects.toThrow( 'Network error' ); }); it('should send all required fields in request body', async () => { mockFetch.mockResolvedValueOnce({ ok: true, json: async () => ({}), }); await authModule.registerCandidate(validData); const callArgs = mockFetch.mock.calls[0]; const body = JSON.parse(callArgs[1].body); expect(body).toEqual({ name: 'John Doe', email: 'john@example.com', password: 'password123', username: 'johndoe', phone: '+5511999999999', }); }); }); describe('login', () => { it('should login and store user in localStorage', async () => { const mockResponse = { token: 'mock-jwt-token', user: { id: '123', name: 'Test User', email: 'test@example.com', roles: ['CANDIDATE'], status: 'active', created_at: '2023-01-01T00:00:00Z', }, }; mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockResponse, }); const user = await authModule.login('test@example.com', 'password123'); expect(user).toBeDefined(); expect(user?.email).toBe('test@example.com'); expect(localStorageMock.setItem).toHaveBeenCalledWith( 'job-portal-auth', expect.any(String) ); // Token is in cookie, not in storage expect(localStorageMock.setItem).not.toHaveBeenCalledWith( 'auth_token', expect.any(String) ); }); it('should throw error on invalid credentials', async () => { mockFetch.mockResolvedValueOnce({ ok: false, status: 401, }); await expect( authModule.login('test@example.com', 'wrongpassword') ).rejects.toThrow('Credenciais inválidas'); }); }); describe('logout', () => { it('should remove auth data from localStorage', () => { authModule.logout(); expect(localStorageMock.removeItem).toHaveBeenCalledWith('job-portal-auth'); }); }); describe('refreshSession', () => { it('should restore user from /users/me endpoint', async () => { mockFetch.mockResolvedValueOnce({ ok: true, json: async () => ({ id: '123', name: 'Test User', email: 'test@example.com', roles: ['candidate'], }), }); const user = await authModule.refreshSession(); expect(user).toBeDefined(); expect(user?.email).toBe('test@example.com'); expect(localStorageMock.setItem).toHaveBeenCalled(); }); it('should clear storage on 401', async () => { mockFetch.mockResolvedValueOnce({ ok: false, status: 401 }); const user = await authModule.refreshSession(); expect(user).toBeNull(); expect(localStorageMock.removeItem).toHaveBeenCalledWith('job-portal-auth'); }); it('should return null on network error', async () => { mockFetch.mockRejectedValueOnce(new Error('Network error')); const user = await authModule.refreshSession(); expect(user).toBeNull(); }); }); describe('getCurrentUser', () => { it('should return user from localStorage', () => { const storedUser = { id: '123', name: 'Test', email: 'test@test.com', role: 'candidate' }; localStorageMock.getItem.mockReturnValueOnce(JSON.stringify(storedUser)); const user = authModule.getCurrentUser(); expect(user).toEqual(storedUser); }); it('should return null when no user stored', () => { localStorageMock.getItem.mockReturnValueOnce(null); const user = authModule.getCurrentUser(); expect(user).toBeNull(); }); }); describe('isAdminUser', () => { it('should return true for admin role', () => { const adminUser = { id: '1', name: 'Admin', email: 'a@a.com', role: 'admin' as const, roles: ['admin'] }; expect(authModule.isAdminUser(adminUser)).toBe(true); }); it('should return true for SUPERADMIN in roles array', () => { const superAdmin = { id: '1', name: 'Super', email: 's@s.com', role: 'candidate' as const, roles: ['SUPERADMIN'] }; expect(authModule.isAdminUser(superAdmin)).toBe(true); }); it('should return false for regular candidate', () => { const candidate = { id: '1', name: 'User', email: 'u@u.com', role: 'candidate' as const, roles: ['CANDIDATE'] }; expect(authModule.isAdminUser(candidate)).toBe(false); }); it('should return false for null user', () => { expect(authModule.isAdminUser(null)).toBe(false); }); }); });