微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在父应用程序模块中使用功能模块的初始状态模拟商店

如何解决如何在父应用程序模块中使用功能模块的初始状态模拟商店

我使用的是 angular 8。我有一个模块 app一个子模块“功能”。两者都有自己的商店。 'app.module.ts' 有

@NgModule({
 imports: [
    ...
    StoreModule.forRoot({ 'app': reducer }),...
}]

同理,'feature' 模块有

StoreModule.forFeature('feature',fromFeature.reducer)

现在,在 jasmine 中测试 app 级组件时,我模拟 Store 如下

let store: MockStore<State>;
 Testbed.configureTestingModule({
 imports: [
   StoreModule.forRoot({'app' : reducer})
 ],providers: [
   provideMockStore({initialState})
 ]

其中 initialStateapp 模块的初始状态。但是,在尝试获取 store = Testbed.get(Store); state 模块的 feature 的未定义值时出错,它尝试从 feature 模块访问选择器。

我的理解是,我需要使用整个应用程序的状态来初始化 mockStore,而不仅仅是 app 模块状态。但是,我不确定如何实现。

我确实尝试导入 StoreModule.forFeature('feature',featureReducer) 并将模拟存储初始化为 provideMockStore({initialState:: {initialState,featureInitialState}}),但我仍然获得了选择器的功能状态 undefined

错误如下

ERROR TypeError: Cannot read property 'isEntity' of undefined
at getIsEntity (VM17 main.js:50252)
at store.js:583
at memoized (store.js:525)
at defaultStateFn (store.js:552)
at store.js:586
at memoized (store.js:525)
at MapSubscriber.project (store.js:480)

其中 getIsEntity一个 feature 模块选择器,定义如下:

const getIsEntity = (state: State): boolean => state.isEntity

如何模拟/传递父应用模块中功能模块的初始状态?

解决方法

将其模拟为根存储,因为没有自己的存储,所有减速器/动作和效果始终与存储(单个根存储)一起使用,而调用“forFeature”给人的印象是它们有自己的存储。

不,他们没有,他们访问同一个根存储。

let store: MockStore<State>;
 TestBed.configureTestingModule({
 imports: [
   StoreModule.forRoot({
     'app' : reducer,'feature': ....,})
 ],providers: [
   provideMockStore({initialState})
 ]

不幸的是,由于信息量很少,很难指出确切的错误位置,但您可以在下面查看一个工作示例:

describe('suite',() => {
    let fixture: MockedComponentFixture<TestedComponent>;
    let storeState: DeepPartial<StoreState & {ngrxCorrelationId: {tasks: Array<string>; payloads: unknown}}>;

    beforeEach(() => {
        const actions = new Observable<{}>();
        storeState = {
            ngrxCorrelationId: {
                tasks: [],payloads: {},},v2ProjectEntity: {
                ids: [],entities: {},lists: {},v2PermissionsEntity: {},};

        TestBed.configureTestingModule({
            declarations: [TestedComponent],providers: [
                provideMockStore({
                    initialState: storeState,}),provideMockActions(() => actions),{
                    provide: LoaderService,useValue: createSpyObj('LoaderService',['setLoaderStatus','hideLoader']),{
                    provide: Router,useValue: createSpyObj('Router',['navigate','navigateByUrl']),{
                    provide: ActivatedRoute,useValue: {
                        queryParams: new Subject(),TestedEffects,],});
        fixture = MockRender(TestedComponent);
    });

    it('listens on initial load public projects of the smart component',inject(
        [ActivatedRoute,Store],(activatedRoute: ActivatedRoute,store: Store<{}>) => {
            const props = {
                cid: 'public',options: {
                    relations: [
                        'location','location.address','quotations','quotations.owner','quotations.owner.company','quotations.documents','certificates','certificatesCustom','documents',scopes: ['public'],filters: {
                        category: undefined,deadline: undefined,order: undefined,};
            spyOn(store,'dispatch');
            (<Subject<{}>>activatedRoute.queryParams).next({});
            fixture.detectChanges();

            expect(store.dispatch).toHaveBeenCalledTimes(1);
            expect(store.dispatch).toHaveBeenCalledWith(publicProjectsListLoad({...props}));
        },));

    it('listens on load public projects with filters of the smart component',filters: {
                        category: ['transformer'],deadline: ['0-10'],order: ['projectName:desc'],'dispatch');
            (<Subject<{}>>activatedRoute.queryParams).next({
                'filters[category]': 'transformer','filters[deadline]': '0-10',order: 'projectName:desc',});
            fixture.detectChanges();

            expect(store.dispatch).toHaveBeenCalledTimes(1);
            expect(store.dispatch).toHaveBeenCalledWith(publicProjectsListLoad({...props}));
        },));
});
,

我终于找到了问题所在。我有模块的单独状态,应用程序状态没有包含所有状态。因此,当我仅使用应用程序状态进行模拟时,测试还需要模块的模拟状态,而在我传递给模拟商店的初始状态中不存在该状态。

根据 Angular 8 文档,示例显示,应用商店状态应该包含所有模块的状态,而我的案例中没有。

通过创可贴解决了这个问题,我们创建了一个假的初始状态来扩展应用程序和模块状态。然后,将那个虚假的初始状态传递给模拟商店。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。