如何用Jest测试history.block的回调函数是否触发?
如何用Jest测试history.block的回调函数是否触发?
看起来你已经成功验证了history.block被调用,但回调里的逻辑(比如console.log)没触发,问题出在你用的mockhistory默认不会执行传入的回调函数,只是记录它被调用了而已。下面给你两种可行的测试思路:
方法一:手动保存并触发block的回调
首先我们需要让mock的history.block方法把传入的回调函数存下来,之后在测试里手动调用这个回调,这样就能验证里面的逻辑是否执行了。具体步骤如下:
- 先mock
console.log,方便我们断言它是否被调用 - 创建一个带自定义
block方法的mock history对象,保存传入的回调 - 渲染组件时把这个mock history传进去
- 触发导航操作后,手动调用保存的回调函数,最后断言结果
代码示例:
test('block navigation and fire console.log', async () => { // 监听console.log,避免真的输出到控制台,同时记录调用情况 const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); // 创建mock history对象,让block方法保存回调 const mockHistory = { block: jest.fn((callback) => { // 把回调存到mockHistory上,方便后续调用 mockHistory.blockCallback = callback; // 返回unblock函数(随便一个空mock就行) return jest.fn(); }), push: jest.fn(), // 模拟push方法,对应你的导航操作 }; // 渲染组件,记得把mockHistory传给Router render( <Router history={mockHistory}> {/* 你的组件,包含触发导航的按钮 */} <button onClick={() => mockHistory.push('/target-route')}>Route</button> <YourComponent shouldBlock={true} /> </Router> ); // 点击导航按钮 await userEvent.click(screen.getByText('Route')); // 模拟history.block收到的transition对象 const mockTransition = { location: { pathname: '/target-route' }, }; // 手动调用block的回调函数 mockHistory.blockCallback(mockTransition); // 断言console.log被正确调用(注意你原代码里的url可能是navigationUrl的笔误哦) expect(consoleLogSpy).toHaveBeenCalledWith('TEST: ', '/target-route'); // 恢复console.log的原始行为 consoleLogSpy.mockRestore(); });
方法二:让mock history自动触发block回调
如果你希望更贴近真实场景,也可以让mock的push方法自动触发block的回调,模拟真实的导航拦截流程:
test('block navigation triggers callback automatically', async () => { const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); let blockCallback; const mockHistory = { block: jest.fn((callback) => { blockCallback = callback; return jest.fn(); }), push: jest.fn((path) => { // 当调用push时,自动触发block回调 blockCallback({ location: { pathname: path }, retry: jest.fn(), // 可以模拟retry方法,按需使用 }); }), }; render( <Router history={mockHistory}> <button onClick={() => mockHistory.push('/target-route')}>Route</button> <YourComponent shouldBlock={true} /> </Router> ); await userEvent.click(screen.getByText('Route')); // 直接断言即可,不需要手动调用回调 expect(consoleLogSpy).toHaveBeenCalledWith('TEST: ', '/target-route'); consoleLogSpy.mockRestore(); });
小提示
你原代码里的console.log('TEST: ', url);可能是个笔误,应该用navigationUrl吧?不然url变量没定义,会报错哦。
备注:内容来源于stack exchange,提问作者marcus-linmarkson
相关产品推荐
相关产品推荐

