Files
workspace/code/fms/fms-vue/tests/menus.spec.js
T
2026-09-13 23:16:08 +08:00

136 lines
3.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useAuthStore } from '@/stores/auth'
import { useMenuStore } from '@/stores/menus'
// mock 后端数据接口,避免真实网络请求
vi.mock('@/services/api', () => ({
loadDataApi: vi.fn(),
}))
import { loadDataApi } from '@/services/api'
// 模块中心等系统管理员专用页面不进 s_menu(入口固定在 AppSidebar、路由层 adminOnly 拦截),
// 因此这里用业务菜单构造数据,验证菜单 store 本身无任何编码/账号特判。
const mockMenus = [
{
b_id: '1',
b_code: 'base',
b_name: '基础数据',
b_menu_type: 'directory',
b_parent_id: null,
b_canuse: 1,
},
{
b_id: '2',
b_code: 'contact',
b_name: '往来单位',
b_menu_type: 'page',
b_parent_id: '1',
b_route: '/base/contact',
b_canuse: 1,
},
{
// 没有任何子项的目录:可见性裁剪后不应渲染
b_id: '3',
b_code: 'empty-dir',
b_name: '空目录',
b_menu_type: 'directory',
b_parent_id: null,
b_canuse: 1,
},
]
function mockSModuleData(menus) {
loadDataApi.mockImplementation((view) =>
Promise.resolve({
data: view === 's_menu' ? menus : [],
code: 0,
success: true,
}),
)
}
function setUser(account, id) {
const auth = useAuthStore()
auth.setSession({ token: 't', user: { id, account } }, 'ORG')
}
/** 冲刷微任务:让 setSession 触发的 watch(clear) 先执行 */
const flush = () => Promise.resolve()
function collectCodes(nodes) {
const codes = []
for (const node of nodes) {
codes.push(String(node.b_code))
if (node.children) codes.push(...collectCodes(node.children))
}
return codes
}
beforeEach(() => {
setActivePinia(createPinia())
loadDataApi.mockReset()
})
describe('menus store(s_menu 动态菜单)', () => {
it('普通用户:全部启用菜单按树渲染,空目录剪枝(无编码特判)', async () => {
mockSModuleData(mockMenus)
setUser('u1', 123)
await flush()
const menus = useMenuStore()
await menus.load()
const codes = collectCodes(menus.visibleMenus)
expect(codes).toContain('base')
expect(codes).toContain('contact')
// 目录没有可见子菜单时不渲染
expect(codes).not.toContain('empty-dir')
})
it('管理员特判不在菜单 store:g3soft 与普通用户渲染一致', async () => {
// 模块中心的管控在路由守卫(meta.adminOnly)与侧栏渲染(仅 g3soft 追加固定入口),
// 菜单 store 对所有登录主体一视同仁
mockSModuleData(mockMenus)
setUser('g3soft', 1)
await flush()
const menus = useMenuStore()
await menus.load()
const codes = collectCodes(menus.visibleMenus)
expect(codes).toHaveLength(2)
expect(codes).toEqual(expect.arrayContaining(['base', 'contact']))
})
it('同一主体重复 load 不重复发请求', async () => {
mockSModuleData(mockMenus)
setUser('u1', 123)
await flush()
const menus = useMenuStore()
await menus.load()
await menus.load()
expect(loadDataApi).toHaveBeenCalledTimes(1)
})
it('切换账号:缓存清空并重新加载', async () => {
mockSModuleData(mockMenus)
setUser('u1', 123)
await flush()
const menus = useMenuStore()
await menus.load()
expect(menus.rawMenus.length).toBe(mockMenus.length)
// 切换到另一个主体:watch(clear) 清空已加载数据
setUser('u2', 999)
await flush()
await flush()
expect(menus.rawMenus.length).toBe(0)
expect(menus.visibleMenus).toEqual([])
// 新主体 load 重新拉取
loadDataApi.mockClear()
await menus.load()
expect(menus.rawMenus.length).toBe(mockMenus.length)
})
})