开玩笑:setTimeout 被调用了太多次

Rhi*_*omb 3 unit-testing timer reactjs jestjs react-hooks

我正在测试一个react使用setTimeout. 问题是,即使它显然不是Jest,也setTimeout被调用了。setTimeout当鼠标悬停在组件上时,有一个用于从 ui 中删除某些内容,另一个用于暂停计时器。

我尝试添加一个console.log()where the setTimeoutis 并且从不调用控制台日志,这意味着没有调用应用程序中的 setTimeout 。

//app
const App = (props) => {
  const [show, setShow] = useState(true);
  const date = useRef(Date.now());
  const remaining = useRef(props.duration);

  let timeout;
  useEffect(() => {
    console.log('Should not run');
    if (props.duration) {
      timeout = setTimeout(() => {
        setShow(false)
      }, props.duration);
    }
  }, [props.duration]);

  const pause = () => {
    remaining.current -= Date.now() - date.current;
    clearTimeout(timeout);
  }

  const play = () => {
    date.current = Date.now();
    clearTimeout(timeout);
    console.log('should not run');
    timeout = setTimeout(() => {
      setIn(false);
    }, remaining.current);
  }

  return (
    <div onMouseOver={pause} onMouseLeave={play}>
      { show &&
        props.content
      }
    </div>
  )
}
Run Code Online (Sandbox Code Playgroud)
//test
it('Should not setTimeout when duration is false', () => {
  render(<Toast content="" duration={false} />);
  //setTimeout is called once but does not come from App
  expect(setTimeout).toHaveBeenCalledTimes(0);
});

it('Should pause the timer when pauseOnHover is true', () => {
    const { container } = render(<Toast content="" pauseOnHover={true} />);

  fireEvent.mouseOver(container.firstChild);
  expect(clearTimeout).toHaveBeenCalledTimes(1);
  fireEvent.mouseLeave(container.firstChild);

  //setTimeout is called 3 times but does not come from App
  expect(setTimeout).toHaveBeenCalledTimes(1);
});


Run Code Online (Sandbox Code Playgroud)

所以在第一个测试中,setTimeout不应该被调用,但我收到它被调用过一次。在第二次测试中,setTimeout应该被调用一次,但被调用了 3 次。该应用程序运行良好,我只是不明白这是怎么回事,jest暗示setTimeout被调用的次数多于实际情况。

小智 5

我的第一个 Jest 测试总是调用setTimeout一次(没有我的组件触发它),我遇到了完全相同的问题。通过记录这个“未知”setTimeout调用的参数,我发现它是用一个_flushCallback函数和延迟调用的0

查看react-test-renderer显示的存储库,此处_flushCallback定义了一个函数。在这里是清楚的部分指出,它使用时,它在非DOM环境中运行(这样做玩笑测试时是如此)。Scheduler_flushCallbacksetTimeout

我不知道如何正确地继续研究这个,就目前而言,似乎setTimeout调用次数的测试是不可靠的。