React集成Firebase认证Jest测试报ERR_UNHANDLED_REJECTION怎么解决
错误原因
- 你添加的try/catch仅包裹了
onAuthStateChanged监听方法的注册逻辑,该方法本身是同步执行的,不会抛出异步错误。本次报错来自Firebase初始化、认证模块异步加载、StyledFirebaseAuth组件内部发起的异步请求,这些异步逻辑的异常不在当前try/catch的捕获范围内。 - 测试环境默认不会加载项目的
.env环境变量,同时Jest的jsdom运行环境默认禁止真实网络请求,Firebase在测试环境中无法完成初始化和接口调用,才会抛出未处理的Promise拒绝。
排查步骤
- 先打印未处理Promise的具体报错信息,在Jest的全局setup文件(通常为
src/setupTests.js)中添加如下代码,即可看到具体的拒绝原因:
process.on('unhandledRejection', (reason, promise) => { console.error('未处理的Promise拒绝,位置:', promise, '原因:', reason); });
解决方案
单元测试不应该调用真实的第三方服务接口,你需要Mock所有Firebase相关依赖,步骤如下:
- 在测试文件顶部添加Firebase模块的Mock逻辑,模拟认证相关的所有方法和属性:
// Mock 整个firebase模块 jest.mock('firebase', () => { const mockAuthInstance = { onAuthStateChanged: jest.fn((callback) => { // 测试登录按钮场景,默认返回未登录状态 callback(null); return jest.fn(); // 返回取消监听的方法 }), signOut: jest.fn().mockResolvedValue(), currentUser: null, GoogleAuthProvider: { PROVIDER_ID: 'google.com' }, FacebookAuthProvider: { PROVIDER_ID: 'facebook.com' }, TwitterAuthProvider: { PROVIDER_ID: 'twitter.com' }, GithubAuthProvider: { PROVIDER_ID: 'github.com' }, }; return { initializeApp: jest.fn(), auth: jest.fn(() => mockAuthInstance), }; });
- Mock
StyledFirebaseAuth组件,避免加载真实组件的异步逻辑,直接渲染测试需要的按钮文本:
// Mock react-firebaseui的认证组件 jest.mock('react-firebaseui/StyledFirebaseAuth', () => { return function MockStyledFirebaseAuth() { return ( <div> <button>Sign in with Google</button> <button>Sign in with Facebook</button> </div> ); }; });
添加完上述Mock逻辑后,测试运行时不会调用真实的Firebase服务,也就不会产生异步报错,你原来的测试用例就可以正常执行了。
如果需要测试已登录状态的渲染逻辑,只需要在对应测试用例中修改Mock的onAuthStateChanged回调传入的用户对象即可。
内容的提问来源于stack exchange,提问作者wick3d
相关产品推荐
相关产品推荐

