如何使用玩笑和反应测试库测试反应组件内的异步逻辑?

时间:2021-01-19 02:52:17

标签: javascript reactjs typescript unit-testing asynchronous

摘要/TLDR

  • 在下面的测试规范代码中,如何根据 React 测试最佳实践成功实现 setTimeout() 函数内部的异步逻辑?
// This test always returns true because the assertions wrapped inside setTimeout() never fire.
it('is clear this code does not work, so how can I implement the same "logic" correctly?', () => {
  const timer = screen.getByTestId('a timer that counts all positive integers from 0 to +Infinity once a user clicks on the DOM.')
  fireEvent.click(timer)
  setTimeout(() => {
    // I want the test runner to wait at least 1 second before making the assertion that the component incremented from 0 to 1.
    const time = Number(timer.textContent)
    expect(time).toBeGreaterThan(0)
  }, 1100)
})

说明

  • 我正在 React 中构建一个带有计时器的组件。
  • 我想编写一个测试,断言计时器在组件中的一个单元格启动时开始计数 点击。
  • 每次启动新游戏时,gameProgress 都会重置。默认情况下,它设置为 newGame,但当用户点击 <Cell/> 时,游戏状态会通过 InProgress 更新为 React.Context

问题

  • 包裹在 setTimeout() 中的代码永远不会运行。我相信 Jest 会忽略此块中的代码。
  • 我假设我需要实现一些其他方法,或者是来自 React 测试库的异步方法,例如 waitFor(),或者可能是使用 jest Timer Mocks。但是,我尝试了这两种想法,但都没有奏效。

测试代码

// TopPanel.test.tsx
it('should start counting if the user clicks on a blank cell', () => {
  render(<TopPanel/>)

  // the <Cell/> component is handled elsewhere in the ReactDOM engine
  const cell = screen.getByTestId('0-0')

  fireEvent.click(cell)

  // I want to assert that the timer hits 1 after 1100 milliseconds; I only count seconds as integers.
  setTimeout(() => {
    expect(time).toBeGreaterThan(0)
  }, 1100)
})

组件代码

// TopPanel.tsx
export default function TopPanel() {
  const { gameProgress } = useGameContext()
  const [time, setTime] = React.useState(0)

  useEffect(() => {
    if (gameProgress === GameProgress.NewGame) setTime(0)
    if (gameProgress === GameProgress.InProgress) {
      const interval = setInterval(() => setTime(time + 1), 1000)
      return () => clearInterval(interval)
    }
  })
  
  return (
    <>
      <div data-testid='topPanel'>
        <div>Timer: <span data-testid='timer'>{time}</span></div>
      </div>
    </>
  )
}

0 个答案:

没有答案