Angular16使用selectSignal后ProvideMockStore致TestBed报错求助
Angular 16 + NgRx Signals 测试报错:Cannot read properties of undefined (reading 'changes')
问题背景
升级Angular到16版本并改用NgRx的selectSignal获取状态后,测试时抛出如下错误:
TypeError: Cannot read properties of undefined (reading 'changes') at apply (http://localhost:9876/_karma_webpack_/webpack:/src/app/core/components/changelog/store/changelog.selectors.ts:20:15) // 省略后续调用栈
组件通过Facade获取Signal数据:
// 组件代码 changes = this.facade.changes; constructor(private facade: ChangelogFacade) {}
Facade中通过selectSignal获取状态:
// Facade代码 changes = this.store.selectSignal(getChangelog);
此前使用Observable搭配async管道时测试正常,现使用provideMockStore()的测试用例无法正常运行。
问题原因
selectSignal会同步执行Selector并返回Signal,而当前测试中provideMockStore()创建的是一个空状态的Mock Store。当getChangelog Selector尝试从状态中读取changes属性时,对应字段不存在,直接抛出undefined错误。
而之前的Observable版本属于异步流,测试初始化阶段不会立即触发Selector计算,因此未暴露该问题。
修复方案
方案1:传入匹配结构的初始状态
给provideMockStore传入与真实Store结构一致的初始状态,确保Selector能访问到changes字段:
// 修改测试代码中的TestBed配置 await TestBed.configureTestingModule({ imports: [FontAwesomeModule, ModalComponent, ChangelogComponent], providers: [ provideMockStore({ // 匹配你的Store层级结构,示例假设changelog状态的key为'changelog' initialState: { changelog: { changes: [] // 可传入空数组或测试模拟数据 } } }) ], }).compileComponents();
方案2:直接指定Selector返回值
如果需要更灵活地控制Selector的返回结果,可以使用MockStore的overrideSelector方法:
// 测试代码中添加MockStore注入 import { MockStore } from '@ngrx/store/testing'; describe('ChangelogComponent', () => { let component: ChangelogComponent; let fixture: ComponentFixture<ChangelogComponent>; let store: MockStore; beforeEach(async () => { await TestBed.configureTestingModule({ imports: [FontAwesomeModule, ModalComponent, ChangelogComponent], providers: [provideMockStore()], }).compileComponents(); store = TestBed.inject(MockStore); // 直接指定getChangelog Selector的返回值 store.overrideSelector(getChangelog, []); // 通知Store状态更新 store.refreshState(); fixture = TestBed.createComponent(ChangelogComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); });
注意事项
- 初始状态的层级结构必须与真实Store完全匹配,避免Selector访问深层属性时再次出现undefined错误。
- 使用
selectSignal时,所有依赖的状态必须在初始化阶段就存在,因为Signal是同步计算的,无法像Observable那样延迟处理。
内容的提问来源于stack exchange,提问作者Fernando Silva Maransatto
相关产品推荐
相关产品推荐

