Angular 16 test guard DI Function

159 Views Asked by At

I have a guard that tests if the user is logged in or not and check his user context

export function authenticationGuard(userContext: UserContextService): CanActivateFn {
  return async (_next: ActivatedRouteSnapshot, state: RouterStateSnapshot) =>  {
    const userService: UserService = inject(UserService);
    const router: Router = inject(Router);
    const cognitoService: CognitoService = inject(CognitoService);

    if(await cognitoService.currentAuthenticatedUser()){
      if(userContext.getUserInfos() === undefined || userContext.getUserInfos() === null || Object.keys(userContext.getUserInfos()).length === 0){
        const userInfo$ = userService.getCurrentUserInfos();
        userContext.setUserInfos(await lastValueFrom(userInfo$));
      }

      return true;
    }else{
      localStorage.setItem('redirect', JSON.stringify(state.url));
      router.navigate(['authentification']);
      return false;
    }
  };
}

I Write unit test :

describe('authenticationGuard', () => {
    let cognitoServiceSpy: jasmine.SpyObj<CognitoService>;
    let userContextServiceSpy: jasmine.SpyObj<UserContextService>;
    let userServiceSpy: jasmine.SpyObj<UserService>;
    let activatedRoute: jasmine.SpyObj<ActivatedRoute>;
    let routerState: jasmine.SpyObj<RouterState>;

    let mockRouter = {
        navigate: jasmine.createSpy('navigate')
    };

    beforeEach(() => {
        cognitoServiceSpy = jasmine.createSpyObj('CognitoService', ['currentAuthenticatedUser']);
        userServiceSpy = jasmine.createSpyObj('UserService', ['getCurrentUserInfos']);
        userContextServiceSpy = jasmine.createSpyObj('UserContextService', ['getUserInfos', 'setUserInfos']);
        activatedRoute = jasmine.createSpyObj('ActivatedRoute', [], {'snapshot': {}});
        routerState = jasmine.createSpyObj('RouterState', [], {'snapshot': {}});

        TestBed.configureTestingModule({
            imports: [RouterTestingModule],
            providers: [
                { provide: CognitoService, useValue: cognitoServiceSpy },
                { provide: UserService, useValue: userServiceSpy },
                { provide: UserContextService, useValue: userContextServiceSpy },
                { provide: Router, useValue: mockRouter },
                { provide: ActivatedRoute, useValue: activatedRoute },
                { provide: RouterState, useValue: routerState }
            ]
        });
    });

  
    it('should be created', fakeAsync(() => {
        cognitoServiceSpy.currentAuthenticatedUser.and.resolveTo(false);


        const executeGuard: any = TestBed.runInInjectionContext(() => {
            return authenticationGuard(userContextServiceSpy);
        });

        tick();

        expect(mockRouter.navigate).toHaveBeenCalled();
        expect(executeGuard).toBeFalse();
    }));
});  

The result is Expected Function to be false.

I don't understand the problem.

How to test my guard. I want the to abocrd test the case when the user is not logged in

1

There are 1 best solutions below

3
Matthieu Riegler On

Your guard is async, it's effectivly returning a Promise<boolean>, not a promise.

it('should be created', (async() => {
    cognitoServiceSpy.currentAuthenticatedUser.and.resolveTo(false);


    const executeGuard = await TestBed.runInInjectionContext(() => {
        return authenticationGuard(userContextServiceSpy);
    });

    expect(mockRouter.navigate).toHaveBeenCalled();
    expect(executeGuard).toBeFalse();
}));

Also, your should be returning a UrlTree instead of navigating + returning false :

So

router.navigate(['authentification']);
return false;

should be replaced by

return router.createUrlTree(['/authentification']);