使用NgMocks测试canActivate守卫时遇依赖缺失错误
函数式CanActivate守卫的NgMocks测试配置问题
我正在为一个简单的canActivate函数式守卫编写测试,该守卫在应用中可正常工作,但使用NgMocks编写测试时出现错误:
Error: MockBuilder has found a missing dependency: hasGraphResultsCanActiveGuard. It means no module provides it. Please, use the "export" flag if you want to add it explicitly.
尝试添加export flag后,又出现无法解析参数的问题。相关代码如下:
// guard export const hasGraphResultsCanActiveGuard: CanActivateFn = ( route: ActivatedRouteSnapshot, routerState: RouterStateSnapshot ) => { return inject(Store) .select(selectGraphResults) .pipe( map((results) => { return results.length > 0; }), tap((hasResults) => { if (!hasResults) { inject(Router).navigate(['/app/map']); } }) ); };
// routes in the module where its used const routes: Routes = [ { path: 'analysis', component: AnalysisComponent, canActivate: [hasGraphResultsCanActiveGuard], }, { path: '**', pathMatch: 'full', redirectTo: 'analysis', }, ];
// Test describe('HasGraphResultsGuard', () => { beforeEach(() => { return ( MockBuilder( [ RouterModule, RouterTestingModule.withRoutes([]), NG_MOCKS_ROOT_PROVIDERS, ], DisruptionPageModule ) .exclude(NG_MOCKS_GUARDS) .keep(hasGraphResultsCanActiveGuard) .provide( provideMockStore({ initialState: { graph: cloneDeep(initialGraphState), }, }) ) ); }); it('Redirects to /app/map', fakeAsync(() => { const fixture = MockRender(RouterOutlet, {}); const router = ngMocks.get(Router); const location = ngMocks.get(Location); // Initialize navigation if (fixture.ngZone) { fixture.ngZone.run(() => router.initialNavigation()); tick(); } // The initial state has no graph results so it should redirect expect(location.path()).toEqual('/app/map'); })); });
请问我是否遗漏了配置项,或是文档存在缺失?
解决方案
问题出在函数式守卫(CanActivateFn)的测试配置逻辑上,和类守卫的处理方式不同,调整后的测试配置如下:
describe('HasGraphResultsGuard', () => { beforeEach(() => { return MockBuilder(DisruptionPageModule) // 排除默认的守卫模拟,避免冲突 .exclude(NG_MOCKS_GUARDS) // 配置测试路由,确保守卫能被触发,用Mock组件替代真实组件 .provide(RouterTestingModule.withRoutes([ { path: 'analysis', component: ngMocks.mock(Component), canActivate: [hasGraphResultsCanActiveGuard], }, { path: 'app/map', component: ngMocks.mock(Component), }, ])) // 提供MockStore并初始化状态 .provide(provideMockStore({ initialState: { graph: cloneDeep(initialGraphState), }, })) // 确保Router相关根依赖被正确提供 .provide(NG_MOCKS_ROOT_PROVIDERS); }); it('Redirects to /app/map when no graph results exist', fakeAsync(() => { const router = ngMocks.get(Router); const location = ngMocks.get(Location); // 主动导航到需要守卫校验的路由 router.navigate(['/analysis']); tick(); // 验证重定向结果 expect(location.path()).toEqual('/app/map'); })); });
关键调整说明:
- 函数式守卫的注册:函数式守卫不是类,不需要用
.keep(),直接在测试路由的canActivate数组中引用即可,更贴合实际业务场景。 - 简化Router配置:不要同时引入
RouterModule和RouterTestingModule,直接用RouterTestingModule.withRoutes()配置测试所需的完整路由链路,包括重定向目标的Mock组件。 - 触发守卫的正确方式:通过
router.navigate(['/analysis'])主动触发路由导航,确保守卫逻辑被执行,而非依赖initialNavigation()。 - 依赖注入校验:确保
Store和Router的Mock实例被正确提供,provideMockStore负责状态管理Mock,RouterTestingModule负责路由相关Mock。
内容的提问来源于stack exchange,提问作者JDillon522
相关产品推荐
相关产品推荐

