我正在使用enzyme
和jest
测试一个应用,该应用在挂载后一定时间后会更新state
和DOM
(使用setTimout()
) 。但是,如何确定时间已经过去并执行检查?
我尝试使用jest.advanceTimersByTime()
,但它给了我警告。 Warning: An update to %s inside a test was not wrapped in act(...).
所以我只是这样做了,但仍然没有任何改变。
const someComponents = () => {
return (<div className="child"></div>);
}
const App = () => {
const [remove, setRemove] = useState(false);
setTimeout(() => setRemove(true), 5000);
return (
<div className="App">
{ remove &&
<someComponent/>
}
</div>
);
};
关于我的测试:
import React from 'react';
import ReactDOM from 'react-dom';
import { act } from 'react-dom/test-utils';
import { mount } from 'enzyme';
describe('test', () => {
it('should remove child at end of timer', () => {
const wrapper = mount(<App />);
expect(wrapper.find('.child')).toHaveLength(1);
act(() => {
jest.advanceTimersByTime(1000000);
wrapper.update(); //Do I need this?
console.log(wrapper.debug())// Still shows child in DOM
expect(wrapper.find('.child')).toHaveLength(0);
});
};
}
5秒后someComponent
应该已经卸载,但是在我尝试对其进行测试时仍然存在。另外,访问remove
和setRemove
的正确方法是什么用酵素?将enzyme
与react hooks
一起使用的信息很少。
答案 0 :(得分:0)
似乎存在一个问题,即当前的测试库(目前)无法正确处理useEffect
,因此测试将始终失败。您可以找到当前跟踪的问题here。
附带说明,您的钩子示例需要使用useEffect
才能起作用。
import React, { useState, useEffect } from "react";
const Example = () => <div className="child">child</div>;
const App = () => {
const [showChild, setShowChild] = useState(true);
useEffect(() => {
const timer = setTimeout(() => setShowChild(false), 5000);
return () => {
clearTimeout(timer);
};
}, []);
return <div className="App">{showChild && <Example />}</div>;
};
export default App;
工作示例:
也就是说,一种解决方法是暂时使用类。
这是一个展示钩子问题的本地示例和一个工人阶级的示例:https://github.com/mattcarlotta/hooks-versus-classes
要安装:
git clone git@github.com:mattcarlotta/hooks-versus-classes.git
并输入。cd hooks-versus-classes
。yarn install
或npm install
。yarn test
或npm run test
来运行测试(它们全部通过,但是one会抛出console.error
,并且断言为不是功能正常)。yarn dev
或npm run dev
来运行项目。工作类代码示例:
App.js
import React, { Component } from 'react';
const Example = () => <div className="child">child</div>;
class App extends Component {
state = { showChild: true };
componentDidMount = () => this.setTimer(); // setup timeout on mount
componentWillUnmount = () => this.clearTimer(); // remove timeout in case of component unmount
clearTimer = () => clearTimeout(this.timeout); // clear timeout
timer = () => this.setState({ showChild: false }, () => this.clearTimer()); // update state and clear timeout
setTimer = () => (this.timeout = setTimeout(this.timer, 5000)); // setup a 5s timeout
render = () => <div>{this.state.showChild && <Example />}</div>;
}
export default App;
App.test.js
import App from './App';
describe('App', () => {
it('initially renders a child component', () => {
expect(wrapper.find('.child')).toHaveLength(1);
});
it('removes child component after a 5 second timeout', () => {
jest.advanceTimersByTime(5000);
expect(wrapper.find('.child')).toHaveLength(0);
});
});