I have an Angular component:
timer$ = interval(1000).pipe(
map(x => x + 1),
startWith(0),
filter(x => x <= TIMEOUT_SEC),
map(x => {
if (x >= TIMEOUT_SEC) {
this.logout();
return {
minutes: 0,
seconds: 0,
};
}
const minutes = Math.floor((TIMEOUT_SEC - x) / 60);
return {
minutes: minutes,
seconds: TIMEOUT_SEC - minutes * 60 - x,
};
})
);
isIdle$ = new BehaviorSubject(false);
Template:
<modal *ngIf="isIdle$ | async" >
<ng-container *ngIf="timer$ | async as timer">
<text *ngIf="timer.minutes > 0 || timer.seconds > 0">
<strong *ngIf="timer.minutes > 0">{{ timer.minutes }} min </strong>
<strong>{{ timer.seconds }} sec</strong>
</text>
</ng-container>
</modal>
And unit test:
it('WORKS: should call logout after timeout', fakeAsync(() => {
expect(window.location.href).toBe('/analyzer');
expect(component).toBeTruthy();
const lastTimer: { minutes: number; seconds: number }[] = [];
const timerSub = component.timer$.subscribe(v => {
lastTimer.push(v);
});
tick(70000);
// I want to see total seconds (60 sec timeout) plus 0, 0
expect(lastTimer.length).toBe(61);
expect(window.location.href).toBe('/logout');
timerSub.unsubscribe();
}));
it('DOES NOT WORK', fakeAsync(() => {
expect(window.location.href).toBe('/analyzer');
expect(component).toBeTruthy();
component.isIdle$.next(true);
fixture.detectChanges();
tick(70000);
fixture.detectChanges();
// I want to see all timers plus 0, 0
expect(window.location.href).toBe('/logout');
}));
Those tests are equivalent to me but one is working as expected while other, which rely on template and async pipe, does not.
Sure I could easily move observable to service and test it there, then inject fake service into component and so on. But I want to understand why if I subscribe it works, while if async pipe subscribe it does not.