Vitest/React Testing Library测试超时求助:点击电源按钮触发超时
解决Vitest测试Simon组件超时问题
核心问题分析
你遇到的超时是因为vi.useFakeTimers()启用后,所有定时器逻辑都会被拦截挂起——哪怕turn_simon_on本身没定时,但如果它间接触发了包含setInterval的start_new_game(或是组件在状态变更时自动调用了start_new_game),挂起的定时器会导致测试无法自然完成,最终触发5000ms超时。
具体修复方案
1. 精准控制定时器的启用/销毁范围
不要在整个测试用例全程启用假定时器,只在需要测试start_new_game的定时逻辑时启用,用完立即清理:
test('测试start_new_game的定时逻辑', async () => { // 先初始化组件,完成电源开启操作 render(<Simon />); const power_button = screen.getByRole('button', { name: /power/i }); await user.click(power_button); // 此时再启用假定时器,测试游戏启动逻辑 vi.useFakeTimers(); const start_button = screen.getByRole('button', { name: /start/i }); await user.click(start_button); // 执行挂起的定时器任务 vi.runOnlyPendingTimers(); // 此处添加你的断言逻辑... // 清理假定时器,避免影响其他测试 vi.useRealTimers(); });
2. 排除非定时器异步操作的拦截
如果必须提前启用假定时器,可以通过配置排除微任务类的异步操作,确保user.click触发的DOM和状态更新能正常完成:
test('测试电源按钮与游戏启动', async () => { vi.useFakeTimers({ doNotFake: ['nextTick', 'setImmediate'] }); render(<Simon />); const power_button = screen.getByRole('button', { name: /power/i }); // 点击电源后,手动执行微任务确保状态同步 await user.click(power_button); await vi.runAllTicks(); const start_button = screen.getByRole('button', { name: /start/i }); await user.click(start_button); // 执行start_new_game中的定时器任务 vi.runOnlyPendingTimers(); // 此处添加你的断言逻辑... vi.useRealTimers(); });
3. 处理电源开启后自动触发的定时器
如果turn_simon_on修改状态(比如isPowerOn)后,组件会自动调用start_new_game,那么点击电源后要立即执行挂起的定时器:
test('电源开启后自动启动游戏', async () => { vi.useFakeTimers(); render(<Simon />); const power_button = screen.getByRole('button', { name: /power/i }); await user.click(power_button); // 执行因状态变更触发的start_new_game定时器 vi.runOnlyPendingTimers(); // 此处添加你的断言逻辑... vi.useRealTimers(); });
4. 临时调整测试超时时间(应急方案)
如果以上方案都不生效,可以给单个测试用例延长超时时间,同时排查是否存在未处理的异步逻辑:
test('测试电源按钮', async () => { // 此处添加你的测试逻辑 }, 10000); // 将超时时间改为10秒
内容的提问来源于stack exchange,提问作者0binny0
相关产品推荐
相关产品推荐

