import test from 'node:test' import assert from 'node:assert/strict' import { readSource } from './helpers.ts' import { MENU_TYPE_OPTIONS, menuParentCandidates, menuSiblingGroupKey, menuTypeLabel, siblingOrderAfterDrop, toMenuReorderRequest, type MenuManageNode, } from '../src/pages/account/menu-manage-model.ts' /** 对齐 admin.js:6799-6830(全量列/类型文案 后台|软件)与 6882-6964(同级拖拽 + reorder 载荷)。 */ function node(id: number, menuType = 'admin', parentId: number | null = null): MenuManageNode { return { id, name: `菜单${id}`, columnKey: `k${id}`, parentId, menuType, routePath: `/r/${id}`, sortOrder: id } } test('align_menu_type_label_matches_reference', () => { // 参考:admin → 后台,其余一律 → 软件(含空值)。 assert.equal(menuTypeLabel('admin'), '后台') assert.equal(menuTypeLabel('app'), '软件') assert.equal(menuTypeLabel('APP'), '软件') assert.equal(menuTypeLabel(null), '软件') assert.equal(menuTypeLabel(undefined), '软件') }) test('align_menu_type_options_backend_software', () => { assert.deepEqual(MENU_TYPE_OPTIONS, [ { value: 'admin', label: '后台' }, { value: 'app', label: '软件' }, ]) }) test('align_menu_sibling_group_key_is_type_plus_parent', () => { assert.equal(menuSiblingGroupKey(node(1, 'admin', 5)), 'admin|5') assert.equal(menuSiblingGroupKey(node(2, 'app', null)), 'app|') assert.equal(menuSiblingGroupKey(node(3, 'app', 5)), 'app|5') }) test('align_menu_sibling_order_after_drop_before_target', () => { const group = [1, 2, 3, 4] assert.deepEqual(siblingOrderAfterDrop(group, 4, 2, false), [1, 4, 2, 3]) }) test('align_menu_sibling_order_after_drop_after_target', () => { const group = [1, 2, 3, 4] assert.deepEqual(siblingOrderAfterDrop(group, 4, 2, true), [1, 2, 4, 3]) }) test('align_menu_sibling_order_after_drop_invalid_returns_original', () => { const group = [1, 2, 3] assert.deepEqual(siblingOrderAfterDrop(group, 9, 2, false), group) assert.deepEqual(siblingOrderAfterDrop(group, 1, 9, true), group) assert.deepEqual(siblingOrderAfterDrop(group, 2, 2, false), group) assert.deepEqual(siblingOrderAfterDrop([], 1, 2, false), []) }) test('align_menu_parent_candidates_same_type_only', () => { const nodes = [node(1, 'admin', null), node(2, 'app', null), node(3, 'admin', 1), node(4, 'app', 2)] assert.deepEqual(menuParentCandidates(nodes, 'admin').map((n) => n.id), [1, 3]) assert.deepEqual(menuParentCandidates(nodes, 'app').map((n) => n.id), [2, 4]) }) test('align_menu_reorder_request_includes_menu_type', () => { // 参考 persistColumnOrder 载荷:{ menu_type, ordered_ids }。 assert.deepEqual(toMenuReorderRequest('admin', [1, 2, 3]), { menu_type: 'admin', ordered_ids: [1, 2, 3] }) assert.deepEqual(toMenuReorderRequest('', [1]), { menu_type: 'app', ordered_ids: [1] }) }) test('align_menu_list_loads_all_types_no_filter', () => { // 参考 loadColumns 拉全量列(无 menuType 过滤),类型由列内区分。 const api = readSource('src/pages/account/menu-manage-api.ts') assert.doesNotMatch(api, /params:\s*\{\s*menuType/, '列表请求不再按 admin 过滤') assert.match(api, /ordered_ids/, '重排载荷带 ordered_ids') assert.match(api, /menu_type/, '重排载荷带 menu_type') }) test('align_menu_page_drag_and_type_wiring', () => { const page = readSource('src/pages/account/MenusPage.vue') assert.match(page, /拖动每行左侧的手柄可调整同级菜单的显示顺序,松开后自动保存/, '顶部拖拽提示文案对齐') assert.match(page, /draggable/, '行手柄可拖拽') assert.match(page, /menuSiblingGroupKey/, '拖拽分组按类型+父级') assert.match(page, /MENU_TYPE_OPTIONS|菜单类型/, '新建/编辑弹窗含菜单类型下拉') assert.match(page, /menuParentCandidates/, '父菜单候选按类型过滤') })