[英]Test rxjs interval in Angular 6 component ngOnInit function
I have a component with the following ngOnInit function which polls a service method for status updates:我有一个带有以下 ngOnInit 函数的组件,它轮询服务方法以进行状态更新:
ngOnInit() {
interval(2000).pipe(
switchMap(() => this.dataService.getStatus())
).subscribe((result) => {
this.uploadStatus = result;
);
}
I am trying to test that the updates are actually happening using the following code:我正在尝试使用以下代码测试更新是否实际发生:
beforeEach(() => {
fixture = TestBed.createComponent(UploadComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should start checking for status updates', fakeAsync(() => {
const dataService = TestBed.get(DataService);
// Mock the getStatus function
spyOn(dataService, 'getStatus').and.returnValue(Observable.create().pipe(map(() => 'woo')));
// Should not be initialised yet
expect(component.uploadStatus).toBeUndefined();
tick(2000);
expect(component.uploadStatus).toBe('woo');
}));
However component.uploadStatus
is always null.但是
component.uploadStatus
始终为 null。 How should I go about testing this type of scenario?我应该如何去测试这种类型的场景? Ideally I would like to check for multiple updates over time.
理想情况下,我想随着时间的推移检查多个更新。
Thanks谢谢
What I eventually settled on was the following.我最终确定的是以下内容。 I also had to store the subscription so that I can cancel it at the end of the test to prevent "periodic timers still in queue" errors:
我还必须存储订阅,以便在测试结束时取消订阅,以防止“定期计时器仍在队列中”错误:
ngOnInit() {
// Store the subscription so we can unsubscribe when testing
this.pollingSubscription = interval(2000).pipe(
switchMap(() => this.dataService.getStatus())
).subscribe((result) => {
this.uploadStatus = result;
});
}
Then test as follows:然后测试如下:
it(`init`, fakeAsync(inject([DataService],
(dataService: DataService) => {
const testReturns = [
of('woo'),
of('yay')
];
let currentReturn = -1;
spyOn(dataService, 'getStatus').and.callFake(() => {
currentReturn++;
return testReturns[currentReturn];
});
expect(component.uploadStatus).toBeUndefined();
fixture.detectChanges();
// expect(component.uploadStatus).toBe('Login');
// spyOn(dataService, 'getStatus').and.returnValue(of('woo'));
component.ngOnInit();
tick(2000);
expect(component.uploadStatus).toBe('woo');
tick(2000);
expect(component.uploadStatus).toBe('yay');
// Unsubscribe to prevent the "periodic timers still in queue" errors
component.pollingSubscription.unsubscribe();
})));
The problem is in the beforeEach
of the unit test template the Angular CLI set up for you.问题出在 Angular CLI 为您设置的
beforeEach
单元测试模板中。 You subscribe to the Observable created by interval
during the first change detection cycle, ie, in ngOnInit
.在第一个变更检测周期,即在
ngOnInit
,您订阅了由interval
创建的 Observable。
The subscription must take place inside the fakeAsync
zone in order for tick
to manage the Observable's time.订阅必须在
fakeAsync
区域内进行,以便tick
管理 Observable 的时间。 Move the call to fixture.detectChanges
inside the fakeAsync
zone and you will see tick
now manages the time.移动呼叫
fixture.detectChanges
内部fakeAsync
区,你会看到tick
现在管理的时间。
beforeEach((): void => {
fixture = TestBed.createComponent(UploadComponent);
component = fixture.componentInstance;
// Get rid of call to detectChanges
});
it('should start checking for status updates', fakeAsync((): void => {
// Arrange
const dataService = TestBed.get(DataService);
spyOn(dataService, 'getStatus').and.returnValue(of('woo'));
// Assert
expect(component.uploadStatus).toBeUndefined();
// Act
fixture.detectChanges();
tick(2000);
// Assert
expect(component.uploadStatus).toBe('woo');
// Clean up RxJS.interval function
discardPeriodicTasks();
}));
you have to trigger change detection after tick, this should work您必须在勾选后触发更改检测,这应该可以工作
tick(2000);
fixture.detectChanges();
expect(component.uploadStatus).toBe('woo');
You may use setTimeout()
to wait for 2 seconds (slightly more because you are again doing asynchronous task inside), and then check the property
value.你可以使用
setTimeout()
等待2秒(稍微多一点,因为你又在里面做异步任务),然后检查property
值。
Make sure to use done()
method to notify the test runner that test case is completed.确保使用
done()
方法通知测试运行器测试用例已完成。
it('should start checking for status updates', (done) => {
const dataService = TestBed.get(DataService);
// Mock the getStatus function
spyOn(dataService, 'getStatus').and.returnValue(Observable.create().pipe(map(() => 'woo')));
// Should not be initialised yet
expect(component.uploadStatus).toBeUndefined();
setTimeout(()=> {
expect(component.uploadStatus).toBe('woo');
done();
},2500);
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.