我的LoadingIndicator测试文件中有以下代码。我正在使用JEST + Enzyme来测试LoadingIndicator容器类。
我一直在努力让分行覆盖率达到100%。它被困在91%。我无法覆盖的分支是LoadingIndicator容器类中的 if(!this.timeoutID)。请帮助我理解我在这里缺少的东西。
import ...;
import ConnectedLoadingIndicator,{ LoadingIndicator } from './loadingIndicator';
jest.useFakeTimers();
describe('LoadingIndicator unconnected container component', () => {
let wrapper;
let instance;
beforeEach(() => {
wrapper = shallow(<LoadingIndicator
loading='true'
error='false' />);
instance = wrapper.instance();
});
it('checks loadingIndicator is hidden on loading false', () => {
wrapper.setProps({ loading: false, error: false });
expect(instance.state.showIndicator).toBe(false);
expect(wrapper.find('.loading-hidden').length).toEqual(1);
});
it('checks loadingIndicator is shown after timer runs', () => {
wrapper.setProps({ loading: true, error: false });
jest.runOnlyPendingTimers();
expect(instance.state.showIndicator).toBe(true);
expect(wrapper.find('.loading-show').length).toEqual(1);
});
it('checks loadingIndicator is hidden on error true', () => {
wrapper.setProps({ loading: true, error: true });
expect(instance.state.showIndicator).toBe(false);
expect(wrapper.find('.loading-hidden').length).toEqual(1);
});
it('checks destroyTimer behavior on loading false and error false', () => {
wrapper.setProps({ loading: false, error: false });
expect(instance.timeoutID).toBe(null);
expect(instance.state.showIndicator).toBe(false);
});
});
LoadingIndicator容器类
import ...;
import LoadingIndicatorComponent from '../../../../components/loadingIndicator';
export class LoadingIndicator extends Component {
constructor(props) {
super(props);
this.timeoutID = null;
this.state = {
showIndicator: false,
};
}
componentDidMount() {
this.ensureTimer(this.props);
}
componentWillUnmount() {
this.destroyTimer();
}
componentWillReceiveProps(props) {
if (props.loading !== this.props.loading
|| props.error !== this.props.error) {
this.ensureTimer(props);
}
}
ensureTimer(props) {
if (props.loading && !props.error) {
if (!this.timeoutID) {
this.timeoutID = setTimeout(() => {
this.timeoutID = null;
this.setState({ showIndicator: true });
}, props.timeoutPeriod);
}
} else {
this.destroyTimer();
}
}
destroyTimer() {
clearTimeout(this.timeoutID);
this.timeoutID = null;
this.setState({ showIndicator: false });
}
render() {
console.log(this.state.showIndicator);
return (
<div className =
{`${this.state.showIndicator ? 'loading-show' : 'loading-hidden'}`}>
<LoadingIndicatorComponent>
Loading...
</LoadingIndicatorComponent>
</div>
);
}
}
const mapStateToProps = (state) => ({
loading: isLoading(state),
error: hasError(state),
});
// timeoutPeriod of 1000 is for showing loading indicator after 1000ms
LoadingIndicator.defaultProps = {
timeoutPeriod: 1000,
};
export default connect(mapStateToProps)(LoadingIndicator);
答案 0 :(得分:1)
我已更新我的测试文件,如下所示。我发现两个分支都必须在一次测试中覆盖,而不是在单独的测试中。如果已设置已解决覆盖问题,则检查timeoutID保持不变。
import ...;
import ConnectedLoadingIndicator,{ LoadingIndicator } from './loadingIndicator';
jest.useFakeTimers();
describe('LoadingIndicator unconnected container component', () => {
let wrapper;
let spy;
let spyEnsureTimer;
let instance;
let props = {
pendingRequest: 0
}
beforeEach(() => {
wrapper = shallow(<LoadingIndicator {...props} />,
{ lifecycleExperimental: true, });
instance = wrapper.instance();
spy = jest.spyOn(instance, 'componentWillReceiveProps');
spyEnsureTimer = jest.spyOn(instance, 'ensureTimer');
});
it('renders', () => {
expect(wrapper.length).toEqual(1);
});
it('checks for timeoutID remains unchanged if already set', () => {
instance.ensureTimer(props);
expect(instance.timeoutID).toBe(0);
instance.ensureTimer({ pendingRequest: 1 });
expect(instance.timeoutID).toBe(1);
instance.ensureTimer({ pendingRequest: 1 });
expect(instance.timeoutID).toBe(1);
});
it('checks componentWillReceiveProps and ensureTimer is called', () => {
expect(spy).not.toHaveBeenCalled();
wrapper.setProps({ pendingRequest: 1 });
expect(spy).toHaveBeenCalled();
expect(spyEnsureTimer.mock.calls.length).toBe(1);
});
it('checks ensureTimer is not called with same props', () => {
expect(spyEnsureTimer.mock.calls.length).toBe(0);
wrapper.setProps({ pendingRequest: 0 });
expect(spyEnsureTimer.mock.calls.length).toBe(0);
});
it('checks loadingIndicator is shown on pendingRequest more than 0', () => {
wrapper.setProps({ pendingRequest: 1 });
jest.runOnlyPendingTimers();
expect(instance.state.showIndicator).toBe(true);
expect(wrapper.find('.loading-show').length).toEqual(1);
});
it('checks destroyTimer behavior on pendingRequest less than 1', () => {
wrapper.setProps({ pendingRequest: 1 });
jest.runOnlyPendingTimers();
expect(instance.state.showIndicator).toBe(true);
wrapper.setProps({ pendingRequest: 0 });
expect(instance.timeoutID).toBe(0);
expect(instance.state.showIndicator).toBe(false);
expect(wrapper.find('.loading-hidden').length).toEqual(1);
});
});
我修改了LoadingIndicator容器类以及以下内容:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { selectPendingRequest } from './selectors';
import LoadingIndicatorComponent from '../../../../components/loadingIndicator';
import './loadingIndicator.css';
export class LoadingIndicator extends Component {
constructor(props) {
super(props);
this.timeoutID = 0;
this.state = {
showIndicator: false,
};
}
componentDidMount() {
this.ensureTimer(this.props);
}
componentWillUnmount() {
this.destroyTimer();
}
componentWillReceiveProps(props) {
if (props.pendingRequest !== this.props.pendingRequest) {
this.ensureTimer(props);
}
}
ensureTimer(props) {
if (props.pendingRequest > 0) {
if (this.timeoutID === 0) {
this.timeoutID = setTimeout(() => {
this.timeoutID = 0;
this.setState({ showIndicator: true });
}, props.timeoutPeriod);
}
} else {
this.destroyTimer();
}
}
destroyTimer() {
clearTimeout(this.timeoutID);
this.timeoutID = 0;
this.setState({ showIndicator: false });
}
render() {
return (
<div className =
{`${this.state.showIndicator ? 'loading-show' : 'loading-hidden'}`}>
<LoadingIndicatorComponent>
Loading...
</LoadingIndicatorComponent>
</div>
);
}
}
const mapStateToProps = (state) => ({
pendingRequest: selectPendingRequest(state) //count of pendingRequest
});
LoadingIndicator.defaultProps = {
timeoutPeriod: 1000,
};
export default connect(mapStateToProps)(LoadingIndicator);