11import { afterEach , beforeEach , describe , expect , it , vi } from 'bun:test' ;
22import type { ExecutionContext } from '@nestjs/common' ;
33import { UnauthorizedException } from '@nestjs/common' ;
4+ import { Reflector } from '@nestjs/core' ;
45import type { Request } from 'express' ;
56
67import { AuthGuard , type RequestWithAuthContext } from '../auth.guard' ;
@@ -18,6 +19,9 @@ describe('AuthGuard', () => {
1819 let mockApiKeysService : {
1920 validateKey : ReturnType < typeof vi . fn > ;
2021 } ;
22+ let mockReflector : {
23+ getAllAndOverride : ReturnType < typeof vi . fn > ;
24+ } ;
2125 let mockExecutionContext : ExecutionContext ;
2226 let mockRequest : RequestWithAuthContext ;
2327
@@ -30,11 +34,15 @@ describe('AuthGuard', () => {
3034 mockApiKeysService = {
3135 validateKey : vi . fn ( ) ,
3236 } ;
37+ mockReflector = {
38+ getAllAndOverride : vi . fn ( ) ,
39+ } ;
3340
3441 // Create guard with mocked dependencies
3542 guard = new AuthGuard (
3643 mockAuthService as unknown as AuthService ,
3744 mockApiKeysService as unknown as ApiKeysService ,
45+ mockReflector as unknown as Reflector ,
3846 ) ;
3947
4048 // Setup mock request
@@ -50,6 +58,8 @@ describe('AuthGuard', () => {
5058 switchToHttp : vi . fn ( ( ) => ( {
5159 getRequest : vi . fn ( ( ) => mockRequest ) ,
5260 } ) ) ,
61+ getHandler : vi . fn ( ) ,
62+ getClass : vi . fn ( ) ,
5363 } as unknown as ExecutionContext ;
5464 } ) ;
5565
@@ -59,6 +69,8 @@ describe('AuthGuard', () => {
5969 switchToHttp : vi . fn ( ( ) => ( {
6070 getRequest : vi . fn ( ( ) => null ) ,
6171 } ) ) ,
72+ getHandler : vi . fn ( ) ,
73+ getClass : vi . fn ( ) ,
6274 } as unknown as ExecutionContext ;
6375
6476 const result = await guard . canActivate ( contextWithoutRequest ) ;
@@ -565,5 +577,35 @@ describe('AuthGuard', () => {
565577 expect ( mockRequest . auth ?. provider ) . toBe ( 'api-key' ) ;
566578 } ) ;
567579 } ) ;
580+
581+ describe ( 'Public decorator' , ( ) => {
582+ it ( 'should allow access to endpoints marked as public' , async ( ) => {
583+ mockReflector . getAllAndOverride . mockReturnValue ( true ) ;
584+
585+ const result = await guard . canActivate ( mockExecutionContext ) ;
586+
587+ expect ( result ) . toBe ( true ) ;
588+ expect ( mockAuthService . authenticate ) . not . toHaveBeenCalled ( ) ;
589+ expect ( mockApiKeysService . validateKey ) . not . toHaveBeenCalled ( ) ;
590+ expect ( mockRequest . auth ) . toBeUndefined ( ) ;
591+ } ) ;
592+
593+ it ( 'should continue authentication for endpoints not marked as public' , async ( ) => {
594+ mockReflector . getAllAndOverride . mockReturnValue ( false ) ;
595+ mockAuthService . authenticate . mockResolvedValue ( {
596+ userId : 'user-1' ,
597+ organizationId : 'org-1' ,
598+ roles : [ 'MEMBER' ] ,
599+ isAuthenticated : true ,
600+ provider : 'clerk' ,
601+ } ) ;
602+
603+ const result = await guard . canActivate ( mockExecutionContext ) ;
604+
605+ expect ( result ) . toBe ( true ) ;
606+ expect ( mockAuthService . authenticate ) . toHaveBeenCalled ( ) ;
607+ expect ( mockRequest . auth ?. userId ) . toBe ( 'user-1' ) ;
608+ } ) ;
609+ } ) ;
568610} ) ;
569611
0 commit comments