Testing RxJS timers with Jest

Giancarlo Buomprisco
·
·2 min read

Testing RxJS has always been challenging for me, especially when using timer operators (such as timer, debounce, interval).

Some testing utilities (such as Angular's) make it easier - others not so much.

Jest, though, didn't make me miss Angular's utilities much; I didn't find too much online, and StackOverflow's answers led to more questions.

So this blog post is for you, and future me.

Testing a simple timer stream with Jest's timers

Let's write a dead-simple RxJS operator that emits a value every 100 milliseconds.

We will test that it emitted five times in 499 milliseconds, no more, and no less.

When we want to use Jest's timers, we need to enable such functionality:

jest.useFakeTimers();

Let's create a simple function tick to advance by a certain number of ms:

const tick = (ms = 0) => {  
	jest.advanceTimersByTime(ms);
};

By default, it advances by 0 milliseconds.

And now, on to the test.

We can use Jest's mock to count the times they have been called.

// a simple mock

const fn = () => jest.fn(() => 1);

Now, nothing special, we will create the timer stream; it starts from 0 and advances every 100 milliseconds:

const stream$ = timer(0, 100).pipe(
  tap(fn),
);

And here is the full test:

it('emits 5 times', async () => {
  const fn = jest.fn(() => 1);
  const stream$ = timer(0, 100).pipe(tap(fn));

  // subscribe to the stream, otherwise it will never execute
  stream$.subscribe();

  // advance time by 499 ms
  tick(499);

  // expect the spy "fn" to have been called 5 times
  expect(fn.mock.calls.length).toEqual(5);
});

And here is proof :)

Test running in WebStorm


Learn more about
RxJsRxJs