求助:Jest测试useDebounceCallback组件时假定时器问题
问题排查与修复方案
核心问题分析
你的测试失败主要源于三个关键错误:
useDebounceCallbackMock 逻辑错误:当前Mock没有返回可调用的防抖函数,导致组件内的handleSearch是undefined,触发onChange时无法执行后续逻辑。useSearchParams返回值类型错误:用Map模拟返回值,但实际useSearchParams返回的是URLSearchParams实例,会导致组件内参数处理异常。- Router Mock 未完整初始化:缺少对
useRouter返回对象的正确Mock,导致router.push的调用无法被追踪。
修复步骤与代码调整
1. 修正 useDebounceCallback 的 Mock
正确的防抖函数Mock需要返回一个可调用的函数,当该函数被触发时,会在延迟后执行传入的回调:
jest.mock('usehooks-ts', () => ({ useDebounceCallback: jest.fn((fn) => { // 返回防抖函数,调用时携带参数执行原回调 return (...args) => { setTimeout(() => fn(...args), 500); }; }), }));
2. 修正 useSearchParams 的 Mock
将返回值改为URLSearchParams实例,匹配真实场景:
useSearchParams.mockReturnValue(new URLSearchParams('search='));
3. 完善 Router 相关 Hooks 的 Mock
在测试文件顶部添加完整的Next.js Router Hooks Mock,并在beforeEach中初始化mock对象:
import { useRouter, usePathname, useSearchParams } from 'next/navigation'; jest.mock('next/navigation', () => ({ useRouter: jest.fn(), usePathname: jest.fn(), useSearchParams: jest.fn(), })); const routerMock = { push: jest.fn() };
完整修复后的测试代码
import { render, fireEvent } from '@testing-library/react'; import { useRouter, usePathname, useSearchParams } from 'next/navigation'; import { ParamSearch } from './ParamSearch'; jest.mock('next/navigation', () => ({ useRouter: jest.fn(), usePathname: jest.fn(), useSearchParams: jest.fn(), })); jest.mock('usehooks-ts', () => ({ useDebounceCallback: jest.fn((fn) => { return (...args) => { setTimeout(() => fn(...args), 500); }; }), })); describe('ParamSearch', () => { const routerMock = { push: jest.fn() }; beforeEach(() => { useRouter.mockReturnValue(routerMock); jest.useFakeTimers(); routerMock.push.mockClear(); // 重置调用记录 }); afterEach(() => { jest.runOnlyPendingTimers(); jest.useRealTimers(); }); it('calls handleSearch as debounced callback after delay', () => { usePathname.mockReturnValue('/test-search'); useSearchParams.mockReturnValue(new URLSearchParams('search=')); const { getByPlaceholderText } = render( <ParamSearch placeholder={'Search'} defaultSearchValue={''} /> ); const searchInput = getByPlaceholderText('Search'); fireEvent.change(searchInput, { target: { value: 'x' } }); // 延迟前未触发push expect(routerMock.push).not.toHaveBeenCalled(); // 快进定时器到防抖延迟时间 jest.advanceTimersByTime(500); // 验证push被正确调用 expect(routerMock.push).toHaveBeenCalledWith('/test-search?search=x'); }); });
额外优化建议
组件内handleSearch的参数类型存在冗余,建议将event: '' | ChangeEvent<HTMLInputElement>改为event: ChangeEvent<HTMLInputElement>,因为onChange事件的参数始终是ChangeEvent类型,空字符串的类型定义属于错误冗余。
内容的提问来源于stack exchange,提问作者LazerFriends
相关产品推荐
相关产品推荐

