import { describe, it, expect, vi, beforeEach } from 'vitest'; import { mount, VueWrapper } from '@vue/test-utils'; import { createPinia, setActivePinia } from 'pinia'; import { createRouter, createMemoryHistory } from 'vue-router'; import { useAppStore } from '@/stores/app.store'; import { useAuthStore } from '@/stores/auth.store'; const mockRoutes = [ { path: '/', name: 'Layout', component: { template: '
' }, children: [ { path: '/dashboard', name: 'Dashboard', component: { template: '
' }, meta: { title: '仪表盘', icon: 'DashboardOutlined' } }, { path: '/users', name: 'Users', component: { template: '
' }, meta: { title: '用户管理', icon: 'UserOutlined' } }, { path: '/system', name: 'System', component: { template: '
' }, meta: { title: '系统管理', icon: 'SettingOutlined' }, children: [ { path: '/system/roles', name: 'Roles', component: { template: '
' }, meta: { title: '角色管理', icon: 'LockOutlined' } }, { path: '/system/menus', name: 'Menus', component: { template: '
' }, meta: { title: '菜单管理', icon: 'MenuOutlined' } } ] }, { path: '/hidden', name: 'Hidden', component: { template: '
' }, meta: { title: '隐藏菜单', icon: 'SettingOutlined', hidden: true } } ] } ]; const router = createRouter({ history: createMemoryHistory(), routes: mockRoutes }); vi.mock('@/router', () => ({ resetRouter: vi.fn(), default: router })); vi.mock('vue-router', async (importOriginal) => { const actual = await importOriginal(); return { ...actual, useRouter: () => router, useRoute: () => router.currentRoute.value }; }); import Sidebar from '@/components/Sidebar.vue'; describe('Sidebar 组件', () => { let wrapper: VueWrapper; let appStore: ReturnType; let authStore: ReturnType; beforeEach(() => { setActivePinia(createPinia()); appStore = useAppStore(); authStore = useAuthStore(); authStore.user = { id: 1, username: 'admin', email: 'admin@example.com', phone: '13800138000', status: 'ACTIVE', permissions: ['dashboard:view', 'user:view', 'role:view', 'menu:view'] }; wrapper = mount(Sidebar, { global: { plugins: [router], stubs: { 'MenuOutlined': true, 'DashboardOutlined': true, 'UserOutlined': true, 'LockOutlined': true, 'SettingOutlined': true } } }); vi.clearAllMocks(); }); describe('初始状态', () => { it('应该正确渲染组件', () => { expect(wrapper.exists()).toBe(true); }); it('应该显示侧边栏', () => { expect(wrapper.find('.sidebar').exists()).toBe(true); }); it('应该显示菜单', () => { expect(wrapper.find('.sidebar-menu').exists()).toBe(true); }); }); describe('侧边栏折叠', () => { it('应该响应侧边栏折叠状态', () => { appStore.toggleSidebar(); expect(wrapper.vm.collapsed).toBe(true); }); it('折叠时应该显示图标而不是文字', async () => { appStore.setSidebarCollapsed(true); await wrapper.vm.$nextTick(); expect(wrapper.vm.collapsed).toBe(true); }); }); describe('菜单项生成', () => { it('应该根据路由生成菜单项', () => { const menuItems = wrapper.vm.menuItems; expect(menuItems).toBeDefined(); expect(Array.isArray(menuItems)).toBe(true); }); it('应该隐藏标记为hidden的菜单项', () => { const menuItems = wrapper.vm.menuItems; const hiddenItem = menuItems.find((item: any) => item.key === 'Hidden'); expect(hiddenItem).toBeUndefined(); }); it('应该包含仪表盘菜单项', () => { const menuItems = wrapper.vm.menuItems; const dashboardItem = menuItems.find((item: any) => item.key === 'Dashboard'); expect(dashboardItem).toBeDefined(); expect(dashboardItem.label).toBe('仪表盘'); }); }); describe('菜单选择', () => { it('应该能够选择菜单项', async () => { await wrapper.vm.handleMenuSelect({ key: 'Dashboard' }); expect(wrapper.emitted('menuSelect')).toBeTruthy(); expect(wrapper.emitted('menuSelect')?.[0]).toEqual(['Dashboard']); }); it('选择菜单项应该导航到对应路由', async () => { const pushSpy = vi.spyOn(router, 'push'); await wrapper.vm.handleMenuSelect({ key: 'Dashboard' }); expect(pushSpy).toHaveBeenCalledWith('/dashboard'); pushSpy.mockRestore(); }); }); describe('权限控制', () => { it('应该检查用户权限', () => { const hasPermission = wrapper.vm.hasPermission('user:view'); expect(hasPermission).toBe(true); }); it('没有权限的菜单项应该被隐藏', () => { authStore.user = { id: 1, username: 'admin', email: 'admin@example.com', phone: '13800138000', status: 'ACTIVE', permissions: [] }; const hasPermission = wrapper.vm.hasPermission('user:view'); expect(hasPermission).toBe(false); }); it('未定义权限的菜单项应该显示', () => { const hasPermission = wrapper.vm.hasPermission(undefined); expect(hasPermission).toBe(true); }); }); describe('路由监听', () => { it('应该更新选中的菜单项', () => { expect(wrapper.vm.selectedKeys).toContain('Dashboard'); }); it('应该展开包含当前路由的父菜单', () => { const openKeys = wrapper.vm.openKeys; expect(Array.isArray(openKeys)).toBe(true); }); }); describe('主题和模式', () => { it('应该接受主题属性', () => { const wrapperWithLightTheme = mount(Sidebar, { props: { theme: 'light' }, global: { plugins: [router], stubs: { 'a-layout-sider': { template: '' }, 'a-menu': { template: '' } } } }); expect(wrapperWithLightTheme.exists()).toBe(true); }); it('应该接受模式属性', () => { const wrapperWithVerticalMode = mount(Sidebar, { props: { mode: 'vertical' }, global: { plugins: [router], stubs: { 'a-layout-sider': { template: '' }, 'a-menu': { template: '' } } } }); expect(wrapperWithVerticalMode.exists()).toBe(true); }); }); });