You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular函数式路由守卫测试报错NG0203,求助解决inject()调用上下文问题

Angular函数式路由守卫测试报错NG0203,求助解决inject()调用上下文问题

兄弟我刚踩过这个坑!这个NG0203错误本质是:函数式守卫里的inject()方法必须在Angular的注入上下文环境中才能调用,你直接在测试的it块里调用authGuard的话,没有这个上下文加持,inject()根本找不到要注入的服务,自然就报错了😅

给你两个关键修复方向,直接改测试代码就能解决:

核心修复思路:用TestBed.runInInjectionContext()包裹守卫调用

Angular提供了runInInjectionContext()方法,专门用来帮我们在测试环境中创建合法的注入上下文,让inject()能正常工作。你只需要把调用authGuard的代码放到这个方法的回调里就行。

修改后的完整测试代码

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;

  // Step 1: Mock KeycloakService(调整位置让代码结构更清晰)
  class MockKeycloakService {
    isLoggedIn(): Promise<boolean> {
      return Promise.resolve(true);
    }
    login(options: any): Promise<void> {
      return Promise.resolve();
    }
  }

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [RouterTestingModule],
      providers: [{ provide: KeycloakService, useClass: MockKeycloakService }],
    });
    router = TestBed.inject(Router);
  });

  it('should allow access when the user is logged in', async () => {
    // Arrange
    const route: ActivatedRouteSnapshot = {} as any;
    const state: RouterStateSnapshot = {} as any;

    // Act:用runInInjectionContext包裹守卫调用
    const result = await TestBed.runInInjectionContext(() => {
      return 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;

    // 在注入上下文里获取mock服务并设置spy
    let keycloakService: MockKeycloakService;
    await TestBed.runInInjectionContext(() => {
      keycloakService = TestBed.inject(KeycloakService) as any;
      spyOn(keycloakService, 'isLoggedIn').and.returnValue(Promise.resolve(false));
      spyOn(keycloakService, 'login').and.returnValue(Promise.resolve());
    });

    // Act:同样用runInInjectionContext包裹
    const result = await TestBed.runInInjectionContext(() => {
      return authGuard(route, state);
    });

    // Assert
    expect(result).toBe(false);
    // 顺便验证login方法的调用参数是否符合预期
    expect(keycloakService.login).toHaveBeenCalledWith({
      redirectUri: window.location.origin + state.url
    });
  });
});

额外说明

  1. 我把MockKeycloakService提到了describe顶部,这样测试代码结构更清晰,也符合Angular测试的常规写法。
  2. 第二个测试用例里,我们需要在注入上下文里获取mock服务并设置spy,这样才能确保spy作用的是守卫实际会用到的那个服务实例。
  3. runInInjectionContext是Angular 14及以上版本提供的API,刚好适配你用的函数式守卫(函数式守卫也是14+引入的),完全匹配你的场景。

备注:内容来源于stack exchange,提问作者DevDuke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 07:55:28