import { ForbiddenException, UnauthorizedException } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { describe, expect, it, vi } from 'vitest'; import { AuthorizationGuard } from './AuthorizationGuard'; import { Public } from './Public'; import { RequireRoles } from './RequireRoles'; class DummyController { @Public() publicHandler(): void {} protectedHandler(): void {} @RequireRoles('admin') adminHandler(): void {} } function createExecutionContext(options: { handler: Function; userId?: string }) { const request = options.userId ? { user: { userId: options.userId } } : {}; return { getHandler: () => options.handler, getClass: () => DummyController, switchToHttp: () => ({ getRequest: () => request, }), }; } describe('AuthorizationGuard', () => { it('allows public routes without a user session', () => { const authorizationService = { getRolesForUser: vi.fn() }; const guard = new AuthorizationGuard(new Reflector(), authorizationService as any); const ctx = createExecutionContext({ handler: DummyController.prototype.publicHandler, }); expect(guard.canActivate(ctx as any)).toBe(true); expect(authorizationService.getRolesForUser).not.toHaveBeenCalled(); }); it('denies non-public routes by default when not authenticated', () => { const authorizationService = { getRolesForUser: vi.fn() }; const guard = new AuthorizationGuard(new Reflector(), authorizationService as any); const ctx = createExecutionContext({ handler: DummyController.prototype.protectedHandler, }); expect(() => guard.canActivate(ctx as any)).toThrow(UnauthorizedException); }); it('allows non-public routes when authenticated', () => { const authorizationService = { getRolesForUser: vi.fn().mockReturnValue([]) }; const guard = new AuthorizationGuard(new Reflector(), authorizationService as any); const ctx = createExecutionContext({ handler: DummyController.prototype.protectedHandler, userId: 'user-1', }); expect(guard.canActivate(ctx as any)).toBe(true); }); it('denies routes requiring roles when user does not have any required role', () => { const authorizationService = { getRolesForUser: vi.fn().mockReturnValue(['user']) }; const guard = new AuthorizationGuard(new Reflector(), authorizationService as any); const ctx = createExecutionContext({ handler: DummyController.prototype.adminHandler, userId: 'user-1', }); expect(() => guard.canActivate(ctx as any)).toThrow(ForbiddenException); }); it('allows routes requiring roles when user has a required role', () => { const authorizationService = { getRolesForUser: vi.fn().mockReturnValue(['admin']) }; const guard = new AuthorizationGuard(new Reflector(), authorizationService as any); const ctx = createExecutionContext({ handler: DummyController.prototype.adminHandler, userId: 'user-1', }); expect(guard.canActivate(ctx as any)).toBe(true); }); });