测试 Vue Router 守卫需 Mock 导航方法或使用 createMemoryHistory 真实初始化 router;验证跳转逻辑时,检查 next 或 router.push 调用参数,或断言 router.currentRoute.value.path;组件内守卫需挂载组件并触发路由变化,注意 await isReady();测试后须清理 Mock。

在测试 Vue Router 的路由守卫(如 beforeEach、beforeEnter 或组件内的 beforeRouteEnter)时,如果守卫内部调用了 next('/login') 或 router.push('/home') 这类导航方法,你需要 Mock 路由实例的导航行为,避免真实跳转干扰测试,同时验证跳转逻辑是否正确。
Mock router.push 和 next 函数
路由守卫中常见的跳转方式有两种:全局守卫用 next('/path'),组合式 API 或独立路由实例中常用 router.push()。它们本质都触发导航,测试时可统一 Mock 为 jest.fn():
- 对
next:直接传入一个 mock 函数替代原生next,检查是否被调用及参数 - 对
router.push:用jest.mock('vue-router', ...)或直接替换测试用的 router 实例上的push方法
示例(使用 Vue Router 4 + Vitest):
import { createRouter, createWebHistory } from 'vue-router'
import { beforeEach } from '@/router/index' // 假设你的全局守卫导出为 beforeEach
// 构造一个简易 mock router
const mockRouter = {
push: jest.fn(),
currentRoute: { value: { path: '/admin' } }
}
test('should redirect to /login when user is not authenticated', () => {
const mockNext = jest.fn()
const mockTo = { path: '/admin' }
const mockFrom = { path: '/' }
// 模拟用户未登录状态
jest.mock('@/utils/auth', () => ({
isAuthenticated: false
}))
// 执行守卫逻辑
beforeEach(mockTo, mockFrom, mockNext)
// 验证是否触发了跳转
expect(mockNext).toHaveBeenCalledWith('/login')
// 或如果守卫内用了 router.push:
// expect(mockRouter.push).toHaveBeenCalledWith('/login')
})
使用 createRouter + createMemoryHistory 真实初始化 router(推荐)
比起纯手动 Mock,更可靠的方式是创建一个内存路由(createMemoryHistory),让守卫走真实流程,再监听导航或断言 router.currentRoute.value.path:
立即学习“Java免费学习笔记(深入)”;
通过Gate-Info和Gate-News MCP进行宏观驱动的加密货币分析,用于CPI、NFP、美联储、利率、工资等宏观因素与加密货币、日历或指标的关联。
- 避免过度 Mock 导致逻辑脱节
- 可配合
router.isReady()确保路由就绪 - 通过
router.push()触发守卫,再检查最终路径
示例:
import { createRouter, createMemoryHistory } from 'vue-router'
import { beforeEach } from '@/router/index'
const router = createRouter({
history: createMemoryHistory(),
routes: [
{ path: '/admin', name: 'Admin', component: { template: '' } },
{ path: '/login', name: 'Login', component: { template: '' } }
]
})
// 注册守卫(确保它被实际使用)
router.beforeEach(beforeEach)
test('redirects unauthenticated user from /admin to /login', async () => {
// 模拟未登录
jest.mock('@/utils/auth', () => ({ isAuthenticated: false }))
await router.push('/admin')
await router.isReady() // 等待导航完成
expect(router.currentRoute.value.path).toBe('/login')
})
组件内守卫(beforeRouteEnter)怎么测?
这类守卫无法直接调用,需挂载组件并触发路由变化。可用 mount + router-link 或 router.push 模拟进入:
- 用
createRouter+createMemoryHistory创建可测试 router - 将 router 提供给
app.use(router) - 挂载目标组件后,调用
router.push()并等待isReady - 检查组件行为(如是否渲染 login 提示)或 router 路径
关键点:组件内守卫是异步的,务必 await router.isReady() 或用 await nextTick() 确保守卫执行完毕。
小提醒:别忘了还原 Mock
如果用了 jest.mock() 或修改了全局对象(如 auth.isAuthenticated),记得在每个 test 后清理:
jest.clearAllMocks()-
jest.resetModules()(尤其在 mock 模块时) - 或使用
afterEach(() => { jest.restoreAllMocks() })
不复杂但容易忽略 —— 守卫测试的核心不是“跳没跳”,而是“该不该跳”和“跳到哪”,Mock 只是让这个判断过程可观察、可断言。


















