警告:测试中对 App 的更新未包含在酶和钩子中的 act(...) 中
Posted
技术标签:
【中文标题】警告:测试中对 App 的更新未包含在酶和钩子中的 act(...) 中【英文标题】:Warning: An update to App inside a test was not wrapped in act(...) in enzyme and hooks 【发布时间】:2020-12-13 16:00:43 【问题描述】:我已经编写了这个组件。它使用钩子和状态获取数据。获取后,加载状态将更改为 false 并显示侧边栏。
我在使用 Jest 和 Enzyme 时遇到了问题,因为它确实在我的单元测试中对 Act 发出了警告。一旦我将行为添加到我的笑话和酶中,测试就失败了!
// @flow
import React, useEffect, useState from 'react';
import Sidebar from '../components/Sidebar';
import fetchData from '../apiWrappers/fetchData';
const App = () =>
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() =>
const getData = async () =>
try
const newData = await fetchData();
setData(newData);
setLoading(false);
catch (e)
setLoading(false);
;
getData();
// eslint-disable-next-line
, []);
return (
<>
!loading
? <Sidebar />
: <span>Loading List</span>
</>
);
;
export default App;
而且,我添加了一个这样的测试,效果很好。
import React from 'react';
import mount from 'enzyme';
import fetchData from '../apiWrappers/fetchData';
import data from '../data/data.json';
import App from './App';
jest.mock('../apiWrappers/fetchData');
const getData = Promise.resolve(data);
fetchData.mockReturnValue(getData);
describe('<App/> Rendering using enzyme', () =>
beforeEach(() =>
fetchData.mockClear();
);
test('After loading', async () =>
const wrapper = mount(<App />);
expect(wrapper.find('span').at(0).text()).toEqual('Loading List');
const d = await fetchData();
expect(d).toHaveLength(data.length);
wrapper.update();
expect(wrapper.find('span').exists()).toEqual(false);
expect(wrapper.html()).toMatchSnapshot();
);
);
所以,我收到了警告:
Warning: An update to App 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 */
);
我确实使用 act react-dom/test-utils 解决了这样的警告。
import React from 'react';
import act from 'react-dom/test-utils';
import mount from 'enzyme';
import fetchData from '../apiWrappers/fetchData';
import data from '../data/data.json';
import App from './App';
jest.mock('../apiWrappers/fetchData');
const getData = Promise.resolve(data);
fetchData.mockReturnValue(getData);
describe('<App/> Rendering using enzyme', () =>
beforeEach(() =>
fetchData.mockClear();
);
test('After loading', async () =>
await act(async () =>
const wrapper = mount(<App />);
expect(wrapper.find('span').at(0).text()).toEqual('Loading List');
const d = await fetchData();
expect(d).toHaveLength(data.length);
wrapper.update();
expect(wrapper.find('span').exists()).toEqual(false);
expect(wrapper.html()).toMatchSnapshot();
);
);
);
但是,我的测试失败了。
<App/> Rendering using enzyme › After loading
expect(received).toEqual(expected) // deep equality
Expected: false
Received: true
35 |
36 | wrapper.update();
> 37 | expect(wrapper.find('span').exists()).toEqual(false);
有人知道为什么会失败吗?谢谢!
"react": "16.13.1",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.3",
【问题讨论】:
哇,那里的运行代码 sn-ps 的问题很好!为此投票! 【参考方案1】:这个问题一点也不新鲜。你可以在这里阅读完整的讨论:https://github.com/enzymejs/enzyme/issues/2073。
总而言之,目前为了修复act
警告,您必须稍等片刻才能更新您的包装器,如下所示:
const waitForComponentToPaint = async (wrapper) =>
await act(async () =>
await new Promise(resolve => setTimeout(resolve));
wrapper.update();
);
;
test('After loading', async () =>
const wrapper = mount(<App />);
expect(wrapper.find('span').at(0).text()).toEqual('Loading List');
// before the state updated
await waitForComponentToPaint(wrapper);
// after the state updated
expect(wrapper.find('span').exists()).toEqual(false);
expect(wrapper.html()).toMatchSnapshot();
);
【讨论】:
感谢您的评论,我实际上已经阅读了链接。而且,我刚刚尝试了您的代码。但是,即使在使用代码之后,我也会收到相同的警告。绕过它的唯一方法是将我的整个测试包装成这样的行为。test.only('After loading', async () => await act(async () => /* the actual test */ ););
但这太过分了!!我在<App />
中使用useEffect
,这可能是个问题。我已经看到了这条评论github.com/enzymejs/enzyme/issues/2073,但是为我实现它很复杂。你有什么其他建议可以在不包装我的每一个测试的情况下完成吗?
尝试增加超时时间await new Promise(resolve => setTimeout(resolve, 20));
看看是否有帮助?
或者你也可以尝试将上面的代码包装在act()
我猜
我已经尝试将时间增加到 100,但仍然收到警告。如果我将上面的代码包装在行为中,我会得到另一个警告。到目前为止它工作的唯一方法是这样的:stackblitz.com/edit/react-act-warning-with-enzyme?file=src/… 但是,我不想对每一个测试都这样做,它有点太多而且有点混乱。你知道无论如何我可以简化它吗? :)
我认为我们不一定要使用 wait-for-expect
来使其工作 :) 你是否有可以重现问题的最小代码(可能是一个小仓库)?以上是关于警告:测试中对 App 的更新未包含在酶和钩子中的 act(...) 中的主要内容,如果未能解决你的问题,请参考以下文章
警告:无法在 React 本机中对未安装的组件执行 React 状态更新
[Vue 警告]:指令中的错误 intersect unbind 钩子:“TypeError:无法读取未定义的属性‘observer’”