使用计时器更新状态不会返回更新的值

时间:2019-05-30 14:32:07

标签: javascript reactjs jestjs enzyme create-react-app

我是Jest的单元测试新手。该项目具有一个进度指示器组件,该组件使用setInterval作为计时器。我需要进行单元测试,以确保“进度”功能中的“已完成”状态变量在20ms滴答时正确更新。

"react-dom": "^16.8.6",
"react-redux": "^6.0.1",
"react-scripts": "^2.1.3"

progress.js

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import CircularProgress from '@material-ui/core/CircularProgress';

const styles = theme => ({
  progress: {
    margin: theme.spacing.unit * 2
  }
});

class CircularDeterminate extends React.Component {
  state = {
    completed: 0
  };

  componentDidMount() {
    this.timer = setInterval(this.progress, 20);
  }

  componentWillUnmount() {
    clearInterval(this.timer);
  }

  progress = () => {
    let be = this.state.completed;
    console.log('>>>>>> ', this.state.completed);
    const { completed } = this.state;
    this.setState({ completed: completed >= 100 ? 0 : completed + 1 });
    console.log('+++++ ', be, '  ', this.state.completed);
  };

  render() {
    const { classes } = this.props;
    if (!this.props.statusCode) {
      return (
        <div>
          <CircularProgress
            className={classes.progress}
            variant="determinate"
            value={this.state.completed}
          />
        </div>
      );
    } else {
      return null;
    }
  }
}

CircularDeterminate.propTypes = {
  classes: PropTypes.object.isRequired
};

export default withStyles(styles)(CircularDeterminate);

progressTest.js

import React from 'react';
import { shallow, mount } from 'enzyme';
import Progress from '../progress';

describe('Input Component', () => {
  it('update timer', () => {
    jest.useFakeTimers();
    const wrapper = mount(<Progress />);
    wrapper.instance().setState({ completed: 8 });

    jest.advanceTimersByTime(41);
    wrapper.update();

    expect(wrapper.instance().state.completed).toBe(10);
  });
});

上面的测试失败了:预期:10,已接收:8。我希望2个滴答(约41毫秒)后,“完成”的值为10。

1 个答案:

答案 0 :(得分:0)

上述代码中的一个问题(取决于Jest的假计时器的工作原理,可能是实际的问题,也可能不是实际的问题,但肯定是 a 问题),这是您在打破一条基本规则的React状态:自state updates are asynchronous起,如果您要基于现有状态设置新状态 ,则必须使用缩减形式setState。所以这是不正确的:

const { completed } = this.state;
this.setState({ completed: completed >= 100 ? 0 : completed + 1 });
console.log('+++++ ', be, '  ', this.state.completed);

这是正确的形式:

this.setState(
    ({completed}) => ({
        completed: completed >= 100 ? 0 : completed + 1
    }),
    () => {
        console.log('+++++ ', be, '  ', this.state.completed);
    }
);