如何测试一个 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 在问题评论中所建议的那样,我决定测试最终状态,而不是检查是否实际调用了操作。为了让它起作用,我必须使用运算符 ofActionSuccessful
将 here 和 'listen' 中描述的动作流注入到 'action success' 事件中。这允许仅在操作完成后检查状态,而不是仅在分派时才检查状态,因此我可以测试最终状态下的一切是否如预期。
需要记住的几件事:
- 不要忘记在完成预期后调用
done
函数,否则会出现超时错误。
done
仅当您传递给 it()
函数的回调未使用 async
函数包装时才有效。
- 确保你的模拟 return 东西,即使它是
undefined
。起初我有我的模拟服务方法 return of()
而不是 of(undefined)
,这在某些情况下会导致问题。
- 此外,您可以像这样
delay
定义您的模拟,of(undefined).delay(1)
,这样您就可以控制调用和期望的时间。
希望这对某人有所帮助。
我一直在整个应用程序中广泛使用 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 在问题评论中所建议的那样,我决定测试最终状态,而不是检查是否实际调用了操作。为了让它起作用,我必须使用运算符 ofActionSuccessful
将 here 和 'listen' 中描述的动作流注入到 'action success' 事件中。这允许仅在操作完成后检查状态,而不是仅在分派时才检查状态,因此我可以测试最终状态下的一切是否如预期。
需要记住的几件事:
- 不要忘记在完成预期后调用
done
函数,否则会出现超时错误。 done
仅当您传递给it()
函数的回调未使用async
函数包装时才有效。- 确保你的模拟 return 东西,即使它是
undefined
。起初我有我的模拟服务方法 returnof()
而不是of(undefined)
,这在某些情况下会导致问题。 - 此外,您可以像这样
delay
定义您的模拟,of(undefined).delay(1)
,这样您就可以控制调用和期望的时间。
希望这对某人有所帮助。