import { describe, expect, it } from 'vitest' import { createMemoryHistory, createRouter } from 'vue-router' import { menuRouteOptions, routes } from '@/router/routes' /** * 路由分组(/module)的契约测试。 * 分组节点必须保持「无 component」:一旦给它配容器组件(内部再放 router-view), * 页面会下沉一层、脱离 DefaultLayout 的 keep-alive,缓存静默失效。 */ function createTestRouter() { return createRouter({ history: createMemoryHistory(), routes }) } describe('路由分组(嵌套结构)', () => { it('分组内子路由解析出完整路径,分组节点不带可渲染组件', async () => { const router = createTestRouter() await router.push('/module/i18n-type') const matched = router.currentRoute.value.matched expect(matched.map((record) => record.path)).toEqual(['/', '/module', '/module/i18n-type']) // 分组节点无 components:RouterView 会跳过它,子页仍渲染在 DefaultLayout 的 router-view 上 expect(matched[1].components).toBeFalsy() // meta 由父到子合并,子记录的 componentName 决定 keep-alive 的 include 名 expect(router.currentRoute.value.meta.componentName).toBe('I18nTypeManagement') }) it('访问分组路径本身会重定向到首个子页(不会白屏)', async () => { const router = createTestRouter() await router.push('/module') expect(router.currentRoute.value.path).toBe('/module/module-management') }) it('菜单路由选项:排除模块中心(adminOnly)整组与分组节点/动态/通配路由', () => { const values = menuRouteOptions.map((option) => option.value) // 模块中心是系统管理员专用页(meta.adminOnly):整组排除, // 「菜单管理」的路由下拉配不出第二入口 expect(values).not.toContain('/module/module-management') expect(values).not.toContain('/module/menu-management') expect(values).not.toContain('/module/i18n-type') expect(values).toContain('/dashboard') // 分组节点本身、详情页(:id)、404 通配、登录页都不是菜单入口 expect(values).not.toContain('/module') expect(values).not.toContain('/detail/:id') expect(values).not.toContain('/login') }) })