Testing interval with async pipe using fakeAsync and tick not working as expected

Viewed 62

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.

0 Answers
Related