如何监视并测试Promise被拒绝时catch块内的调用函数?
测试React组件中Promise拒绝时catch块的函数调用
嘿,我来帮你搞定这个测试需求!要验证当resetPassword()返回的Promise被拒绝时,displayErrorAlert是否在catch块里被正确调用,用Jest的函数间谍(spy)就能轻松实现,下面我给你详细的步骤和代码示例~
核心思路
我们需要完成这几件关键事:
- 模拟
resetPassword函数,让它返回一个被拒绝的Promise,模拟接口失败的场景 - 创建
displayErrorAlert的间谍,用来追踪它是否被调用以及调用参数 - 模拟组件的表单提交,触发
handleSubmit方法 - 等待异步代码执行完毕后,断言间谍是否被正确调用
用React Testing Library实现的测试代码
React Testing Library是现在React官方推荐的测试工具,写法更贴近用户真实操作:
import { render, screen, fireEvent } from '@testing-library/react'; import ResetPassword from './ResetPassword'; describe('ResetPassword Component', () => { it('calls displayErrorAlert when resetPassword Promise is rejected', async () => { // 1. 创建所有需要的模拟函数/间谍 const mockResetPassword = jest.fn().mockRejectedValue({ error: '模拟错误' }); const mockDisplayErrorAlert = jest.fn(); const mockHistory = { push: jest.fn() }; // 2. 渲染组件,传入模拟的props render( <ResetPassword resetPassword={mockResetPassword} displayErrorAlert={mockDisplayErrorAlert} history={mockHistory} /> ); // 3. 找到表单并模拟提交(记得给组件里的表单加data-testid="reset-password-form"哦) const formElement = screen.getByTestId('reset-password-form'); fireEvent.submit(formElement); // 4. 等待Promise的异步处理完成 await Promise.resolve(); // 5. 断言displayErrorAlert被正确调用 expect(mockDisplayErrorAlert).toHaveBeenCalledWith( 'impossible to change password. You should ask for a new reset password link', 6000 ); // 额外验证:因为Promise被拒绝,then块里的history.push不会被触发 expect(mockHistory.push).not.toHaveBeenCalled(); }); });
用Enzyme实现的测试代码(如果你还在使用Enzyme)
如果你习惯用Enzyme,写法也类似:
import { shallow } from 'enzyme'; import ResetPassword from './ResetPassword'; describe('ResetPassword Component', () => { it('triggers displayErrorAlert when resetPassword fails', async () => { // 创建模拟函数 const mockResetPassword = jest.fn().mockRejectedValue({ error: '测试错误' }); const mockDisplayErrorAlert = jest.fn(); const mockHistory = { push: jest.fn() }; // 浅渲染组件 const wrapper = shallow( <ResetPassword resetPassword={mockResetPassword} displayErrorAlert={mockDisplayErrorAlert} history={mockHistory} /> ); // 模拟表单提交,直接触发handleSubmit wrapper.find('form').simulate('submit', { preventDefault: () => {} }); // 等待异步代码执行 await Promise.resolve(); // 断言函数调用 expect(mockDisplayErrorAlert).toHaveBeenCalledWith( 'impossible to change password. You should ask for a new reset password link', 6000 ); expect(mockHistory.push).not.toHaveBeenCalled(); }); });
关键细节说明
mockRejectedValue({ error: 'xxx' }):专门用来模拟Promise被拒绝的情况,和你组件里catch块接收{ error }的结构保持一致await Promise.resolve():因为Promise的处理是异步的,我们需要等待事件循环走完,确保catch块里的代码完全执行完毕后再做断言- 断言调用参数完全匹配:确保
displayErrorAlert接收的提示文本和时长都是你预期的内容
内容的提问来源于stack exchange,提问作者manu
相关产品推荐
相关产品推荐

