79476747

Date: 2025-02-28 21:46:35
Score: 1
Natty:
Report link

jest.useFakeTimers() with jest.advanceTimersByTime() seems to be the only solution. (Or jasmine.clock().install() with jasmine.clock().tick()).

The test setup has to include jest.useFakeTimers() before the first fixture.detectChanges() call (because this is the moment that the async pipe subscribes to the timer - the underlying setInterval has to already be mocked at that point):

beforeEach(async () => {
  await TestBed.configureTestingModule({
    imports: [AppComponent],
  }).compileComponents();

  jest.useFakeTimers();

  fixture = TestBed.createComponent(AppComponent);
  component = fixture.componentInstance;
  fixture.detectChanges();
});

The test then looks like this:

it('should show "Timer fired"', () => {
  jest.advanceTimersByTime(3000);
  fixture.detectChanges();
  expect(fixture.nativeElement.textContent).toContain('Timer fired');
  expect(fixture.nativeElement.textContent).not.toContain('Waiting');
});

My experiences with fakeAsync and the async pipe match those Barry McNamara describes in https://stackoverflow.com/a/59164109/4715712

I updated my original StackBlitz with more tests. They also include a test that unfortunately disproves Naren Muralis original answer (which I at first was convinced is correct even though my gut instinct told me it doesn't work).

Stackblitz Demo: https://stackblitz.com/edit/angular-rxjs-timer-asyncpipe-unit-test?file=src%2Fmain.ts,src%2Ftest.spec.ts

Reasons:
  • Blacklisted phrase (1): stackoverflow
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (1):
Posted by: reins.ch