如何测试一个 Action 是从 NGXS 中的另一个 Action 中发送的?

How to test that an Action was dispatched from within another Action in 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 在问题评论中所建议的那样,我决定测试最终状态,而不是检查是否实际调用了操作。为了让它起作用,我必须使用运算符 ofActionSuccessfulhere 和 'listen' 中描述的动作流注入到 'action success' 事件中。这允许仅在操作完成后检查状态,而不是仅在分派时才检查状态,因此我可以测试最终状态下的一切是否如预期。

需要记住的几件事:

  • 不要忘记在完成预期后调用 done 函数,否则会出现超时错误。
  • done 仅当您传递给 it() 函数的回调未使用 async 函数包装时才有效。
  • 确保你的模拟 return 东西,即使它是 undefined。起初我有我的模拟服务方法 return of() 而不是 of(undefined),这在某些情况下会导致问题。
  • 此外,您可以像这样 delay 定义您的模拟,of(undefined).delay(1),这样您就可以控制调用和期望的时间。

希望这对某人有所帮助。