Angular: Unit Test: Usage of fakeAsync and tick

peng37
2 min readApr 8, 2019

--

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:

  1. 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();
}));

--

--