import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; /** * Unit tests for the roles API module. * * Tests getMyRoles(), switchRole(), and updateUserRoles() which all rely on * authenticatedFetch from $lib/auth and getApiBaseUrl from $lib/api. */ // Mock $lib/api vi.mock('$lib/api', () => ({ getApiBaseUrl: () => 'http://test.classeo.local:18000/api' })); // Mock $lib/auth - authenticatedFetch is the primary dependency const mockAuthenticatedFetch = vi.fn(); vi.mock('$lib/auth', () => ({ authenticatedFetch: (...args: unknown[]) => mockAuthenticatedFetch(...args) })); import { getMyRoles, switchRole, updateUserRoles } from '$lib/features/roles/api/roles'; describe('roles API', () => { beforeEach(() => { vi.clearAllMocks(); }); afterEach(() => { vi.restoreAllMocks(); }); // ========================================================================== // getMyRoles // ========================================================================== describe('getMyRoles', () => { it('should return roles array and activeRole on success', async () => { const mockResponse = { roles: [ { value: 'ROLE_ADMIN', label: 'Administrateur' }, { value: 'ROLE_TEACHER', label: 'Enseignant' } ], activeRole: 'ROLE_ADMIN', activeRoleLabel: 'Administrateur' }; mockAuthenticatedFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve(mockResponse) }); const result = await getMyRoles(); expect(mockAuthenticatedFetch).toHaveBeenCalledWith( 'http://test.classeo.local:18000/api/me/roles' ); expect(result.roles).toHaveLength(2); expect(result.roles[0]).toEqual({ value: 'ROLE_ADMIN', label: 'Administrateur' }); expect(result.activeRole).toBe('ROLE_ADMIN'); expect(result.activeRoleLabel).toBe('Administrateur'); }); it('should throw Error when the API response is not ok', async () => { mockAuthenticatedFetch.mockResolvedValueOnce({ ok: false, status: 500 }); await expect(getMyRoles()).rejects.toThrow('Failed to fetch roles'); }); }); // ========================================================================== // switchRole // ========================================================================== describe('switchRole', () => { it('should return new activeRole on success', async () => { const mockResponse = { activeRole: 'ROLE_TEACHER', activeRoleLabel: 'Enseignant' }; mockAuthenticatedFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve(mockResponse) }); const result = await switchRole('ROLE_TEACHER'); expect(mockAuthenticatedFetch).toHaveBeenCalledWith( 'http://test.classeo.local:18000/api/me/switch-role', expect.objectContaining({ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ role: 'ROLE_TEACHER' }) }) ); expect(result.activeRole).toBe('ROLE_TEACHER'); expect(result.activeRoleLabel).toBe('Enseignant'); }); it('should throw Error when the API response is not ok', async () => { mockAuthenticatedFetch.mockResolvedValueOnce({ ok: false, status: 400 }); await expect(switchRole('ROLE_INVALID')).rejects.toThrow('Failed to switch role'); }); }); // ========================================================================== // updateUserRoles // ========================================================================== describe('updateUserRoles', () => { it('should complete without error on 2xx success', async () => { mockAuthenticatedFetch.mockResolvedValueOnce({ ok: true, status: 204 }); // Should resolve without throwing await expect( updateUserRoles('user-uuid-123', ['ROLE_ADMIN', 'ROLE_TEACHER']) ).resolves.toBeUndefined(); expect(mockAuthenticatedFetch).toHaveBeenCalledWith( 'http://test.classeo.local:18000/api/users/user-uuid-123/roles', expect.objectContaining({ method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ roles: ['ROLE_ADMIN', 'ROLE_TEACHER'] }) }) ); }); it('should throw with hydra:description when present in error response', async () => { mockAuthenticatedFetch.mockResolvedValueOnce({ ok: false, status: 422, json: () => Promise.resolve({ 'hydra:description': 'Le rôle ROLE_INVALID est inconnu.' }) }); await expect( updateUserRoles('user-uuid-123', ['ROLE_INVALID']) ).rejects.toThrow('Le rôle ROLE_INVALID est inconnu.'); }); it('should throw with detail when present in error response', async () => { mockAuthenticatedFetch.mockResolvedValueOnce({ ok: false, status: 403, json: () => Promise.resolve({ detail: 'Accès refusé.' }) }); await expect( updateUserRoles('user-uuid-123', ['ROLE_ADMIN']) ).rejects.toThrow('Accès refusé.'); }); it('should throw generic message when error body is not valid JSON', async () => { mockAuthenticatedFetch.mockResolvedValueOnce({ ok: false, status: 500, json: () => Promise.reject(new Error('Unexpected token')) }); await expect( updateUserRoles('user-uuid-123', ['ROLE_ADMIN']) ).rejects.toThrow('Erreur lors de la mise à jour des rôles (500)'); }); }); });