何时使用 waitForNextUpdate 而不是 act + jest.advanceTimersByTime?

sli*_*wp2 8 reactjs jestjs react-hooks react-hooks-testing-library

Advanced-hooks#async文档上有一个示例。

\n

我对如何waitForNextUpdate运作感到困惑。我做了两个测试用例来比较waitForNextUpdateact()+ jest.advanceTimersByTime()

\n

index.ts:

\n
import { useState, useCallback } from \'react\';\n\nexport function useCounter(initialValue = 0) {\n  const [count, setCount] = useState(initialValue);\n  const increment = () => setCount((x) => x + 1);\n  const incrementAsync = useCallback(() => setTimeout(increment, 100, [increment]);\n  const reset = useCallback(() => setCount(initialValue), [initialValue]);\n  return { count, increment, incrementAsync, reset };\n}\n
Run Code Online (Sandbox Code Playgroud)\n

index.test.ts:

\n
import { renderHook, act } from \'@testing-library/react-hooks\';\nimport { useCounter } from \'./\';\n\njest.setTimeout(5 * 1000);\n\ndescribe(\'waitForNextUpdate  V.S. jest-advancedTimersByTime\', () => {\n  test(\'should pass by using jest.advancedTimersByTime\', () => {\n    jest.useFakeTimers();\n    const { result } = renderHook(() => useCounter());\n    result.current.incrementAsync();\n    act(() => {\n      jest.advanceTimersByTime(100);\n    });\n    expect(result.current.count).toBe(1);\n    jest.useRealTimers();\n  });\n\n  test(\'should pass by using waitForNextUpdate\', async () => {\n    const { result, waitForNextUpdate } = renderHook(() => useCounter());\n    result.current.incrementAsync();\n    await waitForNextUpdate();\n    expect(result.current.count).toBe(1);\n  });\n});\n
Run Code Online (Sandbox Code Playgroud)\n

测试结果:

\n
 PASS  issues/waitForNextUpdate-vs-jest-advancedTimersByTime/index.test.ts\n  waitForNextUpdate  V.S. jest-advancedTimersByTime\n    \xe2\x9c\x93 should pass by using jest.advancedTimersByTime (13 ms)\n    \xe2\x9c\x93 should pass by using waitForNextUpdate (107 ms)\n\nTest Suites: 1 passed, 1 total\nTests:       2 passed, 2 total\nSnapshots:   0 total\nTime:        1.373 s, estimated 14 s\n
Run Code Online (Sandbox Code Playgroud)\n

两个测试用例都通过。setTimeout我发现的唯一区别是,如果我增加to的延迟1000 * 10,使用的测试用例waitForNextUpdate将会失败。

\n
import { useState, useCallback } from \'react\';\n\nexport function useCounter(initialValue = 0) {\n  const [count, setCount] = useState(initialValue);\n  const increment = () => setCount((x) => x + 1);\n  const incrementAsync = useCallback(() => setTimeout(increment, 100, [increment]);\n  const reset = useCallback(() => setCount(initialValue), [initialValue]);\n  return { count, increment, incrementAsync, reset };\n}\n
Run Code Online (Sandbox Code Playgroud)\n
// first test case\n// ...\njest.advanceTimersByTime(1000 * 10);\n// ...\n
Run Code Online (Sandbox Code Playgroud)\n
import { renderHook, act } from \'@testing-library/react-hooks\';\nimport { useCounter } from \'./\';\n\njest.setTimeout(5 * 1000);\n\ndescribe(\'waitForNextUpdate  V.S. jest-advancedTimersByTime\', () => {\n  test(\'should pass by using jest.advancedTimersByTime\', () => {\n    jest.useFakeTimers();\n    const { result } = renderHook(() => useCounter());\n    result.current.incrementAsync();\n    act(() => {\n      jest.advanceTimersByTime(100);\n    });\n    expect(result.current.count).toBe(1);\n    jest.useRealTimers();\n  });\n\n  test(\'should pass by using waitForNextUpdate\', async () => {\n    const { result, waitForNextUpdate } = renderHook(() => useCounter());\n    result.current.incrementAsync();\n    await waitForNextUpdate();\n    expect(result.current.count).toBe(1);\n  });\n});\n
Run Code Online (Sandbox Code Playgroud)\n

waitForNextUpdate那么和act()+之间有什么区别jest.advanceTimersByTime()?什么样的场景我只能使用waitForNextupdate而不是act()+ jest.advanceTimersByTime()

\n

软件包版本:

\n
 PASS  issues/waitForNextUpdate-vs-jest-advancedTimersByTime/index.test.ts\n  waitForNextUpdate  V.S. jest-advancedTimersByTime\n    \xe2\x9c\x93 should pass by using jest.advancedTimersByTime (13 ms)\n    \xe2\x9c\x93 should pass by using waitForNextUpdate (107 ms)\n\nTest Suites: 1 passed, 1 total\nTests:       2 passed, 2 total\nSnapshots:   0 total\nTime:        1.373 s, estimated 14 s\n
Run Code Online (Sandbox Code Playgroud)\n

Phi*_*cks 0

waitForNextUpdate与时间无关,与你的钩子状态有关

由于状态更新在等待 waitForNextUpdate() 期间异步发生,因此无需将incrementAsync 包装在act() 中。异步实用程序自动将等待代码包装在异步 act() 包装器中。

Jest 的advanceTimersByTime利用实际情况setTimeoutsetInterval实例:

调用此 API 时,所有计时器都会提前 msToRun 毫秒。所有已通过 setTimeout() 或 setInterval() 排队并在此时间范围内执行的待处理“宏任务”都将被执行。