Files
workspace/code/fms/fms-vue/tests/unit/tree-external-drag.spec.js
2026-08-27 23:06:36 +08:00

98 lines
4.0 KiB
JavaScript
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 { mount } from '@vue/test-utils'
import { describe, expect, it, vi, beforeEach } from 'vitest'
import Tree from '@/components/ui/tree/tree.vue'
/**
* 模拟 Chrome 的 DataTransfer 行为:
* - dragover / dragenter 阶段:getData() 对所有类型返回空字符串(隐私保护),但 types / effectAllowed 可用
* - drop 阶段:getData() 正常返回 dragstart 中写入的数据
*/
function makeDataTransfer({ types = [], get = () => '' } = {}) {
return {
effectAllowed: 'copy',
dropEffect: 'none',
types,
getData: vi.fn((t) => get(t)),
setData: vi.fn(),
}
}
const treeData = [
{
key: 'g:1',
title: '分组1',
isLeaf: false,
children: [{ key: 'c:1', title: '列1', isLeaf: true }],
},
]
describe('Tree 外部拖拽(字段库 → 分组)', () => {
beforeEach(() => {
// 让 calcDropPosition 能算出 'inside'(行高 40,鼠标落在中点)
Element.prototype.getBoundingClientRect = () => ({
top: 0,
bottom: 40,
left: 0,
right: 200,
width: 200,
height: 40,
x: 0,
y: 0,
toJSON: () => ({}),
})
})
it('dragover 阶段 getData 为空(Chrome 限制)时,基于 types 识别外部源并设置拖放指示', async () => {
const externalDragKey = vi.fn((dt) => {
const types = Array.from(dt?.types || [])
if (!types.includes('application/fms-field')) return null
const fid = dt?.getData?.('application/fms-field')
return fid ? `external-field:${fid}` : `external-field:__pending__`
})
const wrapper = mount(Tree, { props: { treeData, draggable: true, externalDragKey } })
const nodeRow = wrapper.find('.tree-node')
// dragover:getData 读不到值(模拟 Chrome),仅 types 可用
const dt = makeDataTransfer({ types: ['application/fms-field'], get: () => '' })
await nodeRow.trigger('dragover', { dataTransfer: dt, clientY: 20 })
expect(externalDragKey).toHaveBeenCalled()
// dragKey 已被解析 → 节点行出现放置指示(说明拖拽已被识别,可正常落放)
expect(nodeRow.classes()).toContain('drop-inside')
})
it('dragover 阶段仅用 getData 判断时(修复前实现),拖放指示不出现', async () => {
// 旧实现:只靠 getData 判断拖拽源 → Chrome 下 dragover 读不到 → dragKey 不设置
const externalDragKey = vi.fn((dt) => {
const fid = dt?.getData?.('application/fms-field')
return fid ? `external-field:${String(fid)}` : null
})
const wrapper = mount(Tree, { props: { treeData, draggable: true, externalDragKey } })
const nodeRow = wrapper.find('.tree-node')
const dt = makeDataTransfer({ types: ['application/fms-field'], get: () => '' })
await nodeRow.trigger('dragover', { dataTransfer: dt, clientY: 20 })
// 没有任何 drop-* 指示类
expect(nodeRow.classes().some((c) => c.startsWith('drop-'))).toBe(false)
})
it('drop 阶段 getData 可用时,发出正确的 external-field 拖拽键', async () => {
const externalDragKey = (dt) => {
const types = Array.from(dt?.types || [])
if (!types.includes('application/fms-field')) return null
const fid = dt?.getData?.('application/fms-field')
return fid ? `external-field:${fid}` : `external-field:__pending__`
}
const wrapper = mount(Tree, { props: { treeData, draggable: true, externalDragKey } })
const nodeRow = wrapper.find('.tree-node')
// dragover(读不到)→ drop(能读到 '42')
const overDT = makeDataTransfer({ types: ['application/fms-field'], get: () => '' })
await nodeRow.trigger('dragover', { dataTransfer: overDT, clientY: 20 })
const dropDT = makeDataTransfer({
types: ['application/fms-field'],
get: (t) => (t === 'application/fms-field' ? '42' : ''),
})
await nodeRow.trigger('drop', { dataTransfer: dropDT })
const drops = wrapper.emitted('drop')
expect(drops).toBeTruthy()
expect(drops[0][0]).toMatchObject({ dragKey: 'external-field:42', dropKey: 'g:1' })
})
})