使用react-hooks-testing-library测试Firebase auth报无默认App错误如何解决
问题原因
- 你当前对Firebase的mock完全不匹配代码中使用的模块化API:你代码中实际使用的是v9+版本的模块化API(
getAuth()、signInWithEmailAndPassword、initializeApp等直接从对应包导入的方法),但你mock的是v8及之前的链式调用结构,没有覆盖实际用到的方法,导致getAuth执行时调用了真实的Firebase逻辑,检测不到初始化的App实例就抛出错误。 - 测试运行环境不会执行业务入口
index.tsx的初始化逻辑:你业务中虽然在入口调用了initFirebase,但单测运行时只会执行测试文件和被测试文件的代码,没有触发初始化逻辑,即使不mock的情况下也会缺少App实例。 - 断言逻辑存在问题:
signInWithEmailAndPassword的第一个参数是auth实例,之后才是邮箱和密码,你当前的断言参数匹配错误,且loginWithEmailPassword是异步方法,你没有等待Promise执行完成就做断言,会出现断言时序错误。
解决方法
你需要把所有用到的Firebase API都正确mock,修改后的测试代码参考如下:
import React from 'react' import { renderHook, act } from '@testing-library/react-hooks/native' import useFirebaseAuth from '../useAuth'; // 先定义mock方法 const mockSignIn = jest.fn(() => Promise.resolve({ user: { uid: 'test-uid' } })) const mockGetAuth = jest.fn(() => ({})) // mock getAuth直接返回空对象即可 // mock firebase/auth模块,覆盖你用到的方法 jest.mock('firebase/auth', () => ({ getAuth: mockGetAuth, signInWithEmailAndPassword: mockSignIn })) // mock firebase/app模块的初始化相关方法 jest.mock('firebase/app', () => ({ initializeApp: jest.fn(), getApps: jest.fn(() => [{}]), // 模拟已经有初始化的App getApp: jest.fn(() => ({})) })) // 对应mock你自己的初始化文件 jest.mock('../../utils/initAuth', () => ({ initFirebase: jest.fn() })) describe('useAuth Hooks testing', () => { // 每次测试前清空mock调用记录 beforeEach(() => { jest.clearAllMocks() }) test('Login with Email and Password', async () => { // 加async处理异步 const { result } = renderHook(() => useFirebaseAuth()) // 初始状态断言 expect(result.current.user).toBe(null) expect(typeof result.current.loginWithEmailPassword).toBe('function') expect(typeof result.current.signUpWithEmailPassword).toBe('function') const email = 'abc@gmail.com' const password = '123456' // 等待异步方法执行完成 await act(async () => { await result.current.loginWithEmailPassword(email, password) }) // 修正断言参数,第一个参数是getAuth返回的auth实例,之后是邮箱密码 expect(mockSignIn).toBeCalledWith({}, email, password) expect(mockGetAuth).toBeCalledTimes(1) }) })
如果需要测试注册逻辑,只需要在firebase/auth的mock里加上对应的createUserWithEmailAndPassword和对应的mock方法即可。
内容的提问来源于stack exchange,提问作者ken
相关产品推荐
相关产品推荐

