Reactjs 用酶测试时,如何等待组件安装中的设置状态解决?
我试图测试一个React组件,它运行一些异步代码并在componentDidMount中调用setState 下面是我要测试的react组件:Reactjs 用酶测试时,如何等待组件安装中的设置状态解决?,reactjs,jestjs,enzyme,Reactjs,Jestjs,Enzyme,我试图测试一个React组件,它运行一些异步代码并在componentDidMount中调用setState 下面是我要测试的react组件: /** * * AsyncComponent * */ import React from 'react'; class AsyncComponent extends React.Component { constructor(props) { super(props); this.state = { loaded:
/**
*
* AsyncComponent
*
*/
import React from 'react';
class AsyncComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
loaded: false,
component: null,
};
}
componentDidMount() {
this.props.component.then(component => {
this.setState({
loaded: true,
component: component.default ? component.default : component,
});
});
}
render() {
if (!this.state.loaded) {
return null;
}
const Component = this.state.component;
const { component, ...rest } = this.props;
return <Component {...rest} />;
}
}
export default AsyncComponent;
/**
*
*异步组件
*
*/
从“React”导入React;
类AsyncComponent扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
加载:false,
组件:null,
};
}
componentDidMount(){
this.props.component.then(component=>{
这是我的国家({
是的,
component:component.default?component.default:component,
});
});
}
render(){
如果(!this.state.loaded){
返回null;
}
const Component=this.state.Component;
const{component,…rest}=this.props;
返回;
}
}
导出默认异步组件;
下面是测试用例。我在用玩笑和酶
import React from 'react';
import { mount } from 'enzyme';
import AsyncComponent from '../index';
const TestComponent = () => <div>Hello</div>;
describe('<AsyncComponent />', () => {
it('Should render loaded component.', () => {
const promise = Promise.resolve(TestComponent);
const rendered = mount(<AsyncComponent component={promise} />);
expect(rendered.state().loaded).toBe(true);
});
});
从“React”导入React;
从“酶”导入{mount};
从“../index”导入异步组件;
const TestComponent=()=>Hello;
描述(“”,()=>{
它('应该呈现加载的组件',()=>{
const promise=promise.resolve(TestComponent);
const rendered=mount();
expect(rendered.state().loaded).toBe(true);
});
});
测试失败,因为state.loaded仍设置为false。在调用expect之前,是否有办法确保AsyncComponent已完全加载
如果我将expect断言包装在setTimeout中,我可以让它工作,但这似乎是一种相当粗糙的方法。我应该怎么做呢?您需要通过使用
async/await
或从测试中返回承诺来通知jest有关承诺,请查看
描述(“”,()=>{
它('应该呈现加载的组件',async()=>{
const promise=promise.resolve(TestComponent);
const rendered=mount();
等待承诺
expect(rendered.state().loaded).toBe(true);
});
});
我遇到了同样的问题,我想出了一些笨拙的解决方案,我在componentDidMount中调用了一些函数,我想检查该函数是否已被调用,这样代码就适合我了
const loadFiltersTree = jest.fn()
const wrapper = shallow(<FilterTree loadFiltersTree={loadFiltersTree} />)
jest.useFakeTimers()
jest.runAllTimers()
setImmediate(() => {
expect(loadFiltersTree.mock.calls.length).toEqual(1)
})
const loadFiltersTree=jest.fn()
常量包装器=浅()
开玩笑
jest.runAllTimers()
setImmediate(()=>{
expect(loadFiltersTree.mock.calls.length).toEqual(1)
})
破坏承诺链是常见的反模式。根据经验,使用承诺的函数应该将结果承诺返回给链,除非这会导致问题。这保证了调用方函数链接承诺时不会出现竞争条件。其中一个原因是提高了可测试性。这也适用于生命周期挂钩,如componentDidMount
:
componentDidMount() {
return this.props.component.then(...)
}
jest.spyOn(AsyncComponent.prototype, 'componentDidMount');
const wrapper = mount(<AsyncComponent component={promise} />);
expect(wrapper.instance().componentDidMount).toHaveBeenCalledTimes(1);
await wrapper.instance().componentDidMount.mock.results[0].value;
expect(wrapper.state().loaded).toBe(true);
异步Jest测试应该链接所有正在使用的承诺并返回一个承诺<代码>异步..等待是一种实用的方法
在Ezyme中,浅层渲染允许禁用自动componentDidMount
调用并链接lifecycle hook返回的承诺:
const wrapper = shallowMount(<AsyncComponent component={promise} />,
{ disableLifecycleMethods: true });
await wrapper.instance().componentDidMount();
expect(wrapper.state().loaded).toBe(true);
我尝试使用您的代码,但测试失败,因为“rendered.state().loaded”仍然等于false。您可以检查承诺中的回调是否被调用吗?
promise.resolve(TestComponent)
立即与该组件解析。它与setState
和准备测试的组件无关。这段代码毫无意义,肯定不能解决所描述的问题。这是不正确的Promise.resolve()
不会立即计算,所有测试代码都将在调用componentDidMount
调用中的回调之前运行。为了更好地理解承诺的执行顺序,请查看:。第一个例子正好说明了这种情况。当然,async/await
看起来像是一个黑客,Jest团队正在考虑一个功能来解决所有的承诺,就像它对setTimeout
所做的那样,但到目前为止,这个操作系统是一个可能的解决方案。另一种方法是返回已解析的承诺,并在中进行expect
调用,然后进行回调
jest.spyOn(AsyncComponent.prototype, 'componentDidMount');
const wrapper = mount(<AsyncComponent component={promise} />);
expect(wrapper.instance().componentDidMount).toHaveBeenCalledTimes(1);
await wrapper.instance().componentDidMount.mock.results[0].value;
expect(wrapper.state().loaded).toBe(true);