【问题标题】:How to avoid "act" warnings in a integration tests with React Testing Library如何在使用 React 测试库的集成测试中避免“行为”警告
【发布时间】:2021-03-23 14:37:52
【问题描述】:

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

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 的这种使用是负责任的,但我尝试过的任何缓解措施都没有做任何事情。我尝试将点击线包装在“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 分钟的游戏,所以它可以整齐地完成。我只是想测试从登陆页面到第一次交互作为核心集成逻辑的冒烟测试。

现在我能想到的就是制作一个只有一个问题的测试夹具,这样我就可以端到端地运行整个游戏,但是当我当前的测试运行良好(除了警告之外)并且确实如此时,这似乎有点过头了我想要它现在做的一切。我将不胜感激任何指示或建议,即使我只是在吠叫错误的树。谢谢!

【问题讨论】:

  • userEvent.click 行后面有什么?愿意分享触发警告的完整测试吗?
  • @juliomalves - 没有别的了。嗯,有,但我把它全部注释掉了,错误仍然存​​在。在接下来的几行中,我只会得到更多相同类型的警告。测试本身完成并通过。

标签: javascript reactjs react-testing-library


【解决方案1】:

您可以做以下几件事:

  • 警告告诉您,您的应用程序在您的测试完成后继续运行,因此在运行期间发生了您没有签入测试并且没有等待的其他事情。因此,如果您对所测试的内容感到满意,请注意并保持这种状态。
  • 您可以通过为其提供选项来使您的应用更具可测试性。例如,您可以有一个可选的道具来指示计时器中的等待时间,这样您就可以在测试中将其设置为 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));
  // [...]
});

【讨论】:

  • 所以我写了一个测试夹具来缩短游戏时间,我扩展了我的测试一直玩到最后。一旦我完成了将AdvanceTimers 函数放入“act”函数中就可以了。非常感谢您的帮助!
猜你喜欢
  • 2019-12-11
  • 2021-03-11
  • 2020-01-06
  • 2011-09-16
  • 2015-12-15
  • 1970-01-01
  • 2021-04-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多