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' const mockMenus = [ { b_id: '1', b_code: 'sys', b_name: '系统', b_menu_type: 'directory', b_parent_id: null, b_canuse: 1, }, { b_id: '2', b_code: 'module', b_name: '模块管理', b_menu_type: 'page', b_parent_id: '1', b_route: '/module/module-management', b_canuse: 1, }, { b_id: '3', b_code: 'menu', b_name: '菜单管理', b_menu_type: 'page', b_parent_id: '1', b_route: '/module/menu-management', b_canuse: 1, }, { b_id: '4', b_code: 'i18n', b_name: '多语言类型', b_menu_type: 'page', b_parent_id: '1', b_route: '/module/i18n-type', 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('普通用户:隐藏编码 module 的菜单(含空目录剪枝)', async () => { mockSModuleData(mockMenus) setUser('u1', 123) await flush() const menus = useMenuStore() await menus.load() const codes = collectCodes(menus.visibleMenus) expect(codes).toContain('sys') expect(codes).toContain('menu') expect(codes).toContain('i18n') expect(codes).not.toContain('module') }) it('普通用户:目录下仅剩 module 子项时,目录整体不渲染', async () => { // 系统目录下只有「模块管理」这一个可用子菜单 mockSModuleData(mockMenus.filter((m) => m.b_code !== 'menu' && m.b_code !== 'i18n')) setUser('u1', 123) await flush() const menus = useMenuStore() await menus.load() expect(menus.visibleMenus).toEqual([]) }) it('g3soft:module 菜单可见', async () => { mockSModuleData(mockMenus) setUser('g3soft', 1) await flush() const menus = useMenuStore() await menus.load() expect(menus.isG3soft).toBe(true) expect(collectCodes(menus.visibleMenus)).toContain('module') }) 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) }) })