Angular 5使用@ngrx/router-store测试组件遇Karma错误求助
state未定义与beforePreactivation错误 我来帮你拆解一下这个问题,你遇到的其实是NgRx Router Store在测试环境中常见的依赖配置问题,咱们一步一步来解决:
1. 核心问题分析
你一开始碰到的state.router未定义,本质是测试模块没有正确初始化NgRx Router Store的状态,导致选择器拿不到路由相关的state;而添加StoreRouterConnectingModule.forRoot()后出现的Cannot set property 'beforePreactivation' of undefined,则是因为测试环境里Angular Router的核心钩子依赖缺失——Router Store需要依赖Router实例的hooks对象,但测试模块中的Router可能没完成正确初始化。
2. 测试场景的正确配置方案
在测试NgRx Router Store相关组件时,不建议直接用StoreRouterConnectingModule.forRoot(),更稳妥的方式是用模拟状态或者补全Router依赖,以下两种方案任选:
方案一:手动模拟Router State(最简单直接)
不需要导入StoreRouterConnectingModule,而是在StoreModule.forRoot中给router reducer提供初始模拟状态,让选择器能拿到有效数据:
import * as fromRouter from '@ngrx/router-store'; // 模拟Router的初始状态 const mockRouterState: fromRouter.RouterReducerState<RouterStateUrl> = { state: { url: '/test-wizard', queryParams: {}, params: {} }, navigationId: 1 }; // 合并你的其他reducers const reducers = { // 你的业务reducers... router: fromRouter.routerReducer }; // 配置TestBed TestBed.configureTestingModule({ imports: [ RouterModule.forRoot([]), // 必须导入RouterModule,至少配置空路由 StoreModule.forRoot(reducers, { initialState: { router: mockRouterState // 手动注入router初始状态 }, metaReducers }), EffectsModule.forRoot([MyEffects, WizardEffects]), HttpClientModule ], // 其他配置:declarations、providers等 });
方案二:补全Router依赖适配StoreRouterConnectingModule
如果你需要更贴近真实环境的测试,想保留StoreRouterConnectingModule.forRoot(),可以手动初始化Router的hooks对象,解决beforePreactivation未定义的问题:
import { Router } from '@angular/router'; import { StoreRouterConnectingModule } from '@ngrx/router-store'; beforeEach(() => { TestBed.configureTestingModule({ imports: [ RouterModule.forRoot(wizardRoutes), StoreModule.forRoot(reducers, { metaReducers }), EffectsModule.forRoot([MyEffects, WizardEffects]), HttpClientModule, StoreRouterConnectingModule.forRoot() ] }); // 获取Router实例,手动初始化hooks对象 const router = TestBed.inject(Router); router.hooks = router.hooks || {}; // 确保hooks存在,避免undefined报错 });
3. 额外优化建议
- 确保你的
AppState接口正确包含router: fromRouter.RouterReducerState<RouterStateUrl>,避免类型不匹配的隐性问题; - 测试环境下优先用
RouterTestingModule替代RouterModule,它是Angular专门为测试优化的路由模块,能减少很多依赖问题:
import { RouterTestingModule } from '@angular/router/testing'; // 替换原有的RouterModule配置 TestBed.configureTestingModule({ imports: [ RouterTestingModule.withRoutes(wizardRoutes), // 其他导入... ] });
按照上面的配置调整后,你的选择器应该能正常获取router state,同时Karma浏览器中的错误也会消失。
内容的提问来源于stack exchange,提问作者serlingpa

