Files
huangzd1997 50a6cf12e7 task-57(账号/权限页面): 实现菜单删除前置校验
menu-manage-model.ts 增 menuDeleteReason 镜像后端仅删叶子约束(有子先删);menu-manage-api.ts
增 deleteMenu DELETE /api/admin/permission-menus/{id};MenusPage 行删除二次确认、
带子节点禁用/拦截并刷新。8 用例全过,419 单测 + build 绿。
2026-09-05 15:20:39 +08:00

88 lines
3.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import test from 'node:test'
import assert from 'node:assert/strict'
import { readSource } from './helpers.ts'
import {
buildMenuManageTree,
menuDeleteReason,
parseMenuManageList,
} from '../src/pages/account/menu-manage-model.ts'
test('test_task_057_menu_delete_guard_normal_primary_path', () => {
// 正常主路径:叶子菜单可删除(无原因)。
const items = parseMenuManageList([{ id: 9, name: '叶子', column_key: 'leaf', parent_id: null }])
assert.equal(menuDeleteReason(items[0]), undefined)
})
test('test_task_057_menu_delete_guard_normal_variant_input', () => {
// 正常变体:空 children(未挂子树)也可删;有子树不可删。
const items = parseMenuManageList([{ id: 1, name: '组', column_key: 'g', parent_id: null }])
assert.equal(menuDeleteReason(items[0]), undefined)
const tree = buildMenuManageTree(
parseMenuManageList([
{ id: 1, name: '组', column_key: 'g', parent_id: null },
{ id: 2, name: '子', column_key: 'c', parent_id: 1 },
]),
)
assert.match(menuDeleteReason(tree[0]) || '', /子菜单/)
})
test('test_task_057_menu_delete_guard_normal_repeated_operation_is_idempotent', () => {
// 正常重复:守卫纯函数不改输入、结果稳定。
const tree = buildMenuManageTree(
parseMenuManageList([
{ id: 1, name: '根', column_key: 'r', parent_id: null },
{ id: 2, name: '子', column_key: 'c', parent_id: 1 },
]),
)
assert.equal(menuDeleteReason(tree[0]), menuDeleteReason(tree[0]))
assert.equal(tree[0].children?.length, 1)
})
test('test_task_057_menu_delete_guard_boundary_empty_input', () => {
// 边界空值:空树可删;undefined 行视为无子树可删。
assert.equal(menuDeleteReason(undefined as never), undefined)
})
test('test_task_057_menu_delete_guard_boundary_single_item', () => {
// 边界单元素:单叶子可删。
const items = parseMenuManageList([{ id: 5, name: 'only', column_key: 'only' }])
assert.equal(menuDeleteReason(items[0]), undefined)
})
test('test_task_057_menu_delete_guard_boundary_limit_or_missing_field', () => {
// 边界上限:多层子树同样不可删(按是否有 children 判定)。
const tree = buildMenuManageTree(
parseMenuManageList([
{ id: 1, name: '根', column_key: 'r', parent_id: null },
{ id: 2, name: '子', column_key: 'c', parent_id: 1 },
{ id: 3, name: '孙', column_key: 'l', parent_id: 2 },
]),
)
assert.ok(menuDeleteReason(tree[0]))
const sub = tree[0].children?.[0]!
assert.ok(menuDeleteReason(sub))
})
test('test_task_057_menu_delete_guard_invalid_input_rejected', () => {
// 异常输入:父级带子给出与后端一致的可操作文案。
const tree = buildMenuManageTree(
parseMenuManageList([
{ id: 1, name: 'A', column_key: 'a', parent_id: null },
{ id: 2, name: 'B', column_key: 'b', parent_id: 1 },
]),
)
assert.match(menuDeleteReason(tree[0]) || '', /请先删除该菜单下的子菜单/)
})
test('test_task_057_menu_delete_guard_dependency_failure_returns_actionable_message', () => {
// 依赖失败/删除走 adapterDELETE permission-menus/{id},页面二次确认后调用并刷新。
const api = readSource('src/pages/account/menu-manage-api.ts')
assert.match(api, /deleteMenu/)
assert.match(api, /http\.delete/)
assert.match(api, /permission-menus/)
const page = readSource('src/pages/account/MenusPage.vue')
assert.match(page, /deleteMenu/)
assert.match(page, /menuDeleteReason|ElMessageBox/)
assert.equal(/http\.delete|unwrap\(/.test(page), false, '页面不内联删除请求')
})