This commit is contained in:
oneao committed 2026-10-15 17:31:35 +08:00
1 parent b4498e5350
commit bf9dca19de
47 files changed
+8592 -313

No files matched your search

@@ -0,0 +1,119 @@
/**
* MenuTreePanel:行尾启用勾选。
*
* 与模块树面板同构(勾选框不走 G3Tree 内置的 checkable,而是画在 #title 插槽行尾),
* 因此同样要锁住三件事:
* 1. 勾选上报 toggleEnabled,由父级落库;
* 2. 点击不冒泡(行上挂了 click 选中 / mousedown 武装拖拽);
* 3. 未保存草稿不可勾(库里没有这行),且面板必须开 block-node 才能贴到行尾。
*/
import { describe, expect, it } from 'vitest'
import { mount } from '@vue/test-utils'
import type { VueWrapper } from '@vue/test-utils'
import { G3Checkbox, G3Tree } from '@g3soft/ui'
import MenuTreePanel from '@/views/module/menu-management/MenuTreePanel.vue'
import type { MenuNode } from '@/views/module/menu-management/utils'
const TREE = [
{ b_id: 'group_base', b_name: '基础资料', b_menu_type: 'directory', b_canuse: 1 },
{ b_id: 'base_contact', b_name: '联系人', b_menu_type: 'page', b_canuse: 0 },
{ b_id: '-1', b_name: '未保存草稿', b_menu_type: 'page', b_canuse: 1 },
] as unknown as MenuNode[]
function mountPanel(unsavedIds = new Set<string>()) {
return mount(MenuTreePanel, {
props: { treeData: TREE, unsavedIds },
})
}
const rowOf = (wrapper: VueWrapper, label: string) =>
wrapper.findAll('[role="treeitem"]').find((row) => row.text().includes(label))
const checkboxOf = (wrapper: VueWrapper, label: string) =>
rowOf(wrapper, label)?.findComponent(G3Checkbox)
describe('MenuTreePanel 行尾启用勾选', () => {
it('每个节点行都带勾选框,勾选态反映 b_canuse', () => {
const wrapper = mountPanel()
expect(checkboxOf(wrapper, '基础资料')?.props('modelValue')).toBe(true)
expect(checkboxOf(wrapper, '联系人')?.props('modelValue')).toBe(false)
})
it('勾选上报 toggleEnabled(id + 目标启用态)', async () => {
const wrapper = mountPanel()
checkboxOf(wrapper, '联系人')?.vm.$emit('update:modelValue', true)
await wrapper.vm.$nextTick()
expect(wrapper.emitted('toggleEnabled')?.[0]?.[0]).toEqual({
id: 'base_contact',
enabled: true,
})
})
it('取消勾选同样上报(enabled: false)', async () => {
const wrapper = mountPanel()
checkboxOf(wrapper, '基础资料')?.vm.$emit('update:modelValue', false)
await wrapper.vm.$nextTick()
expect(wrapper.emitted('toggleEnabled')?.[0]?.[0]).toEqual({
id: 'group_base',
enabled: false,
})
})
it('点击勾选框不触发行的选中(事件不冒泡)', async () => {
const wrapper = mountPanel()
const row = rowOf(wrapper, '基础资料')!
const box = checkboxOf(wrapper, '基础资料')!.find('input')
await box.trigger('click')
expect(wrapper.emitted('select')).toBeUndefined()
// 行自身仍可正常选中,说明拦的是勾选框那一下、不是把整行点击弄坏了
await row.trigger('click')
expect(wrapper.emitted('select')?.[0]?.[0]).toBe('group_base')
})
it('未保存草稿的勾选框禁用且不上报', async () => {
const wrapper = mountPanel(new Set(['-1']))
const box = checkboxOf(wrapper, '未保存草稿')!
expect(box.props('disabled')).toBe(true)
box.vm.$emit('update:modelValue', false)
await wrapper.vm.$nextTick()
expect(wrapper.emitted('toggleEnabled')).toBeUndefined()
})
it('勾选框渲染在名称之后的行尾', () => {
const wrapper = mountPanel()
const row = rowOf(wrapper, '基础资料')!
const nameEl = row.find('.mm-tree-node__name')
const enableEl = row.find('.mm-tree-node__enable')
expect(nameEl.exists()).toBe(true)
expect(enableEl.exists()).toBe(true)
const relation = nameEl.element.compareDocumentPosition(enableEl.element)
expect(relation & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy()
})
it('面板必须开 block-node:否则内容层不撑满,勾选框贴不到行尾', () => {
const wrapper = mountPanel()
// 断言落在 G3Tree 上:BizTreePanel / BizTree 是 inheritAttrs:false,
// kebab 的 'block-node' 会留在中间层的 $attrs 里(那些层取不到),
// 只有到 G3Tree 才被归一成 blockNode prop。
expect(wrapper.findComponent(G3Tree).props('blockNode')).toBe(true)
})
it('面板不启用 G3Tree 内置 checkable(避免行首出现多选勾选框)', () => {
const wrapper = mountPanel()
expect(wrapper.find('.g3-tree-node__checkbox').exists()).toBe(false)
})
})