使用Jest和Enzyme测试React组件中的反跳功能 [英] Testing debounced function in React component with Jest and Enzyme

查看:124
本文介绍了使用Jest和Enzyme测试React组件中的反跳功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am testing a React component using Jest and Enzyme, and am having difficulty testing that a debounced function is called properly (or at all). I've simplified the component code below (edited to make code even simpler), link to 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>
    );
  }
}

我认为去抖动功能测试应该非常相似到一个非去抖动但具有 setTimeout Promise 的项目(预期值为 内的断言。然后或 .finally )。在尝试了采用这两种想法的多种测试变体之后,我不再那么确定了。有任何想法吗?

I figured that the debounced function test should be pretty similar to one that is non-debounced, but with a setTimeout or Promise (with the expect assertion inside .then or .finally). After trying many variations of tests employing both those ideas, I'm not so sure anymore. Any ideas?

推荐答案

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

NOTE: this answer also applies to lodash.throttle since it is just a wrapper of debounce.

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

Lodash's debounce is a monster and needs some special treatments in test because not only does it use setTimeout() but it also:


  • 通话 setTimeout() 递归:这意味着调用 jest.runAllTimers()来模拟 setTimeout 会导致无限递归错误,因为模拟了 setTimeout ()同步执行,直到它用完任务为止,在这里不是这种情况。

  • Calls setTimeout() recursively: This means calling jest.runAllTimers() to mock setTimeout will lead to infinite recursion error, since mocked setTimeout() executes synchronously until it runs out of task, which is not the case here.

用途 Date API :Jest v25及以下版本仅嘲笑计时器功能(例如 setTimeout setInterval ),而 debounce 都使用 setTimeout Date ,因此我们需要模拟两者。

Uses Date API: Jest v25 and below only mocks timer functions (e.g. setTimeout, setInterval) while debounce uses both setTimeout and Date so we need to mock both of them.

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

How you fix this problem depend on what version of jest you are using.

使用另一个库模拟 Date 对象。在此示例中,我将使用advanceBy() > 玩笑日期模拟

Use another library to mock Date object. In this example I'll use advanceBy() from jest-date-mock

jest.useFakeTimers()

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


Jest版本26:


笑话版本26 引入了现代的伪造模式计时器同时模拟 Date 和计时器功能,它是一种选择功能,因此要使用它,您需要添加 jest.useFakeTimers('测试开始之前

Jest version 26:

Jest version 26 introduces modern mode for fake timers which mocks both Date and timer functions, it's an opt-in feature, so in order to use it you need to add jest.useFakeTimers('modern') before the test runs

jest.useFakeTimers("modern")

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


Jest版本27 +:


根据此 PR ,Jest v27将使用

Jest version 27+:

According to this PR, Jest v27 will use the modern implementation by default so we don't need to specify it explicitly.

jest.useFakeTimers()

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

这篇关于使用Jest和Enzyme测试React组件中的反跳功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆