【问题标题】:Testing debounced function in React component with Jest and Enzyme使用 Jest 和 Enzyme 测试 React 组件中的去抖动功能
【发布时间】:2018-10-08 04:50:35
【问题描述】:

我正在使用 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>
    );
  }
}

我认为去抖功能测试应该与非去抖功能测试非常相似,但带有setTimeoutPromiseexpect 断言在.then.finally 内)。在尝试了使用这两种想法的许多测试变体之后,我不再那么确定了。有什么想法吗?

【问题讨论】:

  • 您可能需要使用this 模拟计时器并使用jest.advanceTimersByTime()。如果你能提供一个我可以编写和调试测试的设置,我可以尝试一些方法并分享一个解决方案。
  • 感谢您的帮助!我简化了我的代码示例,并在上面的问题中添加了一个 codepen 链接。
  • 谢谢。但由于 jest 不在浏览器中运行,我将无法编写和验证测试。也许过一段时间我会试试。但是我找到了一个符合我想法的答案。看看stackoverflow.com/a/52226973/2950032
  • 我不确定这是否只是出于显示目的的简化,但您的处理程序很容易在构造函数中只是 this.handleClick = _.debounce(this.handleClick.bind(this), 3000);。然后,一切都正确绑定,您可以单独测试点击处理程序。

标签: javascript reactjs jestjs enzyme


【解决方案1】:

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

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

  • CallssetTimeout()recursively:这意味着调用jest.runAllTimers()来模拟setTimeout会导致无限递归错误,因为被模拟的setTimeout()会同步执行,直到任务用完为止,事实并非如此在这里。

  • UsesDateAPI:Jest v25 及以下版本仅模拟计时器功能(例如setTimeoutsetInterval)而debounce 使用setTimeoutDate,所以我们需要同时模拟两者其中。

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

对于 jest 25 及以下版本:

使用另一个库来模拟 Date 对象。在这个例子中,我将使用来自jest-date-mockadvanceBy()

jest.useFakeTimers()

await act(async () => {
  triggerDebounced()
  advanceBy(DEBOUNCED_TIME + 1000) // forward Date
  jest.advanceTimersByTime(DEBOUNCED_TIME) // forward setTimeout's timer
})

笑话版本 26:

Jest version 26 引入了模拟 Date 和定时器功能的现代模式,它是一个可选功能,因此要使用它,您需要在测试运行前添加 jest.useFakeTimers('modern')

jest.useFakeTimers("modern")

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

Jest 版本 27+:

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

jest.useFakeTimers()

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

【讨论】:

    猜你喜欢
    • 2019-06-16
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    • 2019-02-12
    • 2020-11-02
    • 2019-07-26
    • 2017-02-12
    • 2020-07-17
    相关资源
    最近更新 更多