task-9(壳层/路由): 实现路由 meta 菜单 key 约定与 RouteMeta 类型增强

新增 src/types/vue-router.d.ts 模块增强(RouteMeta.title/menuKey),meta.ts 提供
metaMenuKey/命名校验,router 守卫改类型化访问去掉 as cast,AdminLayout 标题同步
去 cast;校验首批注册表 menuKey 合规。
This commit is contained in:
2026-09-05 12:20:14 +08:00
parent 02e0dc20b8
commit ab7255a55b
5 changed files with 118 additions and 2 deletions
+72
View File
@@ -0,0 +1,72 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { readSource } from './helpers.ts'
import {
ADMIN_MENU_KEY_PATTERN,
isValidMenuKey,
metaMenuKey,
validateRouteMenuKeys,
} from '../src/router/meta.ts'
import { adminPages } from '../src/router/routes.ts'
test('test_task_009_route_menu_key_meta_normal_primary_path', () => {
// 正常主路径:合法 menuKey 被识别。
assert.equal(metaMenuKey({ menuKey: 'admin_users' }), 'admin_users')
assert.equal(isValidMenuKey('admin_users'), true)
assert.equal(ADMIN_MENU_KEY_PATTERN.test('admin_users'), true)
})
test('test_task_009_route_menu_key_meta_normal_variant_input', () => {
// 正常变体:另一合法 key(含数字)也能识别。
assert.equal(isValidMenuKey('admin_group_manage'), true)
assert.equal(isValidMenuKey('asin_center2'), true)
})
test('test_task_009_route_menu_key_meta_normal_repeated_operation_is_idempotent', () => {
// 正常重复:读取与校验幂等。
assert.equal(metaMenuKey({ menuKey: 'shop_list' }), metaMenuKey({ menuKey: 'shop_list' }))
assert.equal(isValidMenuKey('shop_list'), isValidMenuKey('shop_list'))
})
test('test_task_009_route_menu_key_meta_boundary_empty_input', () => {
// 边界空值:无 meta/无 menuKey 回退空串;空串 key 不参与命名约束。
assert.equal(metaMenuKey(undefined), '')
assert.equal(metaMenuKey({}), '')
assert.equal(metaMenuKey({ menuKey: '' }), '')
assert.deepEqual(validateRouteMenuKeys([]), [])
})
test('test_task_009_route_menu_key_meta_boundary_single_item', () => {
// 边界单元素:单条带合法 key 的注册记录无校验问题。
assert.deepEqual(validateRouteMenuKeys([{ path: 'a/b', menuKey: 'admin_x' }]), [])
})
test('test_task_009_route_menu_key_meta_boundary_limit_or_missing_field', () => {
// 边界上限/缺字段:重复 key、驼峰/连字符/数字开头 key 均被校验拒绝。
const issues = validateRouteMenuKeys([
{ path: 'a', menuKey: 'dup' },
{ path: 'b', menuKey: 'dup' },
{ path: 'c', menuKey: 'CamelKey' },
{ path: 'd', menuKey: 'kebab-key' },
{ path: 'e', menuKey: '1digit' },
])
assert.ok(issues.some((i) => i.includes('重复')))
assert.ok(issues.some((i) => i.includes('命名非法')))
})
test('test_task_009_route_menu_key_meta_invalid_input_rejected', () => {
// 异常输入:非字符串 menuKey 回退空串,不崩溃、不参与校验。
assert.equal(metaMenuKey({ menuKey: 123 }), '')
assert.equal(metaMenuKey({ menuKey: null }), '')
assert.deepEqual(validateRouteMenuKeys([{ path: 'x', menuKey: 1 }, { path: 'y' }]), [])
})
test('test_task_009_route_menu_key_meta_dependency_failure_returns_actionable_message', () => {
// 依赖失败:RouteMeta 已增强类型;守卫使用类型化 meta;注册表 menuKey 全部合规。
const dts = readSource('src/types/vue-router.d.ts')
assert.match(dts, /interface RouteMeta/)
assert.match(dts, /menuKey\?: string/)
const router = readSource('src/router/index.ts')
assert.equal(router.includes('as string | undefined'), false, 'menuKey 应为类型化访问,禁止 cast')
assert.deepEqual(validateRouteMenuKeys(adminPages), [])
})