如何解决Jest和VITest中‘Cannot access 'mockKeycloak' before initialization’错误
解决Vitest中mock变量初始化顺序导致的"Cannot access 'mockKeycloak' before initialization"错误
问题原因
你遇到的错误核心是Vitest会把所有vi.mock调用自动提升到文件最顶部执行,不管代码书写顺序。你的代码里存在三个问题:一是重复调用了vi.mock("keycloak-js"),二是用let和const重复声明了同名变量mockKeycloak,最关键的是:带工厂函数的vi.mock被提升执行时,后面的const mockKeycloak还没完成初始化,工厂函数引用它就触发了暂时性死区错误。
解决方案
下面给出两种可行的修正方式:
方法1:将mock对象直接内嵌到mock工厂函数中
完全避免外部变量依赖,是最稳妥的写法:
// Import statements... vi.mock("keycloak-js", () => { return { __esModule: true, default: vi.fn().mockImplementation(() => ({ init: vi.fn(() => Promise.resolve()), updateToken: vi.fn(() => Promise.resolve()), createLoginUrl: vi.fn(() => "mock-login-url"), token: "mock-token", authServerUrl: "mock-auth-url", realm: "mock-realm", })), }; }); // Other mock setups... describe("My Test Suite", () => { beforeEach(async () => { // ... Initialization code ... }); test("My test case", async () => { // ... Test logic ... }); });
方法2:用let声明并提前赋值,复用mock对象
如果需要在测试其他环节复用这个mock对象,可以用let声明并提前完成赋值,避免暂时性死区问题:
// Import statements... // 用let声明并直接赋值,跳过暂时性死区 let mockKeycloak = { init: vi.fn(() => Promise.resolve()), updateToken: vi.fn(() => Promise.resolve()), createLoginUrl: vi.fn(() => "mock-login-url"), token: "mock-token", authServerUrl: "mock-auth-url", realm: "mock-realm", }; // 移除多余的vi.mock调用,只保留带工厂函数的版本 vi.mock("keycloak-js", () => { return { __esModule: true, default: vi.fn().mockImplementation(() => mockKeycloak), }; }); // Other mock setups... describe("My Test Suite", () => { beforeEach(async () => { // 可在此处重置mock函数状态,避免测试用例间污染 mockKeycloak.init.mockResolvedValue(true); mockKeycloak.updateToken.mockResolvedValue(true); }); test("My test case", async () => { // ... Test logic ... }); });
额外注意事项
- 不要重复mock同一个模块,多次调用
vi.mock("keycloak-js")会导致配置冲突 - 如果需要动态修改mock行为(比如不同测试用例返回不同值),可以使用
vi.doMock(它不会被自动提升,执行顺序与代码书写顺序一致),但常规场景下上面两种方法足够覆盖需求
内容的提问来源于stack exchange,提问作者CoolLife
相关产品推荐
相关产品推荐

