如何在使用 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));
// [...]
});
我正在我的单页应用程序的集成测试中呈现该组件,并尝试遵循从登陆页面到测验/记忆游戏的第一个问题的快乐路径。
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));
// [...]
});