如何测试一个动作是从NGXS中的另一个动作中分派的?

问题描述

我一直在整个应用程序中广泛使用NGXS,但是有些事情我仍然无法以适当的方式完成,到目前为止,文档或此处提出的其他问题都没有帮助。其中之一就是测试动作,特别是测试从另一个动作中调用了某个动作。检查以下内容

store.ts

@Action(ActionToBeTested)
  public doActionToBeTested(
    ctx: StateContext<MyState>,): void {
    const state = ctx.getState();

    // update state in some way

    ctx.patchState(state);

    this.restApiService.save(state.businessData)
      .pipe(
        mergeMap(() =>
          this.store.dispatch(new SomeOtherAction(state.businessData)),)
      )
      .subscribe();
  }

store.spec.ts

it('should test the state was update,restapi was called and action was dispatched',async(() => {
    store.reset({...someMockState});

    store.dispatch(new ActionToBeTested());

    store
      .selectOnce((state) => state.businessData)
      .subscribe((data) => {
        expect(data).toBe('Something I expect');
        expect(restApiServiceSpy.save).toHaveBeenCalledTimes(1);
        
      });
  }));

以此,我可以测试状态是否已更新并且调用了其余服务,但是我根本无法测试动作SomeOtheAction是否已调度。自将第一个动作(我知道有点疯狂)分配给此answer中描述的内容后,尝试在商店中进行监视以来,我已经尝试了很多事情,但没有成功。

有人遇到类似的困难并找到了解决方案。如果是这样,请指出正确的方向,我将很乐意自己走这条路。谢谢

解决方法

解决问题将近一整天后,我得出了可以视为解决方案的解决方案。如下:

it('should test the state was update,restapi was called and action was dispatched',(done) => {
      store.reset({...someMockState});
      
      actions$.pipe(ofActionSuccessful(DeleteSource)).subscribe((_) => {
        const updatedData = store.selectSnapshot(
          (state) => state.businessData,);
        
        expect(updatedData).toBe('Something I expect due to the first action');
        expect(updatedData).toBe('Something I expect due to the SECOND action');
        expect(restApiServiceSpy.save).toHaveBeenCalledTimes(1);
        done();
      });
  
      store.dispatch(new ActionToBeTested());
});

那么,这是怎么回事?正如@Eldar在问题评论中所建议的那样,我决定测试最终状态,而不是检查该动作是否真正被调用。为了使其正常工作,我必须按照here所述插入动作流,并使用操作员ofActionSuccessful“监听”“动作成功”事件。这样就可以仅在操作完成后检查状态,而不必只是分派状态,这样我就可以测试一切是否都处于最终状态。

几件事要记住:

  • 完成期望后,别忘了调用done函数,否则会出现超时错误。
  • done仅在传递给it()函数的回调没有与async函数一起包装的情况下起作用。
  • 请确保您的模拟返回了某些内容,即使它是undefined。最初,我的模拟服务方法返回of()而不是of(undefined),这在某些情况下会引起问题。
  • 此外,您可以像delay这样用已定义的of(undefined).delay(1)来定义模拟,因此您可以控制通话和期望的时间。

希望这对某人有帮助。