Jest - 测试 clear超时 in useEffect hook



在我的按钮组件中,单击时,我强制禁用按钮 500 毫秒以防止多次提交,0.5 秒后禁用状态恢复为默认值。尽管方法不同,我得到了两行代码,我似乎无法在我的单元测试中涵盖。

请参阅下面的简化组件源代码:

import React, {useState, useEffect} from 'react';
const Button = ({disabled, onClick}) => {
const [disableButton, forceDisabledButton] = useState(false);
useEffect(() => {
let timeId;
if (disableButton) {
timeId = setTimeout(() => {
forceDisabledButton(false);
}, 500);
}
return () => {
if (timeId) {
clearTimeout(timeId);
}
}
}, [disableButton]);
const onButtonClick = (e) => {
onClick && onClick(e);
forceDisabledButton(true);
}
return (
<button onClick={onButtonClick} disabled={!disableButton ? disabled : disableButton}>Button</button>
)
}

默认值disabled设置为false。 测试用例:

(...)
it('should become disabled after click and then return to its previous disabled state', () => {
const mountButton = shallow(<Button/>);
jest.useFakeTimers();
expect(mountButton.find('button').length).toEqual(1);
mountButton.find('button').simulate('click');
expect(mountButton.find('button').prop('disabled')).toEqual(true);
setTimeout(() => {
expect(mountButton.find('button').prop('disabled')).toEqual(false);
expect(clearTimeout).toHaveBeenCalledWith(expect.any(Number));
}, 600)
})

未涵盖的行是:forceDisabledButton(false);clearTimeout(timeId);.我最初尝试jest.runAllTimers(),但它也没有设法涵盖这两个功能。测试通过,在应用程序中我没有任何内存泄漏警告(以及按钮被禁用 500 毫秒的视觉确认),所以我知道它工作正常并且这两个函数都被调用了。我可以尝试哪些修改来解决单元测试中的这两个函数?

谢谢

您可以使用runAllTimers

it('should become disabled after click and then return to its previous disabled state', (done) => {
const mountButton = mount(<Button/>);
jest.useFakeTimers();
expect(mountButton.find('button').length).toEqual(1);
mountButton.find('button').simulate('click');
expect(mountButton.find('button').prop('disabled')).toEqual(true);
setTimeout(() => {
expect(mountButton.find('button').prop('disabled')).toEqual(false);
done(); // not sure if it's required for case with `runAllTimers`
}, 600);
jest.runAllTimers();
})

或者您可以使用advanceTimersByTime来检查延迟是否正好是 500:

it('should become disabled after click and then return to its previous disabled state', () => {
const mountButton = mount(<Button/>);
jest.useFakeTimers();
// ...
jest.advanceTimersByTime(499);
expect(mountButton.find('button').prop('disabled')).toEqual(true);
jest.advanceTimersByTime(2);
expect(mountButton.find('button').prop('disabled')).toEqual(false);
})

至于clearTimeout作为清理的一部分,useEffect它将在重新渲染或挂载时调用。因此,如果您真的想检查它是否被称为,只需使用mountButton.update()触发重新渲染。但是你可以验证clearTimeout是否被调用,而不是检查它是否被调用为useEffect钩子的一部分。

一般来说,使用runOnlyPendingTimersrunAllTimers更安全,因为如果我们在useEffect中有顺序setTimeout,稍后一次可能会导致无限循环(但不是这种情况)

[UPD]shallow()可能无法正常工作,因为在与钩子集成时仍然存在未解决的问题。

相关内容

  • 没有找到相关文章