import { describe, it, expect, beforeEach } from 'vitest' import { createRouter, createWebHistory } from 'vue-router' import type { RouteRecordRaw } from 'vue-router' const mockLocalStorage = { store: {} as Record, getItem(key: string) { return this.store[key] || null }, setItem(key: string, value: string) { this.store[key] = value }, removeItem(key: string) { delete this.store[key] }, clear() { this.store = {} } } Object.defineProperty(window, 'localStorage', { value: mockLocalStorage }) const createTestRouter = (routes: RouteRecordRaw[]) => { return createRouter({ history: createWebHistory(), routes }) } describe('路由守卫权限检查', () => { beforeEach(() => { mockLocalStorage.clear() }) describe('基础认证检查', () => { it('未登录用户访问受保护路由应重定向到登录页', async () => { const routes: RouteRecordRaw[] = [ { path: '/login', name: 'Login', component: { template: '
Login
' } }, { path: '/', component: { template: '
Layout
' }, meta: { requiresAuth: true }, children: [ { path: 'dashboard', name: 'Dashboard', component: { template: '
Dashboard
' } } ] } ] const router = createTestRouter(routes) router.beforeEach((to, _from, next) => { const token = localStorage.getItem('token') if (to.meta.requiresAuth && !token) { next('/login') } else { next() } }) await router.push('/dashboard') expect(router.currentRoute.value.path).toBe('/login') }) it('已登录用户访问受保护路由应允许通过', async () => { mockLocalStorage.setItem('token', 'valid-token') const routes: RouteRecordRaw[] = [ { path: '/login', name: 'Login', component: { template: '
Login
' } }, { path: '/', component: { template: '
Layout
' }, meta: { requiresAuth: true }, children: [ { path: 'dashboard', name: 'Dashboard', component: { template: '
Dashboard
' } } ] } ] const router = createTestRouter(routes) router.beforeEach((to, _from, next) => { const token = localStorage.getItem('token') if (to.meta.requiresAuth && !token) { next('/login') } else { next() } }) await router.push('/dashboard') expect(router.currentRoute.value.path).toBe('/dashboard') }) }) describe('角色权限检查', () => { it('普通用户访问管理员路由应重定向到403页面', async () => { mockLocalStorage.setItem('token', 'valid-token') mockLocalStorage.setItem('roles', JSON.stringify(['user'])) const routes: RouteRecordRaw[] = [ { path: '/login', name: 'Login', component: { template: '
Login
' } }, { path: '/403', name: 'Forbidden', component: { template: '
403 Forbidden
' } }, { path: '/', component: { template: '
Layout
' }, meta: { requiresAuth: true }, children: [ { path: 'dashboard', name: 'Dashboard', component: { template: '
Dashboard
' } }, { path: 'users', name: 'UserManagement', component: { template: '
UserManagement
' }, meta: { roles: ['admin'] } } ] } ] const router = createTestRouter(routes) router.beforeEach((to, _from, next) => { const token = localStorage.getItem('token') const rolesStr = localStorage.getItem('roles') const userRoles = rolesStr ? JSON.parse(rolesStr) : [] if (to.meta.requiresAuth && !token) { next('/login') return } if (to.meta.roles && Array.isArray(to.meta.roles)) { const hasRole = to.meta.roles.some((role: string) => userRoles.includes(role)) if (!hasRole) { next('/403') return } } next() }) await router.push('/users') expect(router.currentRoute.value.path).toBe('/403') }) it('管理员用户访问管理员路由应允许通过', async () => { mockLocalStorage.setItem('token', 'valid-token') mockLocalStorage.setItem('roles', JSON.stringify(['admin'])) const routes: RouteRecordRaw[] = [ { path: '/login', name: 'Login', component: { template: '
Login
' } }, { path: '/403', name: 'Forbidden', component: { template: '
403 Forbidden
' } }, { path: '/', component: { template: '
Layout
' }, meta: { requiresAuth: true }, children: [ { path: 'dashboard', name: 'Dashboard', component: { template: '
Dashboard
' } }, { path: 'users', name: 'UserManagement', component: { template: '
UserManagement
' }, meta: { roles: ['admin'] } } ] } ] const router = createTestRouter(routes) router.beforeEach((to, _from, next) => { const token = localStorage.getItem('token') const rolesStr = localStorage.getItem('roles') const userRoles = rolesStr ? JSON.parse(rolesStr) : [] if (to.meta.requiresAuth && !token) { next('/login') return } if (to.meta.roles && Array.isArray(to.meta.roles)) { const hasRole = to.meta.roles.some((role: string) => userRoles.includes(role)) if (!hasRole) { next('/403') return } } next() }) await router.push('/users') expect(router.currentRoute.value.path).toBe('/users') }) it('无角色要求的路由所有登录用户都可访问', async () => { mockLocalStorage.setItem('token', 'valid-token') mockLocalStorage.setItem('roles', JSON.stringify(['user'])) const routes: RouteRecordRaw[] = [ { path: '/login', name: 'Login', component: { template: '
Login
' } }, { path: '/', component: { template: '
Layout
' }, meta: { requiresAuth: true }, children: [ { path: 'dashboard', name: 'Dashboard', component: { template: '
Dashboard
' } } ] } ] const router = createTestRouter(routes) router.beforeEach((to, _from, next) => { const token = localStorage.getItem('token') const rolesStr = localStorage.getItem('roles') const userRoles = rolesStr ? JSON.parse(rolesStr) : [] if (to.meta.requiresAuth && !token) { next('/login') return } if (to.meta.roles && Array.isArray(to.meta.roles)) { const hasRole = to.meta.roles.some((role: string) => userRoles.includes(role)) if (!hasRole) { next('/403') return } } next() }) await router.push('/dashboard') expect(router.currentRoute.value.path).toBe('/dashboard') }) }) })