109 lines
3.9 KiB
JavaScript
109 lines
3.9 KiB
JavaScript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
||
import { setActivePinia, createPinia } from 'pinia'
|
||
import { useAuthStore } from '@/stores/auth'
|
||
import { usePermissionStore } from '@/stores/permissions'
|
||
import { createTestPinia } from './helpers/app.js'
|
||
import router from '@/router'
|
||
|
||
// mock 后端数据接口
|
||
vi.mock('@/services/api', () => ({
|
||
loadDataApi: vi.fn(),
|
||
}))
|
||
|
||
import { loadDataApi } from '@/services/api'
|
||
|
||
const mockModules = [
|
||
{
|
||
b_id: '1',
|
||
b_code: 'm1',
|
||
b_name: 'M1',
|
||
b_canuse: 1,
|
||
b_canmenu: 1,
|
||
b_module_type: 'directory',
|
||
b_parent_id: null,
|
||
b_icon: '',
|
||
b_route: '',
|
||
},
|
||
]
|
||
|
||
beforeEach(() => {
|
||
localStorage.clear()
|
||
sessionStorage.clear()
|
||
setActivePinia(createPinia())
|
||
loadDataApi.mockReset()
|
||
loadDataApi.mockImplementation((view) =>
|
||
Promise.resolve({ data: view === 's_module' ? mockModules : [], code: 0, success: true }),
|
||
)
|
||
// 回到登录页,断开受保护路由状态
|
||
return router.push('/login').catch(() => {})
|
||
})
|
||
|
||
afterEach(() => {
|
||
if (router.hasRoute('biz')) router.removeRoute('biz')
|
||
})
|
||
|
||
describe('路由守卫 权限加载(三场景)', () => {
|
||
it('场景·未登录:访问受保护页 → 重定向 /login?redirect', async () => {
|
||
await router.push('/dashboard')
|
||
expect(router.currentRoute.value.path).toBe('/login')
|
||
expect(router.currentRoute.value.query.redirect).toBe('/dashboard')
|
||
})
|
||
|
||
it('场景·登录:访问受保护页 → 触发 load,菜单数据就绪(同主体不重复请求)', async () => {
|
||
const auth = useAuthStore()
|
||
auth.setSession({ token: 't', user: { id: 123, account: 'u1', name: 'U' } }, 'ORG')
|
||
await router.push('/dashboard')
|
||
expect(loadDataApi).toHaveBeenCalled()
|
||
expect(usePermissionStore().modules.length).toBe(1)
|
||
// 再次进入另一受保护页(同主体)不应重复发请求
|
||
loadDataApi.mockClear()
|
||
await router.push('/test/list')
|
||
expect(loadDataApi).not.toHaveBeenCalled()
|
||
})
|
||
|
||
it('场景·登录:访问无权限 moduleId 路由 → 重定向 /dashboard', async () => {
|
||
const auth = useAuthStore()
|
||
auth.setSession({ token: 't', user: { id: 123, account: 'u1', name: 'U' } }, 'ORG')
|
||
router.addRoute({
|
||
path: '/biz',
|
||
name: 'biz',
|
||
component: { render: () => null },
|
||
meta: { requiresAuth: true, moduleId: 'm-no' },
|
||
})
|
||
await router.push('/biz')
|
||
expect(router.currentRoute.value.path).toBe('/dashboard')
|
||
})
|
||
|
||
it('场景·刷新已登录态:persist 恢复后守卫 load 成功,无 clear 竞态', async () => {
|
||
// 按 pinia-plugin-persistedstate v4 的实际存储格式写入(纯 state JSON,无 {state, version} 包装)
|
||
sessionStorage.setItem(
|
||
'fms-login',
|
||
JSON.stringify({ loginInfo: { token: 't', user: { id: 123, account: 'u1', name: 'U' } } }),
|
||
)
|
||
localStorage.setItem(
|
||
'fms-user',
|
||
JSON.stringify({ userInfo: { orgId: 'ORG', account: 'u1' } }),
|
||
)
|
||
// 用 createTestPinia(内部已 install,persist 插件真实注册),等价于刷新页面
|
||
const pinia = createTestPinia()
|
||
const a = useAuthStore() // 首次创建
|
||
await a.$hydrate() // 显式从 localStorage 恢复(等价于刷新页面)
|
||
expect(useAuthStore().isAuthenticated).toBe(true)
|
||
await router.push('/dashboard')
|
||
expect(usePermissionStore().modules.length).toBe(1)
|
||
})
|
||
|
||
it('场景·切换账号:旧主体请求作废,新主体重新加载', async () => {
|
||
const auth = useAuthStore()
|
||
auth.setSession({ token: 't', user: { id: 123, account: 'u1', name: 'U' } }, 'ORG')
|
||
await router.push('/dashboard')
|
||
expect(usePermissionStore().modules.length).toBe(1)
|
||
// 切换到另一账号
|
||
auth.setSession({ token: 't2', user: { id: 999, account: 'u2', name: 'U2' } }, 'ORG2')
|
||
loadDataApi.mockClear()
|
||
await router.push('/test/list')
|
||
expect(loadDataApi).toHaveBeenCalled() // 新主体重新加载
|
||
expect(usePermissionStore().modules.length).toBe(1)
|
||
})
|
||
})
|