使用Jest和Enzyme测试React组件中的反跳功能

时间:2018-10-08 04:50:36

标签: javascript reactjs jestjs enzyme

我正在使用Jest和Enzyme测试React组件,并且很难测试去抖动功能是否被正确调用(或根本没有调用)。我简化了下面的组件代码(已编辑,使代码更简单),链接到codepen here

// uses lodash debounce

class MyApp extends React.Component {
  constructor(props) {
    super()
    this.state = {name: "initial value"};
    this.debouncedFunction = _.debounce(this.debouncedFunction, 3000);
    this.handleClick = this.handleClick.bind(this)
  }

  debouncedFunction () {
    this.setState({name: "after delay, updated value"});
  }

  handleClick() {
    this.debouncedFunction();
  }

  render() {
    return (
      <div>
        <p>{this.state.name}</p>
        <button onClick={this.handleClick}>
          click for debounced function
        </button>
      </div>
    );
  }
}

我认为去抖动的功能测试应该与未去抖动的测试非常相似,但是要使用setTimeoutPromise({{1}内有expect断言}或.then)。在尝试了使用这两种想法的多种测试变体之后,我不再那么确定了。有什么想法吗?

1 个答案:

答案 0 :(得分:6)

注意:此答案也适用于lodash.throttle,因为它只是debounce的包装。

Lodash的debounce是一个怪物,在测试中需要进行一些特殊处理,因为它不仅使用setTimeout(),而且还使用了

  • Calls setTimeout() recursively:这意味着调用jest.runAllTimers()模拟setTimeout将导致无限递归错误,因为模拟{{1} }同步执行,直到任务用完为止,在这里不是这种情况。

  • Uses Date API:Jest v25及以下版本仅在setTimeout()时模拟计时器函数(例如setTimeoutsetInterval)同时使用debouncesetTimeout,因此我们需要模拟两者。

如何解决此问题取决于您所使用的玩笑的版本。

对于玩笑版本25及以下:

使用另一个库来模拟Date对象。在此示例中,我将使用jest-date-mock中的Date

advanceBy()

笑话版26:

笑话version 26引入了用于假计时器的现代模式,该模式可以模拟jest.useFakeTimers() await act(async () => { triggerDebounced() advanceBy(DEBOUNCED_TIME + 1000) // forward Date jest.advanceTimersByTime(DEBOUNCED_TIME) // forward setTimeout's timer }) 和计时器功能,这是一项可选功能,因此要使用它,您需要在添加Date之前测试运行

jest.useFakeTimers('modern')

笑话版27 +:

根据此PR,Jest v27将默认使用现代实现,因此我们无需明确指定它。

jest.useFakeTimers("modern")

await act(async () => {
  triggerDebounced()
  jest.advanceTimersByTime(DEBOUNCED_TIME)
})