dimanche 7 mars 2021

How to test a delayed event handler in jest?

I've got a function that should be get executed in near future and I want to test it with jest but have no idea how to do this properly. Actually, I'm using React + testing react library but that doesn't change anything I suppose.
Here's the function itself:

let start;
const holdClick = (el, delayedClickHandler, time = 0) => {
  if (time === 0) return delayedClickHandler();
  let counter = 0;
  function countToExecute() {
    if (counter === time) delayedClickHandler();
    else {
      start = requestAnimationFrame(countToExecute);
      counter += 1;
    }
  }

  start = window.requestAnimationFrame(countToExecute);

  el.ontouchend = () => {
    window.cancelAnimationFrame(start);
  };
};

My Component

function Component() {
  const [clicked, setClicked] = useState(false);

  return (
    <span
      // data attribute must be changed to "active" after 30 ticks
      data-testid={clicked ? 'active' : 'static'}
      onTouchStart={e => holdClick(e.target, () => setClicked(true), 30)}
    >
      click me
    </span>
  );
}

And my test

test('execute delayed click', () => {
  beforeEach(() => {
    jest.spyOn(window, 'requestAnimationFrame').mockImplementation(cb => cb());
  });

  const { getByTestId } = render(<App />);
  const el = getByTestId('static');

  fireEvent.click(el);

  jest.useFakeTimers();
  setTimeout(() => {
    expect(el).toHaveAttribute('data-testid', 'active');
  }, 10000);
  jest.runAllTimers();
});

My guess is that the problem lays in requestAnimationFrame but as I've mentioned before, I'm pretty much clueless of any ways to fix this. I've tried to add jest.spyOn(window, 'requestAnimationFrame').mockImplementation(cb => cb()); but it didn't change anything. So I'm wondering if there's a solution that doesn't require a troublesome mock of window object.

Aucun commentaire:

Enregistrer un commentaire