无法让React Hook setInterval Timer在JestEnzyme测试期间运行。

问题描述 投票:0回答:1

我正试图为这个组件写总结写一些测试。我实现了一个自定义的 useInterval 钩子继丹-阿布拉莫夫的这篇博文(编码). 它基本上使一个声明式的 setInterval 的功能,但我很难用Jest和Enzyme来测试。然而,我很难用Jest和Enzyme来测试它。该应用程序是用create-react-app引导的。我已经安装了最新的版本。当我点击开始按钮时,经过的时间增加并完美地显示在页面上。在父组件中,我更新了状态,它存储了经过的时间。它将更新后的经过时间 timer 赞成 Timer.js. 因此,它在屏幕上播种了正确的。elapsedTime. 这在浏览器中可以正常工作。然而,在运行测试时,定时器没有运行。

// Timer.js
const TimerDisplay = ({ timer, updateTimer }) => {

  useInterval(() => {
    const delta = Math.floor((Date.now() - timer.offsetTime) / 1000);
    updateTimer({ ...timer, elapsedTime: delta });

  }, timer.isTicking ? 300 : null);

  const handleStartButton = () => {
    updateTimer({ ...timer, isTicking: true });
  }

  return (
    <React.Fragment>
      <div>{timer.elapsedTime}</div>
      <button className='start' onClick={() => handleStartButton()}>Start</button>
      <button className='stop' {/* removed for brevity*/}>Stop</button>
    </React.Fragment>
  );
};

测试的代码如下。我使用了Jest的spy函数和enzyme的mount。我读到我需要挂载,而不是因为钩子而使用浅层。我设置Jest使用假的计时器。然后,我模拟按下启动按钮,以验证按钮是否正常工作。然而,在这个测试中,我已经设置了 isTicking: true 所以我真的不需要模拟启动。虽然这是一个理智的检查,以确保函数spy按预期工作--它确实是这样。预期的结果是,它在300毫秒后调用spy回调。因此,当我 jest.advanceTimersByTime(500)监视函数应该至少有一次在 useInterval 回调。然而,在测试中却没有发生这种情况。

// Timer.spec.js
describe('Timer', () => {
  const spyFunction = jest.fn();

  const timer = {
    offsetTime: new Date(),
    isTicking: true,
    elapsedTime: 0
  };

  let wrapper = null;

  beforeEach(() => {
    wrapper = mount(<Timer updateTimer={spyFunction} timer={timer} />);
  });

  afterEach(() => {
    wrapper.unmount();
    wrapper = null;
  });

  it('timer should run', () => {
    jest.useFakeTimers();

    expect(spyFunction).not.toHaveBeenCalled();

    wrapper.find('button.start').simulate('click', { button: 0 });

    // works as expected
    expect(spyFunction).toHaveBeenCalled();

    // doesn't seem to work for some reason
    jest.advanceTimersByTime(500);

    // will fail; function only called once by the button.start. It should have been called at least twice.
    expect(spyFunction).toHaveBeenCalledTimes(2);
  });
});

我想这个问题应该是与 useInterval 钩子。我怀疑垃圾收集是在回调被调用之前发生的。有什么方法可以测试 useInterval 钩子的回调 updateTimer 又名 Jest.Fn?

// useInterval hook
import { useEffect, useRef } from 'react';

export const useInterval = (callback, delay) => {
  const savedCallback = useRef();

  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null) {
      let id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
};
reactjs jestjs react-hooks enzyme create-react-app
1个回答
1
投票

问题是 jest.useFakeTimers();更确切地说,是在你所谓的一个地方。您正在将您的组件安装在 beforeEach,在你伪造计时器之前。正因为如此,你的 useInterval 钩子的设置是为了使用真正的 setInterval,而不是开玩笑时的假上。当你打电话的时候 jest.useFakeTimers(); 太晚了,因为它不会影响任何东西(你没有创建任何与定时器相关的新东西)。

如果你把它移到 mountbeforeEach 测试就可以了。

© www.soinside.com 2019 - 2024. All rights reserved.