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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 05:22:46