ngxs:store.reset禁用茉莉单元测试中的调度员
在用茉莉花测试我的NGXS商店时,我的出乎意料的行为遇到了麻烦。
在这里,我试图测试DeleteAlerts操作:
@Action(DeleteAlerts)
deleteAlerts(ctx: StateContext<AlertStateModel>, action: DeleteAlerts) {
return this.alertService.deleteAlerts(action.alertIds).pipe(
map(response => {
if (response.ok) {
action.alertIds.forEach(alertId => {
ctx.setState(patch({
alerts: removeItem<UniqueAlert>(alert => alert.alertIds.includes(alertId))
}));
});
} else {
throw new Error('Server failed to respond.');
}
}
));
}
但是首先必须使用虚拟数据填充该商店。
我创建了此模型:
const alertsMock = new Alerts({
alerts: [new UniqueAlert({alertIds: ['test1']}),
new UniqueAlert({alertIds: ['test2']}),
new UniqueAlert({alertIds: ['test3']})]
});
我的商店看起来像这样:
export interface AlertStateModel {
alerts: UniqueAlert[];
}
然后我尝试用模拟填充商店:
store.reset({alerts: alertsMock.alerts})
但是,当我在测试中执行此操作时,deletealerts
操作在调用时不会派遣。 store.dispatch(new deletealerts(alertids))
这是我不明白的部分:用getAlerts store.reset
方法时,操作确实派遣了。 >调度,指示从模拟服务加载警报:
getAlerts操作:
@Action(GetAlerts)
public getAlerts(ctx: StateContext<AlertStateModel>) {
return this.alertService.getAlerts().pipe(
tap(fetchedAlerts => {
ctx.setState({alerts: fetchedAlerts.alerts});
})
);
}
此测试通过:
it('should delete one alert from the store when DeleteAlerts is dispatched', () => {
spyOn(alertService, 'getAlerts').and.returnValue(of(alertsMock));
store.dispatch(new GetAlerts());
spyOn(alertService, 'deleteAlerts').and.returnValue(of(new HttpResponse({status: 200})));
store.dispatch(new DeleteAlerts(['test2']));
store.selectOnce(AlertState).subscribe(data => {
expect(data.alerts).toEqual(alertsMock.alerts.filter(alert => !alert.alertIds.includes('test2')));
});
});
});
此测试没有:
it('should delete one alert from the store when DeleteAlerts is dispatched', () => {
store.reset({alerts: alertsMock.alerts});
spyOn(alertService, 'deleteAlerts').and.returnValue(of(new HttpResponse({status: 200})));
store.dispatch(new DeleteAlerts(['test2']));
store.selectOnce(AlertState).subscribe(data => {
expect(data).toEqual(alertsMock.alerts.filter(alert => !alert.alertIds.includes('test2')));
});
});
最重要的是,您可能已经注意到我的期望是在data
上。 ,而不是data.Alerts
在非功能测试中。这是我想理解的另一种行为,因为选择器应返回状态,该状态包含嵌套arters
对象。
为什么两项测试不等效,为什么选择器使用store.reset
填充商店的预期对象
? 包含一个嵌套警报
对象;这就是AlertService返回的数据的格式。
I am having trouble with an unexpected behavior while unit testing my NGXS store with Jasmine.
Here, I am trying to test the DeleteAlerts action :
@Action(DeleteAlerts)
deleteAlerts(ctx: StateContext<AlertStateModel>, action: DeleteAlerts) {
return this.alertService.deleteAlerts(action.alertIds).pipe(
map(response => {
if (response.ok) {
action.alertIds.forEach(alertId => {
ctx.setState(patch({
alerts: removeItem<UniqueAlert>(alert => alert.alertIds.includes(alertId))
}));
});
} else {
throw new Error('Server failed to respond.');
}
}
));
}
but the store must first be populated with dummy data.
I created this mock :
const alertsMock = new Alerts({
alerts: [new UniqueAlert({alertIds: ['test1']}),
new UniqueAlert({alertIds: ['test2']}),
new UniqueAlert({alertIds: ['test3']})]
});
My store looks like this :
export interface AlertStateModel {
alerts: UniqueAlert[];
}
I then tried to populate the store with the mock :
store.reset({alerts: alertsMock.alerts})
However, when I do this in my test, the DeleteAlerts
action does not dispatch when calling store.dispatch(new DeleteAlerts(alertIds))
Here is the part I do not understand : The action does dispatch when replacing the store.reset
method with a GetAlerts
dispatch, which is directed to load the alerts from a mocked service :
The GetAlerts action :
@Action(GetAlerts)
public getAlerts(ctx: StateContext<AlertStateModel>) {
return this.alertService.getAlerts().pipe(
tap(fetchedAlerts => {
ctx.setState({alerts: fetchedAlerts.alerts});
})
);
}
This test passes :
it('should delete one alert from the store when DeleteAlerts is dispatched', () => {
spyOn(alertService, 'getAlerts').and.returnValue(of(alertsMock));
store.dispatch(new GetAlerts());
spyOn(alertService, 'deleteAlerts').and.returnValue(of(new HttpResponse({status: 200})));
store.dispatch(new DeleteAlerts(['test2']));
store.selectOnce(AlertState).subscribe(data => {
expect(data.alerts).toEqual(alertsMock.alerts.filter(alert => !alert.alertIds.includes('test2')));
});
});
});
This test does not :
it('should delete one alert from the store when DeleteAlerts is dispatched', () => {
store.reset({alerts: alertsMock.alerts});
spyOn(alertService, 'deleteAlerts').and.returnValue(of(new HttpResponse({status: 200})));
store.dispatch(new DeleteAlerts(['test2']));
store.selectOnce(AlertState).subscribe(data => {
expect(data).toEqual(alertsMock.alerts.filter(alert => !alert.alertIds.includes('test2')));
});
});
On top of that, you might have noticed that my expectation is on data
, rather than data.alerts
on the non-functional test. This is another behavior I would like to understand, since the selector should return the state, which contains a nested alerts
object.
Why aren't the two tests equivalent, and why does the selector not return the expected object when using store.reset
to populate the store ?
Regarding why the alertsMock
contains a nested alerts
object ; that is the format of the data returned by the alertService.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
看起来您没有将商店快照扩展到测试重置中。该文档并没有明确说明这样做,但是当我以这种方式重置时,我自己的测试通过了。
It looks like you are not expanding the store snapshot into the test reset. The documentation doesn't explicitly say to do this, but my own tests pass when I reset in this fashion.