首页 > 解决方案 > 开玩笑测试 useInterval React Hook 不起作用

问题描述

试图测试自定义 useInterval Hook 但 jest.advanceTimersByTime(199);似乎 jest.advanceTimersToNextTimer(1);没有工作。

我在任何地方登录jest.getTimerCount(),它返回 0;

自定义挂钩:

import { useRef, useEffect } from 'react';

function useInterval(callback: () => void, delay: number | null) {
  const savedCallback = useRef<() => void | null>();

  // Remember the latest callback.
  useEffect(() => {
    savedCallback.current = callback;
  });

  // Set up the interval.
  useEffect(() => {
    function tick() {
      console.log("here"); // This never gets logged !!!!
      if (typeof savedCallback?.current !== 'undefined') {
        console.log(delay, savedCallback);
      }
    }

    if (delay !== null) {
      const id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
}

export default useInterval;

测试:

import useInterval from "./useInterval";
import { renderHook } from '@testing-library/react-hooks';


describe("useInterval Hook:", () => {
  let callback = jest.fn();


  beforeAll(() => {
    // we're using fake timers because we don't want to
    // wait a full second for this test to run.
    jest.useFakeTimers();
  });

  afterEach(() => {
    callback.mockRestore();
    jest.clearAllTimers();
  });

  afterAll(() => {
    jest.useRealTimers();
  });


  test('should init hook with delay', () => {
    const { result } = renderHook(() => useInterval(callback, 5000));

    expect(result.current).toBeUndefined();
    expect(setInterval).toHaveBeenCalledTimes(1);
    expect(setInterval).toHaveBeenCalledWith(expect.any(Function), 5000);
  });


  test('should repeatedly calls provided callback with a fixed time delay between each call', () => {
    const { result } = renderHook(() => useInterval(callback, 200));
    expect(callback).not.toHaveBeenCalled();

    // fast-forward time until 1s before it should be executed
    jest.advanceTimersByTime(199);
    expect(callback).not.toHaveBeenCalled(); // FAILS

    // jest.getTimerCount() here returns 0

    // fast-forward until 1st call should be executed
    jest.advanceTimersToNextTimer(1);
    expect(callback).toHaveBeenCalledTimes(1);

    // fast-forward until next timer should be executed
    jest.advanceTimersToNextTimer();
    expect(callback).toHaveBeenCalledTimes(2);

    // fast-forward until 3 more timers should be executed
    jest.advanceTimersToNextTimer(3);
    expect(callback).toHaveBeenCalledTimes(5);
  });
});

标签: reactjsjestjsreact-hooks

解决方案


我通过移动jest.useFakeTimers();beforeEach块而不是beforeAll.


推荐阅读