Angular provides helper functions fakeAsync and tick to handle asynchronous tests. But from my experience I don’t need them for most of my tests, I only find 3 use cases.
—
Check code here.
—
Here is the component I am gonna test:
@Component({
selector: 'mst-fake-async',
template: `
<div>interval value: {{ intervalValue }}</div>
<div>setTimeout value: {{ setTimeoutValue }}</div>
<div>Promise value: {{ promiseValue }}</div> `,
})
export class FakeAsyncComponent implements OnInit, OnDestroy {
observableValue = 0;
intervalValue = 0;
setTimeoutValue = 0;
promiseValue = 0;
private observableSub: Subscription;
private intervalSub: Subscription;
private setTimeoutTimer: NodeJS.Timer; ngOnInit() {
this.observableSub = of(1).subscribe((value) => {
this.observableValue = value;
}); this.intervalSub = interval(1000).subscribe((value) => {
this.intervalValue = value;
}); this.setTimeoutTimer = setTimeout(() => {
this.setTimeoutValue = 1;
}, 3000); Promise.resolve(1).then((value) => {
this.promiseValue = value;
}); }
ngOnDestroy() {
this.observableSub.unsubscribe();
this.intervalSub.unsubscribe();
clearTimeout(this.setTimeoutTimer);
}
}
Before the examples, here is one thing:
If an Observable already has value, the code within subscribe will be run synchronously, you don’t need fakeAsync, you can test it like this:
it("observableValue doesn't need to wait", () => {
fixture.detectChanges();
expect(component.observableValue).toBe(1); component.ngOnDestroy();
});
Ok, here are the 3 cases:
- rxjs interval
it('intervalValue should be 0 without fakeAsync and tick', () => {
fixture.detectChanges();
expect(component.intervalValue).toBe(0); component.ngOnDestroy();
});it('intervalValue should be 1 with fakeAsync and tick', fakeAsync(() => {
fixture.detectChanges();
// interval starts with 0, so we should tick 2 seconds to get 1
tick(2000);
fixture.detectChanges();
expect(component.intervalValue).toBe(1); tick(1000);
fixture.detectChanges();
expect(component.intervalValue).toBe(2); component.ngOnDestroy();
}));
2. setTimeout
it('setTimeoutValue should be 0 without fakeAsync and tick', () => {
fixture.detectChanges();
expect(component.setTimeoutValue).toBe(0); component.ngOnDestroy();
});it('setTimeoutValue should be 1 with fakeAsync and tick', fakeAsync(() => {
fixture.detectChanges();
tick(3000);
fixture.detectChanges();
expect(component.setTimeoutValue).toBe(1); component.ngOnDestroy();
}));
3. Promise
it('promise value should be 0 without fakeAsync and tick', () => {
fixture.detectChanges();
expect(component.promiseValue).toBe(0);
component.ngOnDestroy();
});it('promise value should be 1 with fakeAsync and tick', fakeAsync(() => {
fixture.detectChanges();
tick();
fixture.detectChanges(); expect(component.promiseValue).toBe(1);
component.ngOnDestroy();
}));