import assert from 'node:assert/strict'; import { describe, it } from 'node:test'; import * as roleResourceTree from '../src/views/system/role/modules/role-resource-tree'; type MenuNode = { id: string; children?: MenuNode[]; }; type NormalizeRoleMenuCheckedIds = (input: { menuTree: MenuNode[]; checkedIds: string[] }) => string[]; const menuTree: MenuNode[] = [ { id: 'personal', children: [ { id: 'weekly', children: [{ id: 'weeklyDetail' }] }, { id: 'monthly', children: [{ id: 'monthlyDetail' }] } ] }, { id: 'infra', children: [{ id: 'stateMachine' }, { id: 'cmd' }] } ]; const normalizeRoleMenuCheckedIds = (roleResourceTree as { normalizeRoleMenuCheckedIds?: NormalizeRoleMenuCheckedIds }) .normalizeRoleMenuCheckedIds; const { resolveRoleMenuSubmitIds } = roleResourceTree; describe('resolveRoleMenuSubmitIds', () => { it('keeps original ids when there is no user interaction', () => { const result = resolveRoleMenuSubmitIds({ menuTree, baselineIds: ['weekly', 'monthly'], dirtyIds: [], checkedIds: ['personal', 'weekly', 'monthly'] }); assert.deepEqual(result, ['weekly', 'monthly']); }); it('preserves untouched branches when another branch changes', () => { const result = resolveRoleMenuSubmitIds({ menuTree, baselineIds: ['weekly', 'monthly'], dirtyIds: ['stateMachine'], checkedIds: ['personal', 'weekly', 'monthly', 'stateMachine'] }); assert.deepEqual(result, ['weekly', 'monthly', 'stateMachine']); }); it('recomputes the whole dirty branch instead of expanding unrelated baseline ids', () => { const result = resolveRoleMenuSubmitIds({ menuTree, baselineIds: ['personal'], dirtyIds: ['weekly'], checkedIds: ['personal', 'weekly', 'weeklyDetail'] }); assert.deepEqual(result, ['personal', 'weekly', 'weeklyDetail']); }); it('does not expand untouched sibling branches under the same ancestor', () => { const result = resolveRoleMenuSubmitIds({ menuTree, baselineIds: ['monthly'], dirtyIds: ['weeklyDetail'], checkedIds: ['personal', 'weekly', 'weeklyDetail', 'monthly', 'monthlyDetail'] }); assert.deepEqual(result, ['weeklyDetail', 'monthly']); }); it('does not submit half-checked parent ids when a fully authorized branch becomes partial', () => { const result = resolveRoleMenuSubmitIds({ menuTree, baselineIds: ['personal'], dirtyIds: ['monthlyDetail'], checkedIds: ['weekly', 'weeklyDetail'] }); assert.deepEqual(result, ['weekly', 'weeklyDetail']); }); }); describe('normalizeRoleMenuCheckedIds', () => { it('removes partially covered parent ids before tree rendering', () => { assert.equal(typeof normalizeRoleMenuCheckedIds, 'function'); const result = normalizeRoleMenuCheckedIds?.({ menuTree, checkedIds: ['personal', 'weekly', 'weeklyDetail'] }); assert.deepEqual(result, ['weekly', 'weeklyDetail']); }); it('keeps parent ids when the backend uses a parent-only full-branch representation', () => { assert.equal(typeof normalizeRoleMenuCheckedIds, 'function'); const result = normalizeRoleMenuCheckedIds?.({ menuTree, checkedIds: ['personal'] }); assert.deepEqual(result, ['personal']); }); });