如何使用Jest Mock setTimeout解决React按钮防抖后的测试问题
解决方案
1. 先修正防抖代码的基础错误
你当前的按钮点击防抖写法存在逻辑问题:setTimeout(handler(e), 1000)会立即执行handler(e),再把函数返回值作为定时器回调,完全没有达到延迟执行的效果。正确写法应该给setTimeout传入函数包装:
<Button onClick={(e) => setTimeout(() => handler(e), 1000)}/>
2. 正确使用Jest假定时器的方案
之前假定时器不生效,大概率是没有同步触发定时器执行、也没有处理React的状态更新批次,正确用法如下:
it('displays similar listings', async () => { // 启用假定时器 jest.useFakeTimers(); const renderResult = renderVdp(renderParams); // 此处补充你原有测试逻辑里的按钮点击触发步骤,示例: // fireEvent.click(renderResult.getByRole('button', {name: '查询'})) // 执行所有 pending 状态的定时器,用act包裹保证React状态更新完成 act(() => { jest.runAllTimers(); }); // 重置为真实定时器,避免影响其他测试用例 jest.useRealTimers(); // 正常执行断言即可,不需要额外加1秒等待 expect(renderResult.getAllByText('2017 BMW M3')).toHaveLength(4); });
如果使用React Testing Library v13+版本,也可以在waitFor之前执行jest.advanceTimersByTime(1000),无需单独调用runAllTimers
3. 无侵入兼容方案
如果不想在测试里处理定时器逻辑,可以把防抖延迟提取为可配置参数,生产环境传1000,测试环境默认传0,不需要修改原有测试用例也不会产生真实延迟:
// 组件定义时新增可配置的延迟参数 const ActionButton = ({ debounceDelay = 1000, handler }) => { return <Button onClick={(e) => setTimeout(() => handler(e), debounceDelay)}/> } // 测试场景传入0延迟即可 <ActionButton debounceDelay={0} handler={testHandler} />
内容的提问来源于stack exchange,提问作者Igor Shmukler
相关产品推荐
相关产品推荐

