Обновление состояния с таймером не возвращает обновленные значения - PullRequest
0 голосов
/ 30 мая 2019

Я новичок в модульном тестировании с Jest. В проекте есть компонент индикатора прогресса, который использует setInterval в качестве таймера. Мне нужно провести модульное тестирование, чтобы переменная состояния «завершено» корректно обновлялась на тиках 20 мс в функции «прогресс».

"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. Я ожидаю, что значение «выполнено» будет иметь значение 10 через 2 такта (~ 41 мс).

1 Ответ

0 голосов
/ 30 мая 2019

Одна проблема в приведенном выше коде (которая может или не может быть реальной проблемой в зависимости от того, как работают фальшивые таймеры Jest, но, безусловно, является проблемой * ), вы нарушаете одно из фундаментальных правилСостояние реакции: Поскольку обновления состояния являются асинхронными , если вы устанавливаете новое состояние на основе существующего состояния , вы должны использовать форму обратного вызова 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);
    }
);
...