这是我的自定义 React-hook。
import { useEffect, useRef } from 'react'
function useInterval({ callback, interval, delay }) {
const savedTimerId = useRef<NodeJS.Timeout>()
useEffect(() => {
const loop = () => {
const res = callback()
const nextIteration = () => {
savedTimerId.current = setTimeout(loop, interval)
}
if (res instanceof Promise) {
res.then(nextIteration)
} else {
nextIteration()
}
}
let delayedTimerId: NodeJS.Timeout
if (!delay) {
loop()
} else {
delayedTimerId = setTimeout(loop, delay)
}
return () => {
// @ts-ignore
clearTimeout(savedTimerId.current)
if (delayedTimerId) {
clearTimeout(delayedTimerId)
}
}
}, [callback, interval, delay])
}
export { useInterval }
这是单元测试
import { renderHook } from '@testing-library/react-hooks'
import { useInterval } from '../useInterval'
describe("Test scenarios for 'useInterval' hook", () => {
jest.useFakeTimers()
it("Should call 'callback' once", () => {
const callback = jest.fn()
const interval = 10000
const params = { callback, interval }
renderHook(() => useInterval(params))
expect(setTimeout).toHaveBeenCalledTimes(1)
expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), interval)
})
})
但这就是输出
Error: expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 2
我调试了这个片段。我发现在 useInterval
调用之前,某些东西已经触发了 setTimeout
。
似乎已在内部调用了setTimeout
。我做错了什么?有什么想法吗?
最佳答案
你说得对,@testing-library/react-hooks
正在后台调用setTimeout
,你可以通过以下方式确认这一点:
jest.useFakeTimers()
renderHook(() => {})
expect(setTimeout).toHaveBeenCalledTimes(1)
您可能最好关注调用 callback
的次数,而不是 setTimeout
:
afterEach(() => {
jest.clearAllMocks();
jest.useRealTimers();
});
describe("Test scenarios for 'useInterval' hook", () => {
it("Should call 'callback' immediately", () => {
jest.useFakeTimers()
const callback = jest.fn()
const interval = 10000
const params = { callback, interval }
renderHook(() => useInterval(params))
expect(callback).toHaveBeenCalledTimes(1)
})
it("Should call 'callback' repeatedly", () => {
jest.useFakeTimers()
const callback = jest.fn()
const interval = 10000
const params = { callback, interval }
renderHook(() => useInterval(params))
jest.advanceTimersByTime(interval * 2)
// Expect 3 calls: 1 immediate call and 2 interval calls:
expect(callback).toHaveBeenCalledTimes(3)
})
})
关于reactjs - @testing-library/react-hooks 调用 setTimeout 两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63369917/