Jest测试Firestore报错:ReferenceError: 无法在初始化前访问'mockFirestore'
问题原因
Jest会将jest.mock调用自动提升到模块所有代码的最顶部执行,这意味着当你的jest.mock工厂函数执行时,后面定义的mockFirestore变量还未完成初始化,因此抛出了"Cannot access 'mockFirestore' before initialization"的错误。
修复方案
将所有mock函数的定义移到jest.mock的工厂函数内部,或者通过链式调用避免提前引用未初始化的变量。以下是两种可行的修复代码:
方案一:在mock工厂函数内定义所有mock变量
import { RoleService } from "../../services/RoleService"; import { CustomError } from "../../exceptions/custom_error"; // 提前声明变量,方便测试中修改mock行为 let mockGet: jest.Mock; let mockDoc: jest.Mock; let mockCollection: jest.Mock; let mockFirestore: jest.Mock; jest.mock("firebase-admin", () => { // 在工厂函数内部初始化所有mock函数 mockGet = jest.fn(); mockDoc = jest.fn().mockReturnValue({ get: mockGet }); mockCollection = jest.fn().mockReturnValue({ doc: mockDoc }); mockFirestore = jest.fn().mockReturnValue({ collection: mockCollection }); return { firestore: jest.fn().mockReturnValue(mockFirestore()), }; }); describe("RoleService Unit Tests", () => { beforeEach(() => { jest.clearAllMocks(); }); test("should throw error when role does not exist", async () => { const roleId = "role123"; mockGet.mockResolvedValue({ exists: false, data: jest.fn().mockReturnValue(null), id: roleId, }); await expect(RoleService.getRoleById(roleId)).rejects.toThrow(CustomError.roleNotFound()); }); });
方案二:链式调用mock函数,无需额外变量声明
import { RoleService } from "../../services/RoleService"; import { CustomError } from "../../exceptions/custom_error"; import admin from "firebase-admin"; jest.mock("firebase-admin", () => { return { firestore: jest.fn().mockReturnValue({ collection: jest.fn().mockReturnValue({ doc: jest.fn().mockReturnValue({ get: jest.fn() }) }) }) }; }); describe("RoleService Unit Tests", () => { beforeEach(() => { jest.clearAllMocks(); }); test("should throw error when role does not exist", async () => { const roleId = "role123"; // 从mock实例中获取get函数并修改其返回值 const mockGet = (admin.firestore() as any).collection().doc().get; mockGet.mockResolvedValue({ exists: false, data: jest.fn().mockReturnValue(null), id: roleId, }); await expect(RoleService.getRoleById(roleId)).rejects.toThrow(CustomError.roleNotFound()); }); });
原理说明
两种方案都是通过将mock函数的定义逻辑放到jest.mock的工厂函数内部,确保当Jest提升执行jest.mock时,所有依赖的mock函数已经完成初始化,从根源上解决了变量提前访问的问题。
内容的提问来源于stack exchange,提问作者Eduardo
相关产品推荐
相关产品推荐

