Files
huangzd1997 8e828c1204 task-7(壳层/路由): 根路由跳转到首个可见页面,移除硬编码默认页
helpers.firstVisiblePath 深度优先返回首个可路由页面,无页面返回空串;
store 增加 firstVisible;守卫在根路由/无权限时跳首个可见页,全部无页面则
停留根路由展示无菜单空态,删除 redirect:'/account/users' 硬编码。
2026-09-05 14:43:53 +08:00

78 lines
3.4 KiB
TypeScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { readSource } from './helpers.ts'
import { firstVisiblePath } from '../src/router/helpers.ts'
import type { AdminMenuNode } from '../src/types/admin.ts'
function node(partial: Partial<AdminMenuNode> & { key: string; name: string }): AdminMenuNode {
return { key: partial.key, name: partial.name, route: partial.route, children: partial.children }
}
const NESTED: AdminMenuNode[] = [
node({ key: 'a', name: '组A', children: [node({ key: 'a1', name: '无路由' })] }),
node({ key: 'b', name: '组B', children: [
node({ key: 'b1', name: '用户', route: '/account/users' }),
node({ key: 'b2', name: '菜单', route: '/account/menus' }),
] }),
]
test('test_task_007_first_route_redirect_normal_primary_path', () => {
// 正常主路径:深度优先返回第一个可见页面。
assert.equal(firstVisiblePath(NESTED), '/account/users')
})
test('test_task_007_first_route_redirect_normal_variant_input', () => {
// 正常变体:另一棵树返回其自身首个可见页,不依赖固定页。
const tree: AdminMenuNode[] = [
node({ key: 'x', name: '顶级', route: '/shop/list' }),
node({ key: 'y', name: '后置', route: '/tasks/list' }),
]
assert.equal(firstVisiblePath(tree), '/shop/list')
})
test('test_task_007_first_route_redirect_normal_repeated_operation_is_idempotent', () => {
// 正常重复:结果稳定、不修改输入。
const snapshot = JSON.stringify(NESTED)
assert.equal(firstVisiblePath(NESTED), firstVisiblePath(NESTED))
assert.equal(JSON.stringify(NESTED), snapshot)
})
test('test_task_007_first_route_redirect_boundary_empty_input', () => {
// 边界空值:无任何菜单返回空串,不硬编码缺省页。
assert.equal(firstVisiblePath([]), '')
assert.equal(firstVisiblePath(undefined), '')
assert.equal(firstVisiblePath(null), '')
})
test('test_task_007_first_route_redirect_boundary_single_item', () => {
// 边界单元素:仅一个顶层页面时返回它。
assert.equal(firstVisiblePath([node({ key: 's', name: '单页', route: '/solo' })]), '/solo')
})
test('test_task_007_first_route_redirect_boundary_limit_or_missing_field', () => {
// 边界上限:只有无路由子项的分组不产出可见页。
const onlyEmptyGroups: AdminMenuNode[] = [
node({ key: 'g', name: '空组', children: [node({ key: 'c', name: '不可点' })] }),
]
assert.equal(firstVisiblePath(onlyEmptyGroups), '')
})
test('test_task_007_first_route_redirect_invalid_input_rejected', () => {
// 异常输入:畸形节点被跳过并继续找下一个可见页。
const withMalformed: AdminMenuNode[] = [
{ key: 'bad', name: '畸形', route: '' } as unknown as AdminMenuNode,
node({ key: 'ok', name: '可见', route: '/fine' }),
]
assert.equal(firstVisiblePath(withMalformed), '/fine')
})
test('test_task_007_first_route_redirect_dependency_failure_returns_actionable_message', () => {
// 依赖失败:根跳转由会话首个可见页驱动,不再硬编码 account/users。
const router = readSource('src/router/index.ts')
assert.equal(router.includes('redirect: \'/account/users\''), false, '禁止硬编码根跳转缺省页')
assert.equal(router.includes('firstVisible'), true, '守卫必须使用会话首个可见页')
const store = readSource('src/stores/admin-session.ts')
assert.match(store, /firstVisible:/)
assert.match(store, /firstVisiblePath/)
})