In Angular how can I write a unit test case for something that implements CanActivateFn
like this?
export const AuthorizedUserClaimGuard: CanActivateFn = (route, state) => {
const auth = inject(AuthenticationService);
const config = inject(ConfigurationService);
if (!auth.authenticated) {
auth.setState({
route: state.url,
});
auth.logout();
// tslint:disable-next-line: no-console
console.info('User is not authenticated, redirecting to the login page.');
}
const userClaims = config.authorizedClaims;
for (const userClaim of userClaims) {
if (auth.hasPermission(userClaim)) {
return true;
}
}
return false;
};
I've tried the following code but it doesn't work because AuthorizedUserClaimGuard
is not a class. Is there a way to make it work like this?
describe('AuthorizedUserClaimGuard', () => {
let guard: AuthorizedUserClaimGuard;
let authentication: AuthenticationService;
let configuration: ConfigurationService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
{
provide: AuthenticationService,
useClass: MockAuthenticationService,
},
],
}).compileComponents();
}));
beforeEach(() => {
authentication = TestBed.get(AuthenticationService);
configuration = TestBed.get(ConfigurationService);
configuration.setConfiguration(MOCK_CONFIGURATION);
guard = new AuthorizedUserClaimGuard(authentication, configuration);
});
it('should return true for a logged in user', () => {
const route = createMockRoute();
const state = createMockRouteState();
expect(guard.canActivate(route, state)).toBeTruthy();
});
}
Yes it is not a class, it is a function. You don't need to declare it. However, as you have injections included, you need to run your function in injection context.
describe('AuthorizedUserClaimGuard', () => {
let authentication: AuthenticationService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
{
provide: AuthenticationService,
useClass: MockAuthenticationService,
},
],
});
}));
it('should return true for a logged in user', () => {
const guardResult = TestBed.runInInjectionContext(() = AuthorizedUserClaimGuard(createMockRoute(), createMockRouteState()));
expect(guardResult).toBeTruthy();
});
}
The guardResult type can differ depending on your implementation. You have a sync result and can compare it directly. Naren Murali from the previous answer expects the result to be a promise. In case it would be an observable I would recommend to compare the result with marbles.