From 836ea6ecc74116ecee0e9fb07f9d91f1672d268a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Sat, 5 Sep 2026 14:17:43 +0800 Subject: [PATCH] =?UTF-8?q?task-37(=E4=BC=9A=E8=AF=9D/=E8=8F=9C=E5=8D=95/?= =?UTF-8?q?=E6=9D=83=E9=99=90):?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin-frontend-vue/tests/task-37.test.ts | 54 ++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 admin-frontend-vue/tests/task-37.test.ts diff --git a/admin-frontend-vue/tests/task-37.test.ts b/admin-frontend-vue/tests/task-37.test.ts new file mode 100644 index 00000000..fa769af3 --- /dev/null +++ b/admin-frontend-vue/tests/task-37.test.ts @@ -0,0 +1,54 @@ +import test from 'node:test' +import assert from 'node:assert/strict' +import { parseMenuTree } from '../src/api/session-model.ts' +import { toSidebarEntries } from '../src/layout/menu-mapper.ts' + +test('test_task_037_menu_parent_child_normal_primary_path', () => { + // 正常主路径:分组下的子页面作为 children 嵌套保留。 + const tree = parseMenuTree({ data: { items: [{ key: 'g', name: '组', children: [{ key: 'p', name: '页', route: '/p' }] }] } }) + assert.equal(tree[0].children?.[0].key, 'p') +}) + +test('test_task_037_menu_parent_child_normal_variant_input', () => { + // 正常变体:多层父子关系逐层保留(组 > 子组 > 页面)。 + const tree = parseMenuTree({ items: [{ key: 'a', name: 'A', children: [{ key: 'b', name: 'B', children: [{ key: 'c', name: 'C', route: '/c' }] }] }] }) + assert.equal(tree[0].children?.[0].children?.[0].route, '/c') +}) + +test('test_task_037_menu_parent_child_normal_repeated_operation_is_idempotent', () => { + // 正常重复:解析不重建/不污染父子引用结构之外的对象,结果稳定。 + const payload = { data: { items: [{ key: 'g', name: '组', children: [{ key: 'p', name: '页', route: '/p' }] }] } } + assert.deepEqual(parseMenuTree(payload), parseMenuTree(payload)) +}) + +test('test_task_037_menu_parent_child_boundary_empty_input', () => { + // 边界空值:分组无子节点合法(可后续再挂载)。 + const tree = parseMenuTree({ items: [{ key: 'g', name: '组' }] }) + assert.equal(tree[0].children, undefined) +}) + +test('test_task_037_menu_parent_child_boundary_single_item', () => { + // 边界单元素:单个页面节点可直接成为顶级项。 + const tree = parseMenuTree({ items: [{ key: 's', name: '单页', route: '/solo' }] }) + assert.equal(tree.length, 1) + assert.equal(tree[0].route, '/solo') +}) + +test('test_task_037_menu_parent_child_boundary_limit_or_missing_field', () => { + // 边界上限/缺字段:children 为非数组/空时不崩溃。 + const tree = parseMenuTree({ items: [{ key: 'g', name: '组', children: null as unknown as undefined }] }) + assert.equal(tree[0].children, null) +}) + +test('test_task_037_menu_parent_child_invalid_input_rejected', () => { + // 异常输入:整棵非树负载(success=false)抛错,不产生半棵树。 + assert.throws(() => parseMenuTree({ success: false, message: '无权限' }), /无权限/) +}) + +test('test_task_037_menu_parent_child_dependency_failure_returns_actionable_message', () => { + // 依赖失败:渲染层把父子关系映射为分组/子项,校验不丢层级。 + const entries = toSidebarEntries([{ key: 'g', name: '组', children: [{ key: 'p', name: '页', route: '/p' }] }]) + assert.equal(entries.length, 1) + assert.equal(entries[0].kind, 'group') + assert.equal(entries[0].kind === 'group' && entries[0].children[0].route, '/p') +})