import test from 'node:test' import assert from 'node:assert/strict' import { readSource } from './helpers.ts' import { ADMIN_MENU_TYPE, buildMenuManageTree, parseMenuManageList } from '../src/pages/account/menu-manage-model.ts' test('test_task_054_menu_manage_list_normal_primary_path', () => { // 正常主路径:扁平列表按 parentId 组装树、同级按 sort 排序。 const items = parseMenuManageList([ { id: 1, name: '账号权限', column_key: 'account', parent_id: null, route_path: 'group-account', sort_order: 2 }, { id: 2, name: '用户管理', column_key: 'account_users', parent_id: 1, route_path: '/account/users', sort_order: 1 }, { id: 3, name: '菜单管理', column_key: 'admin_columns', parent_id: 1, route_path: '/account/menus', sort_order: 2 }, ]) const tree = buildMenuManageTree(items) assert.equal(tree.length, 1) assert.equal(tree[0].id, 1) assert.equal(tree[0].children?.length, 2) assert.equal(tree[0].children?.[0].columnKey, 'account_users') }) test('test_task_054_menu_manage_list_normal_variant_input', () => { // 正常变体:多个根 + 缺父的子节点按根处理,不丢节点。 const items = parseMenuManageList([ { id: 1, name: 'A', column_key: 'a', parent_id: null }, { id: 2, name: 'B', column_key: 'b', parent_id: 999 }, { id: 3, name: 'C', column_key: 'c', parent_id: null }, ]) const tree = buildMenuManageTree(items) assert.equal(tree.length, 3) const ids = tree.map((n) => n.id).sort((x, y) => x - y) assert.deepEqual(ids, [1, 2, 3]) }) test('test_task_054_menu_manage_list_normal_repeated_operation_is_idempotent', () => { // 正常重复:建树不改输入、结果稳定。 const items = parseMenuManageList([{ id: 1, name: 'A', column_key: 'a', parent_id: null, sort_order: 0 }]) assert.deepEqual(buildMenuManageTree(items), buildMenuManageTree(items)) assert.equal(items[0].sortOrder, 0) }) test('test_task_054_menu_manage_list_boundary_empty_input', () => { // 边界空值:空负载/空数组 → 空树。 assert.deepEqual(parseMenuManageList({}), []) assert.deepEqual(buildMenuManageTree([]), []) }) test('test_task_054_menu_manage_list_boundary_single_item', () => { // 边界单元素:单根成树。 const tree = buildMenuManageTree(parseMenuManageList([{ id: 9, name: 'Only', column_key: 'only', parent_id: null }])) assert.equal(tree.length, 1) assert.equal(tree[0].id, 9) }) test('test_task_054_menu_manage_list_boundary_limit_or_missing_field', () => { // 边界上限/缺字段:缺 sort 用 0;子按 (sort,name) 稳定。 const items = parseMenuManageList([ { id: 1, name: '根', column_key: 'root', parent_id: null }, { id: 2, name: 'b', column_key: 'b', parent_id: 1, sort_order: 2 }, { id: 3, name: 'a', column_key: 'a', parent_id: 1, sort_order: 1 }, ]) const children = buildMenuManageTree(items)[0].children || [] assert.deepEqual(children.map((c) => c.id), [3, 2]) }) test('test_task_054_menu_manage_list_invalid_input_rejected', () => { // 异常输入:缺 id 行被解析过滤,不入树。 const tree = buildMenuManageTree(parseMenuManageList([{ id: 1, name: 'ok', column_key: 'ok' }, { name: 'bad' }])) assert.equal(tree.length, 1) assert.equal(tree[0].name, 'ok') }) test('test_task_054_menu_manage_list_dependency_failure_returns_actionable_message', () => { // 依赖失败/加载走 adapter:页面不再内联 http;api 走 GET permission-menus(menuType=admin)+解析建树。 const model = readSource('src/pages/account/menu-manage-model.ts') assert.equal(/axios|http\./.test(model), false) const page = readSource('src/pages/account/MenusPage.vue') assert.match(page, /menu-manage-api|fetchMenuManageTree/) assert.equal(/http\.get|unwrap\(/.test(page), false, '页面不再内联请求') const api = readSource('src/pages/account/menu-manage-api.ts') assert.match(api, /permission-menus/) assert.match(api, /parseMenuManageList/) assert.match(api, /buildMenuManageTree/) // 对齐 admin.js loadColumns:列表拉全量菜单(不再按 admin 类型过滤),类型在行内区分。 assert.doesNotMatch(api, /menuType:\s*ADMIN_MENU_TYPE/, '列表请求不再过滤 menuType') assert.match(api, /menu_type/, '重排载荷带 menu_type') })