我正在尝试测试运行某些异步代码并在componentDidMount中调用setState的React组件。
这是我要测试的反应组件:
/**
*
* 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;
以下是测试用例。我正在使用开玩笑和酶。
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);
});
});
测试失败,因为state.loaded仍设置为false。有没有办法在调用expect之前确保AsyncComponent已经完全加载?
如果我将期望断言包装在setTimeout中,我可以使它工作,但这似乎是一种相当hacky方式。我应该怎么做呢?
答案 0 :(得分:0)
我遇到了同样的问题,我想出了一些笨拙的解决方案,我在componentDidMount中有一些函数调用,我想检查是否已调用该函数,以便代码对我有用
const loadFiltersTree = jest.fn()
const wrapper = shallow(<FilterTree loadFiltersTree={loadFiltersTree} />)
jest.useFakeTimers()
jest.runAllTimers()
setImmediate(() => {
expect(loadFiltersTree.mock.calls.length).toEqual(1)
})
答案 1 :(得分:0)
打破承诺链是常见的反模式。根据经验,使用promise的函数应返回生成的promise链,除非这会引起问题。这保证了当调用者函数链接一个诺言时不会出现竞争条件。原因之一是可测试性的提高。这也适用于生命周期挂钩,例如componentDidMount
:
componentDidMount() {
return this.props.component.then(...)
}
异步Jest测试应链接使用中的所有诺言并返回诺言。 async..await
是执行此操作的实用方法。
在酶中,浅层渲染可禁用自动componentDidMount
调用并链接生命周期挂钩返回的承诺:
const wrapper = shallowMount(<AsyncComponent component={promise} />,
{ disableLifecycleMethods: true });
await wrapper.instance().componentDidMount();
expect(wrapper.state().loaded).toBe(true);
这也可以通过监视componentDidMount
完成完整渲染:
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);
答案 2 :(得分:-1)
您需要使用async/await
通知jest有关承诺,或者从测试中返回承诺,请查看docs
describe('<AsyncComponent />', () => {
it('Should render loaded component.', async() => {
const promise = Promise.resolve(TestComponent);
const rendered = mount(<AsyncComponent component={promise} />);
await promise
expect(rendered.state().loaded).toBe(true);
});
});