Files
workspace/code/g3soft-erp/web/tests/views/module/menu-management/MenuTreePanel.spec.ts
T
2026-10-15 17:31:35 +08:00

120 lines
4.4 KiB
TypeScript
Raw 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.
/**
* 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)
})
})