feat(files): 文件管理四项——侧栏拖拽移动、草稿跨窗口认领、未命名默认存根目录、打开所在位置(docs/25)

This commit is contained in:
Muse
2026-11-14 16:36:36 +08:00
parent 71825201a2
commit c2f69f9303
12 changed files with 513 additions and 19 deletions

View File

@@ -99,3 +99,95 @@ describe('文件树', () => {
container.remove()
})
})
describe('文件树拖拽移动', () => {
const fireDrag = async (el: Element | undefined | null, type: string) => {
if (!el) throw new Error(`元素不存在,无法派发 ${type}`)
const e = new Event(type, { bubbles: true, cancelable: true }) as Event & { dataTransfer: Record<string, unknown> }
e.dataTransfer = { effectAllowed: '', dropEffect: '', setData: () => undefined, getData: () => '' }
await act(async () => { el.dispatchEvent(e) })
}
it('把文件拖到文件夹上触发移动回调', async () => {
const moves: { path: string; dest: string }[] = []
const { container, root } = await renderSidebar({
onMoveEntry: (entry: { path: string }, dest: string) => moves.push({ path: entry.path, dest }),
})
const file = findButton(container, 'a.md')
const folder = findButton(container, 'sub')
await fireDrag(file, 'dragstart')
await fireDrag(folder, 'dragover')
expect(folder?.className).toContain('drop-target')
await fireDrag(folder, 'drop')
expect(moves).toEqual([{ path: 'C:/ws/a.md', dest: 'C:/ws/sub' }])
await act(async () => { root.unmount() })
container.remove()
})
it('拖回原文件夹(根目录)不触发移动', async () => {
const moves: unknown[] = []
const { container, root } = await renderSidebar({
onMoveEntry: (...args: unknown[]) => moves.push(args),
})
const file = findButton(container, 'a.md')
const head = container.querySelector('.filetree-head')
await fireDrag(file, 'dragstart')
await fireDrag(head, 'dragover')
await fireDrag(head, 'drop')
expect(moves).toEqual([])
await act(async () => { root.unmount() })
container.remove()
})
it('子文件夹里的文件可以拖回根目录', async () => {
const moves: { path: string; dest: string }[] = []
const { container, root } = await renderSidebar({
onMoveEntry: (entry: { path: string }, dest: string) => moves.push({ path: entry.path, dest }),
})
await act(async () => {
findButton(container, 'sub')?.dispatchEvent(new MouseEvent('click', { bubbles: true }))
})
await act(async () => { await sleep(30) })
const inner = findButton(container, 'b.md')
const head = container.querySelector('.filetree-head')
await fireDrag(inner, 'dragstart')
await fireDrag(head, 'dragover')
await fireDrag(head, 'drop')
expect(moves).toEqual([{ path: 'C:/ws/sub/b.md', dest: 'C:/ws' }])
await act(async () => { root.unmount() })
container.remove()
})
it('文件夹拖到自己身上不触发移动', async () => {
const moves: unknown[] = []
const { container, root } = await renderSidebar({
onMoveEntry: (...args: unknown[]) => moves.push(args),
})
const folder = findButton(container, 'sub')
await fireDrag(folder, 'dragstart')
await fireDrag(folder, 'dragover')
await fireDrag(folder, 'drop')
expect(moves).toEqual([])
await act(async () => { root.unmount() })
container.remove()
})
it('右键菜单含「打开所在位置」并回传条目', async () => {
const revealed: string[] = []
const { container, root } = await renderSidebar({
onRevealEntry: (entry: { path: string }) => revealed.push(entry.path),
})
await act(async () => {
findButton(container, 'a.md')?.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true }))
})
await act(async () => { await sleep(10) })
const item = findButton(container, '打开所在位置')
expect(item).toBeTruthy()
await act(async () => {
item?.dispatchEvent(new MouseEvent('click', { bubbles: true }))
})
expect(revealed).toEqual(['C:/ws/a.md'])
await act(async () => { root.unmount() })
container.remove()
})
})