如何在使用 React 测试库的集成测试中避免 "act" 警告

How to avoid "act" warnings in a integration tests with React Testing Library

我正在我的单页应用程序的集成测试中呈现该组件,并尝试遵循从登陆页面到测验/记忆游戏的第一个问题的快乐路径。

Warning: An update to GamePlay inside a test was not wrapped in act(...).

第二行是触发多个警告的...

    const firstItem = getAllByRole("listitem")[0]
    userEvent.click(firstItem)

它单击列表中的第一个选项,导致游戏组件呈现。该组件显示一个单词 5000 毫秒,然后使用在组件的 useEffect 挂钩(如下)中设置的 setTimeout 隐藏它。此例程中还禁用和启用了答案输入字段。

    function hideQuestion() {
        setInputDisabled(false)
        setDisplayWord(false)
    }

    const [displayWord, setDisplayWord]= useState(true);

    useEffect(()=>{
        setTimeout(hideQuestion, 5000)
    },[displayWord])

    const [inputDisabled, setInputDisabled] = useState(true);

通过阅读,我认为这可能是 setTimeout 的使用造成的,但 none 我尝试过的缓解措施都起到了作用。我尝试将点击行包装在一个“act”函数中,但什么也没做。我尝试使测试异步并等待该行,但同样什么也没做 - 我仍然收到此错误(以及几个类似的错误)...

  console.error
    Warning: An update to GamePlay inside a test was not wrapped in act(...).
    
    When testing, code that causes React state updates should be wrapped into act(...):
    
    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */
    
    This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
        at GamePlay (/home/user/code/spellingapp/src/components/GamePlay.js:3:20)
        at MainPage (/home/user/code/spellingapp/src/components/MainPage.js:8:29)
        at Route (/home/user/code/spellingapp/node_modules/react-router/cjs/react-router.js:470:29)
        at Switch (/home/user/code/spellingapp/node_modules/react-router/cjs/react-router.js:676:29)
        at Router (/home/user/code/spellingapp/node_modules/react-router/cjs/react-router.js:99:30)
        at BrowserRouter (/home/user/code/spellingapp/node_modules/react-router-dom/cjs/react-router-dom.js:67:35)
        at App (/home/user/code/spellingapp/src/App.js:16:29)

       5 |   function hideQuestion() {
       6 |     // console.log("I have hidden the word and enabled the text box")
    >  7 |     setInputDisabled(false)

我试过阅读这篇文章:https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning

但我很难完全理解它并将其与我自己的代码联系起来。我认为它的要点是当出现“意外”状态变化时你会收到这些警告,但我看不出我应该如何让我的预期。我的应用程序是一款实时游戏,因此整个 运行 关闭计时器 - 一个计时器结束,另一个开始。我不想 运行 玩整整 10 分钟的游戏才能顺利完成。我只想测试从登录页面到第一次交互作为核心集成逻辑的冒烟测试。

现在我能想到的就是制作一个只有一个问题的测试夹具,这样我就可以 运行 整个游戏端到端,但是当我当前的测试 运行 很好(除了警告)并且我现在想要它做的一切。我将不胜感激任何指示或建议,即使我只是找错了树。谢谢!

您可以执行以下几项操作:

  • 警告告诉您您的应用程序在测试完成后继续,因此在 运行 期间发生了您没有签入测试也没有等待的其他事情。因此,如果您对正在测试的内容感到满意,请注意并保持这种状态。
  • 您可以通过提供选项使您的应用更易于测试。例如,你可以有一个可选的 prop 指示在计时器中等待的时间量,这样你就可以在你的测试中将它设置为 0 或一个小数字。
  • 您可以模拟计时器:
beforeEach(jest.useFakeTimers);
afterEach(jest.useRealTimers);

test("your game", async () => {
  const { getAllByRole } = render(<Game />);
  // [...]
  const firstItem = getAllByRole("listitem")[0]
  userEvent.click(firstItem)
  act(() => jest.advanceTimersByTime(5000));
  // [...]
  act(() => jest.advanceTimersByTime(5000));
  // [...]
});