如何Mock带then和catch块的Firebase认证函数并使用Jest测试?
错误原因
你的mock写法存在两处核心问题:
- jest.mock中对
signInWithEmailAndPassword的导出多套了一层无意义的箭头函数,导致调用signInWithEmailAndPassword(auth, email, password)之后返回的是mockSignIn函数本身,而非执行mockSignIn得到的Promise对象,自然不存在then方法 - 你只定义了注册用的
mockSignUp,没有定义登录用的mockSignIn函数 - 登录逻辑是异步操作,测试用例没有等待异步执行完成,会导致断言提前触发
修复方案
第一步:修正mock定义
// 提前定义所有依赖的mock函数 const mockGetAuth = jest.fn(); // 登录mock,返回符合结构的Promise const mockSignIn = jest.fn(() => Promise.resolve({ user: { uid: "fakeuid", email: "abc@gmail.com" } }) ); const mockSignUp = jest.fn(() => Promise.resolve({ user: { uid: "fakeuid" } }) ); // 修正导出规则,直接绑定mock函数,不要多套箭头函数 jest.mock('firebase/auth', () => ({ getAuth: mockGetAuth, signInWithEmailAndPassword: mockSignIn, createUserWithEmailAndPassword: mockSignUp }));
第二步:修正测试用例,处理异步逻辑
test('Login with Email and Password', async () => { const { result } = renderHook(() => useFirebaseAuth()) const email = 'abc@gmail.com' const password = '123456' act(() => { result.current.loginWithEmailPassword(email, password) }) // 等待所有微任务执行完成,保证then/catch逻辑执行完毕 await Promise.resolve() // 可选:验证mock被正确调用 expect(mockSignIn).toHaveBeenCalledWith(expect.anything(), email, password) })
可选优化
你可以直接把loginWithEmailPassword函数的Promise返回,测试会更简洁:
const loginWithEmailPassword = (email: string, password: string) => { const auth = getAuth() // 向外返回Promise return signInWithEmailAndPassword(auth, email, password) .then((userCredential) => { const user = userCredential.user; // 原有业务逻辑 return user }).catch((error) => { const errorCode = error.code; const errorMessage = error.message; // 按需处理错误后抛出 throw error }); }
对应测试代码可简化为:
test('Login with Email and Password', async () => { const { result } = renderHook(() => useFirebaseAuth()) const email = 'abc@gmail.com' const password = '123456' await act(async () => { await result.current.loginWithEmailPassword(email, password) }) expect(mockSignIn).toHaveBeenCalledWith(expect.anything(), email, password) })
内容的提问来源于stack exchange,提问作者ken
相关产品推荐
相关产品推荐

