Hello since the class guards are deprecated, I moved mine to a functional, but my test broke and I'm really confused of the injectable service of keycloak and the parameters of the guard.
Here is the Guard:
export const authGuard: CanActivateFn = async (
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Promise<boolean> => {
const keycloak = inject(KeycloakService);
const isLogged = await keycloak.isLoggedIn();
if (!isLogged) {
await keycloak.login({
redirectUri: window.location.origin + state.url,
});
return false;
}
return true;
};
This is my test:
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { KeycloakService } from 'keycloak-angular';
import { authGuard } from './auth.guard';
describe('authGuard', () => {
let router: Router;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule],
// Provide the MockKeycloakService for the KeycloakService dependency
providers: [{ provide: KeycloakService, useClass: MockKeycloakService }],
});
// Get the Router instance
router = TestBed.inject(Router);
});
// Step 1: Mock KeycloakService
class MockKeycloakService {
isLoggedIn(): Promise<boolean> {
// Simulate that the user is logged in for testing purposes
return Promise.resolve(true);
}
login(options: any): Promise<void> {
// Simulate the login process for testing purposes
return Promise.resolve();
}
}
it('should allow access when the user is logged in', async () => {
// Arrange
const route: ActivatedRouteSnapshot = {} as any;
const state: RouterStateSnapshot = {} as any;
// Act
const result = await authGuard(route, state);
// Assert
expect(result).toBe(true);
});
it('should redirect to login when the user is not logged in', async () => {
// Arrange
const route: ActivatedRouteSnapshot = {} as any;
const state: RouterStateSnapshot = {
url: '/consent-initiation',
} as any;
// Create a new instance of the MockKeycloakService to simulate the user not logged in
const keycloakService: MockKeycloakService = TestBed.inject(KeycloakService) as any;
spyOn(keycloakService, 'isLoggedIn').and.returnValue(Promise.resolve(false));
// Act
const result = await authGuard(route, state);
// Assert
expect(result).toBe(false);
// You can also test whether the KeycloakService.login() method was called with the correct redirectUri.
});
});
this is the error I get -> Error: NG0203: inject() must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with runInInjectionContext
. Find more at https://angular.io/errors/NG0203
Can't figure out how to fix it. any suggestions ?
You need to use TestBed.runInInjectionContext()
when running your auth guard:
// incorrect
const result = await authGuard(route, state);
// correct
const result = await TestBed.runInInjectionContext(() => authGuard(route, state));