[英]Testing debounced function in React component with Jest and Enzyme
我正在使用 Jest 和 Enzyme 测试 React 组件,并且很难测试去抖动函数是否被正确调用(或根本调用)。 我已经简化了下面的组件代码(经过编辑以使代码更简单),此处链接到 codepen
// 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
(与expect
中断言.then
或.finally
)。 在尝试了采用这两种想法的多种测试变体之后,我不再那么确定了。 有任何想法吗?
注意:这个问题的答案也适用于lodash.throttle
,因为它只是一个包装debounce
。
Lodash的debounce
是一个怪物,并在测试中需要一些特殊的处理,因为它不仅使用setTimeout()
但它也:
递归调用setTimeout()
:这意味着调用jest.runAllTimers()
来模拟setTimeout
将导致无限递归错误,因为模拟的setTimeout
setTimeout()
同步执行,直到它用完任务,这里不是这种情况。
使用Date
API :Jest v25 及以下仅模拟计时器函数(例如setTimeout
、 setInterval
)而debounce
使用setTimeout
和Date
所以我们需要模拟它们。
您如何解决此问题取决于您使用的是哪个版本的笑话。
使用另一个库来模拟Date
对象。 在这个例子中,我将使用jest-date-mock
advanceBy()
jest.useFakeTimers()
await act(async () => {
triggerDebounced()
advanceBy(DEBOUNCED_TIME + 1000) // forward Date
jest.advanceTimersByTime(DEBOUNCED_TIME) // forward setTimeout's timer
})
Jest版本 26为假定时器引入了现代模式,它模拟Date
和定时器功能,这是一个选择加入的功能,所以为了使用它,你需要在测试运行之前添加jest.useFakeTimers('modern')
jest.useFakeTimers("modern")
await act(async () => {
triggerDebounced()
jest.advanceTimersByTime(DEBOUNCED_TIME)
})
根据这个PR ,Jest v27 将默认使用现代实现,因此我们不需要明确指定它。
jest.useFakeTimers()
await act(async () => {
triggerDebounced()
jest.advanceTimersByTime(DEBOUNCED_TIME)
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.