46622d9f42
parseMenuTree 兼容 data:{items}/{items}/数组信封,空树返回 [](与接口失败抛错
区分),success=false 抛后端 message;session.ts fetchAdminMenuTree 已复用;
单测 8 用例覆盖分组/单页/空/缺 route/异常,live 024 用真实菜单树验证。
76 lines
3.2 KiB
TypeScript
76 lines
3.2 KiB
TypeScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { readSource } from './helpers.ts'
|
|
import { parseMenuTree } from '../src/api/session-model.ts'
|
|
|
|
const GROUPED = {
|
|
success: true,
|
|
data: {
|
|
items: [
|
|
{ key: 'admin_group_account', name: '账号与权限', children: [
|
|
{ key: 'admin_users', name: '用户管理', route: '/account/users' },
|
|
] },
|
|
],
|
|
},
|
|
}
|
|
|
|
test('test_task_024_menu_tree_adapter_normal_primary_path', () => {
|
|
// 正常主路径:data:{items} 树形信封解出分组与页面。
|
|
const tree = parseMenuTree(GROUPED)
|
|
assert.equal(tree.length, 1)
|
|
assert.equal(tree[0].key, 'admin_group_account')
|
|
assert.equal(tree[0].children?.[0].route, '/account/users')
|
|
})
|
|
|
|
test('test_task_024_menu_tree_adapter_normal_variant_input', () => {
|
|
// 正常变体:数组直传与 {items} 信封均可解析。
|
|
const direct = parseMenuTree([{ key: 'a', name: '甲' }])
|
|
assert.equal(direct.length, 1)
|
|
const envelope = parseMenuTree({ success: true, items: [{ key: 'b', name: '乙', route: '/b' }] })
|
|
assert.equal(envelope[0].route, '/b')
|
|
})
|
|
|
|
test('test_task_024_menu_tree_adapter_normal_repeated_operation_is_idempotent', () => {
|
|
// 正常重复:解析稳定、不改输入。
|
|
assert.deepEqual(parseMenuTree(GROUPED), parseMenuTree(GROUPED))
|
|
assert.deepEqual(GROUPED, {
|
|
success: true,
|
|
data: { items: [{ key: 'admin_group_account', name: '账号与权限', children: [{ key: 'admin_users', name: '用户管理', route: '/account/users' }] }] },
|
|
})
|
|
})
|
|
|
|
test('test_task_024_menu_tree_adapter_boundary_empty_input', () => {
|
|
// 边界空值:空 items/空数组/缺省按空树处理,不抛错(与接口失败区分)。
|
|
assert.deepEqual(parseMenuTree({ success: true, data: { items: [] } }), [])
|
|
assert.deepEqual(parseMenuTree({ success: true, items: [] }), [])
|
|
assert.deepEqual(parseMenuTree({ success: true, data: {} }), [])
|
|
assert.deepEqual(parseMenuTree([]), [])
|
|
})
|
|
|
|
test('test_task_024_menu_tree_adapter_boundary_single_item', () => {
|
|
// 边界单元素:单个分组节点返回。
|
|
const tree = parseMenuTree({ data: { items: [{ key: 'g', name: '分组' }] } })
|
|
assert.equal(tree.length, 1)
|
|
assert.equal(tree[0].name, '分组')
|
|
})
|
|
|
|
test('test_task_024_menu_tree_adapter_boundary_limit_or_missing_field', () => {
|
|
// 边界上限/缺字段:页面缺 route 不崩溃;group 无 route 合法。
|
|
const tree = parseMenuTree({ items: [{ key: 'g', name: '组', children: [{ key: 'p', name: '页' }] }] })
|
|
assert.equal(tree[0].children?.[0].route, undefined)
|
|
})
|
|
|
|
test('test_task_024_menu_tree_adapter_invalid_input_rejected', () => {
|
|
// 异常输入:success=false 视为接口失败并抛错(区别于空权限)。
|
|
assert.throws(() => parseMenuTree({ success: false, message: '未登录', code: 401 }), /未登录/)
|
|
assert.deepEqual(parseMenuTree(null as unknown as { items?: [] }), [])
|
|
})
|
|
|
|
test('test_task_024_menu_tree_adapter_dependency_failure_returns_actionable_message', () => {
|
|
// 依赖失败:会话适配调用菜单解析器;后端按 sort 顺序原样返回(前端不重排)。
|
|
const session = readSource('src/api/session.ts')
|
|
assert.match(session, /parseMenuTree/)
|
|
const model = readSource('src/api/session-model.ts')
|
|
assert.match(model, /parseMenuTree/)
|
|
})
|