测试功能性 Angular 路由防护

Dev*_*uke 4 angular-routing angular angular-test angular-guards

您好,由于类防护已被弃用,我将其移至功能性,但我的测试失败了,我对 keycloak 的可注入服务和防护的参数感到非常困惑。

这是守卫:

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;
};
Run Code Online (Sandbox Code Playgroud)

这是我的测试:

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.
  });
});
Run Code Online (Sandbox Code Playgroud)

这是我得到的错误 -> 错误:NG0203:注入()必须从注入上下文调用,例如构造函数、工厂函数、字段初始值设定项或与runInInjectionContext. 欲了解更多信息,请访问https://angular.io/errors/NG0203

不知道如何解决它。有什么建议 ?

Dan*_*ose 6

TestBed.runInInjectionContext()运行身份验证防护时需要使用:

// incorrect
const result = await authGuard(route, state);

// correct
const result = await TestBed.runInInjectionContext(() => authGuard(route, state));
Run Code Online (Sandbox Code Playgroud)