如何在Vitest/Jest中Stub defineNuxtRouteMiddleware?
解决Nuxt中defineNuxtRouteMiddleware的Mock问题
问题背景
我有如下中间件代码:
import checkAuth from './callbacks/checkAuth'; export default defineNuxtRouteMiddleware(checkAuth);
已将defineNuxtRouteMiddleware调用与中间件逻辑分离,仅需测试该函数是否被传入有效参数调用,但测试失败,原因是defineNuxtRouteMiddleware未定义。尝试用vi.stubGlobal('defineNuxtRouteMiddleware', vi.fn());无效,求Mock方法。
解决方法
原因分析
defineNuxtRouteMiddleware是Nuxt注入的全局API,测试环境不会自动挂载,直接用vi.stubGlobal无效大概率是模块加载顺序问题——你的中间件模块在Stub执行前就已经被导入,导致Mock没生效。
方案1:Mock Nuxt的#app模块
直接Mock Nuxt提供的#app模块,确保导入中间件时能获取到Mock的函数:
// 测试文件顶部优先Mock vi.mock('#app', () => ({ defineNuxtRouteMiddleware: vi.fn((fn) => fn) })); // 导入相关模块 import checkAuth from '@/middleware/callbacks/checkAuth'; import '@/middleware/your-middleware-file'; // 替换成你的中间件文件路径 test('defineNuxtRouteMiddleware被传入checkAuth调用', () => { const { defineNuxtRouteMiddleware } = await import('#app'); expect(defineNuxtRouteMiddleware).toHaveBeenCalledWith(checkAuth); });
方案2:调整导入顺序,确保Stub先生效
如果不想Mock模块,可以在导入中间件前先Stub全局,或者用动态导入确保Stub执行在前:
test('验证参数传入', async () => { // 先Stub全局 vi.stubGlobal('defineNuxtRouteMiddleware', vi.fn((fn) => fn)); // 动态导入中间件,此时Stub已生效 await import('@/middleware/your-middleware-file'); const checkAuth = (await import('@/middleware/callbacks/checkAuth')).default; expect(defineNuxtRouteMiddleware).toHaveBeenCalledWith(checkAuth); });
方案3:用Nuxt官方测试工具简化操作
如果是Nuxt 3项目,推荐使用@nuxt/test-utils,它会自动模拟Nuxt的全局API,无需手动Stub:
import { describe, test, expect, vi } from 'vitest'; import { setup } from '@nuxt/test-utils'; // 先初始化Nuxt测试环境 await setup({ // 可根据项目配置添加测试环境参数 }); test('中间件正确调用defineNuxtRouteMiddleware', async () => { // 监听defineNuxtRouteMiddleware方法 const { defineNuxtRouteMiddleware } = await import('#app'); const mockFn = vi.spyOn(await import('#app'), 'defineNuxtRouteMiddleware'); // 导入中间件 await import('@/middleware/your-middleware-file'); const checkAuth = (await import('@/middleware/callbacks/checkAuth')).default; expect(mockFn).toHaveBeenCalledWith(checkAuth); });
内容的提问来源于stack exchange,提问作者datsenkoboos
相关产品推荐
相关产品推荐

