使用MUI-X v5 DesktopDatePicker时Jest.useFakeTimers超时如何解决
Jest useFakeTimers 导致 MUI-X v5 DesktopDatePicker 测试超时的解决方案
核心原因
MUI-X v5 的 DesktopDatePicker 组件内部依赖 setTimeout、requestAnimationFrame 处理面板切换动画、日期禁用态校验、日历视图渲染的异步逻辑。默认调用 jest.useFakeTimers() 会全量 mock 所有时间相关 API,把组件内部等待执行的异步定时任务全部挂起,任务一直无法执行完成就会导致测试超时。
你本身的需求只是固定 new Date() 返回值来规避跨月选日期、禁用过去日期的逻辑异常,不需要全量 mock 所有时间API,这是触发问题的核心诱因。
可落地的解决方法
按优先级从高到低排列:
只mock Date对象,保留其他时间API的真实实现
这是最适配你需求的方案,不需要改动组件代码,也不会破坏组件内部的定时逻辑。Jest 27及以上版本支持指定fake timers的mock范围:beforeEach(() => { jest.useFakeTimers({ // 保留定时器、动画帧相关API的真实实现,不做mock doNotFake: [ 'setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'requestAnimationFrame', 'cancelAnimationFrame' ], // 直接在这里指定你要固定的系统时间即可 now: new Date('2024-05-20T00:00:00.000Z') }) }) afterEach(() => { // 每个用例执行完恢复真实时间,避免污染其他测试 jest.useRealTimers() })全量fake timers场景下手动flush待执行任务
如果你确实需要全量mock时间API(比如测试时间等待相关逻辑),可以在每一步交互触发后手动推进定时器,把组件挂起的任务执行完:test('跨月选择非过去日期正常生效', async () => { jest.useFakeTimers() // 固定系统时间 jest.setSystemTime(new Date('2024-05-20')) render(<DesktopDatePicker disablePast />) // 打开日期面板 fireEvent.click(screen.getByRole('textbox')) // 执行所有待处理的定时任务,等待面板渲染完成 jest.runOnlyPendingTimers() // 点击切换到下个月 fireEvent.click(screen.getByLabelText('下个月')) jest.runOnlyPendingTimers() // 选择目标日期 fireEvent.click(screen.getByText('15')) jest.runOnlyPendingTimers() // 写你的断言逻辑即可 expect(screen.getByRole('textbox')).toHaveValue('06/15/2024') jest.useRealTimers() })测试环境关闭组件动画
组件大部分定时逻辑都是为了服务过渡动画,测试环境可以直接关闭动画,从根源消除对定时API的依赖:import { createTheme, ThemeProvider } from '@mui/material/styles' // 测试专用主题,全局关闭日期选择器动画 const testTheme = createTheme({ components: { MuiPickersCalendar: { defaultProps: { reduceAnimations: true } } } }) // 渲染组件时包裹主题即可 render( <ThemeProvider theme={testTheme}> <DesktopDatePicker disablePast /> </ThemeProvider> )
注意:不要在测试文件顶层无差别调用jest.useFakeTimers()且不做恢复,会污染其他测试用例的执行环境,引发随机失败。
内容的提问来源于stack exchange,提问作者Nate Thibert
相关产品推荐
相关产品推荐

