How to use jest.useFakeTimers(); with react

Viewed 1086

I have a simple component, I would like ot test setInterval(), basically after forwarding the timer the snapshots should show 3 but instead is always on 0. Any idea what is wrong in my code? Thanks

component:

import React from 'react';

export function Test(): JSX.Element {
  const [counter, setCounter] = React.useState(0);
  React.useEffect(() => {
    const id = setInterval(() => {
      setCounter(counter + 1);
    }, 1000);
    return clearInterval(id);
  });
  return <div>{counter}</div>;
}

test:

import React from 'react';
import renderer, { act } from 'react-test-renderer';
import { Test } from './Test';

describe('test', () => {
  jest.useFakeTimers();
  it('should xx', () => {
    const tree = renderer.create(<Test />);

    act(() => {
      jest.advanceTimersByTime(3000);
      expect(tree).toMatchSnapshot();
    });
  });
});


result:

// Jest Snapshot v1

exports[`test should xx 1`] = `
<div>
  0
</div>
`;

2 Answers

I think you are clearing the interval just after creating it. I mean you are returning clearInterval(id). Instead just return the id.

import React from 'react'; export function Test(): JSX.Element { const [counter, setCounter] = React.useState(0); React.useEffect(() => { const id = setInterval(() => { setCounter(counter + 1); }, 1000); return id; }); return <div>{counter}</div>; }

You need to change useEffect so it may return a clean-up function, like:

import React from 'react';

export function Test(): JSX.Element {
  const [counter, setCounter] = React.useState(0);

  React.useEffect(() => {
    const interval = setInterval(() => {
      setCounter(counter + 1);
    }, 1000);

    return () => clearInterval(interval);
  });

  return <div>{counter}</div>;
}
Related