【发布时间】:2019-07-29 13:27:16
【问题描述】:
我的 React 应用程序有一个从远程服务器获取数据以显示的组件。在 pre-hooks 时代,componentDidMount() 是个好去处。但现在我想为此使用钩子。
const App = () => {
const [ state, setState ] = useState(0);
useEffect(() => {
fetchData().then(setState);
});
return (
<div>... data display ...</div>
);
};
我使用 Jest 和 Enzyme 的测试如下所示:
import React from 'react';
import { mount } from 'enzyme';
import App from './App';
import { act } from 'react-test-renderer';
jest.mock('./api');
import { fetchData } from './api';
describe('<App />', () => {
it('renders without crashing', (done) => {
fetchData.mockImplementation(() => {
return Promise.resolve(42);
});
act(() => mount(<App />));
setTimeout(() => {
// expectations here
done();
}, 500);
});
});
测试成功,但记录了一些警告:
console.error node_modules/react-dom/cjs/react-dom.development.js:506
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 */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser. Learn more at (redacted)
in App (created by WrapperComponent)
in WrapperComponent
App 组件的唯一更新发生在 Promise 回调中。我如何确保这发生在 在 act 块内?文档明确建议在act 块外部进行断言。此外,将它们放在里面不会改变警告。
【问题讨论】:
-
此代码将调用
fetchData两次,如果fetchData返回不同的数据则进入无限循环。您应该将[]作为第二个参数传递给useEffect以模拟componentDidMount。否则每次渲染都会调用useEffect。首先fetchData导致重新渲染。每当setState获得新值时,它都会导致额外的渲染。 -
我不确定,但github.com/threepointone/react-act-examples 看起来很有希望
-
感谢@UjinT34 的评论。事实上,我有
[]作为部门,但认为它与这个特定问题无关。事实上,它应该在那里防止过于频繁地调用fetchData。尽管如此,关于不使用act的警告仍然存在:( -
感谢@skyboyer 的建议。您提到的回购的重点是他们使用“手动”模拟,他们可以手动解决 - 在
act语句中。我更喜欢使用 Jests 模拟可能性。我的感觉是,从 Jest 模拟中解决 Promise 发生在act之外,从而触发了警告。但我不知道如何解决。
标签: reactjs jestjs enzyme react-hooks react-test-renderer