From aad11c71bbc9183974aa04949d448443bededae0 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:44 +0800 Subject: [PATCH] =?UTF-8?q?task-39(=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-39.test.ts | 57 ++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 admin-frontend-vue/tests/task-39.test.ts diff --git a/admin-frontend-vue/tests/task-39.test.ts b/admin-frontend-vue/tests/task-39.test.ts new file mode 100644 index 00000000..de4911f0 --- /dev/null +++ b/admin-frontend-vue/tests/task-39.test.ts @@ -0,0 +1,57 @@ +import test from 'node:test' +import assert from 'node:assert/strict' +import { readSource } from './helpers.ts' +import { parseMenuTree } from '../src/api/session-model.ts' + +test('test_task_039_backend_tree_compat_normal_primary_path', () => { + // 正常主路径:data.items 信封。 + const tree = parseMenuTree({ success: true, data: { items: [{ key: 'a', name: 'A', route: '/a' }] } }) + assert.equal(tree[0].route, '/a') +}) + +test('test_task_039_backend_tree_compat_normal_variant_input', () => { + // 正常变体:data:{items}/无 data 的 {items}/裸数组三种信封均可解。 + assert.equal(parseMenuTree({ data: { items: [{ key: 'x', name: 'X' }] } }).length, 1) + assert.equal(parseMenuTree({ success: true, items: [{ key: 'y', name: 'Y', route: '/y' }] }).length, 1) + assert.equal(parseMenuTree([{ key: 'z', name: 'Z' }]).length, 1) +}) + +test('test_task_039_backend_tree_compat_normal_repeated_operation_is_idempotent', () => { + // 正常重复:同一负载解析结果稳定且不改输入。 + const payload = { data: { items: [{ key: 'a', name: 'A', children: [{ key: 'b', name: 'B', route: '/b' }] }] } } + assert.deepEqual(parseMenuTree(payload), parseMenuTree(payload)) +}) + +test('test_task_039_backend_tree_compat_boundary_empty_input', () => { + // 边界空值:空 items/空 data/空数组/非对象均按空树处理(区别于接口失败)。 + assert.deepEqual(parseMenuTree({ data: { items: [] } }), []) + assert.deepEqual(parseMenuTree({}), []) + assert.deepEqual(parseMenuTree(null as unknown as { items?: [] }), []) + assert.deepEqual(parseMenuTree(undefined as unknown as { items?: [] }), []) +}) + +test('test_task_039_backend_tree_compat_boundary_single_item', () => { + // 边界单元素:单分组/单页面两种最小树均可解析。 + assert.equal(parseMenuTree({ data: { items: [{ key: 'g', name: '组' }] } }).length, 1) + assert.equal(parseMenuTree({ items: [{ key: 'p', name: '页', route: '/p' }] }).length, 1) +}) + +test('test_task_039_backend_tree_compat_boundary_limit_or_missing_field', () => { + // 边界上限/缺字段:附加未知字段与缺省字段都不丢失/不崩溃。 + const tree = parseMenuTree({ items: [{ key: 'p', name: '页', route: '/p', sort: 3, icon: 'x', extra: { keep: true } }] }) + assert.equal((tree[0] as unknown as { extra: { keep: boolean } }).extra.keep, true) +}) + +test('test_task_039_backend_tree_compat_invalid_input_rejected', () => { + // 异常输入:success=false 视为接口失败抛错(区别于“权限为空”)。 + assert.throws(() => parseMenuTree({ success: false, message: '会话失效', code: 401 }), /会话失效/) +}) + +test('test_task_039_backend_tree_compat_dependency_failure_returns_actionable_message', () => { + // 依赖失败:会话适配 fetchAdminMenuTree 复用同一解析器兜住各信封边界。 + const session = readSource('src/api/session.ts') + assert.match(session, /parseMenuTree/) + const model = readSource('src/api/session-model.ts') + assert.match(model, /export function parseMenuTree/) + assert.match(model, /Array\.isArray/) +})