579 lines
22 KiB
TypeScript
579 lines
22 KiB
TypeScript
/**
|
||
* 17-finder-vue: Finder Vue 组件化全覆盖测试
|
||
*
|
||
* 覆盖功能点:
|
||
* 导航 — 侧边栏点击、面包屑、前进/后退、参数路径
|
||
* 视图 — 图标/列表切换、排序
|
||
* 选择 — 单击、Ctrl+单击、Shift+范围、Cmd+A、空白区取消
|
||
* 文件操作 — 新建文件夹、重命名、移到废纸篓
|
||
* 剪贴板 — 拷贝/粘贴
|
||
* 搜索 — 过滤文件列表
|
||
* 键盘 — Enter 重命名、Cmd+C/V/A、Delete 删除
|
||
* 拖放 — dragstart/drop
|
||
* 右键菜单 — 空白区菜单、文件菜单
|
||
* FS 变化 — fs:changed 自动刷新
|
||
*/
|
||
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
||
import { h, render, nextTick } from 'vue'
|
||
import FinderComponent from '../../src/apps/finder/Finder.vue'
|
||
import { fs } from '../../src/composables/useFS'
|
||
import { wm } from '../../src/composables/useWM'
|
||
import { setupDOM } from '../helpers'
|
||
|
||
// 模拟 win 对象
|
||
function makeMockWin() {
|
||
const el = document.createElement('div')
|
||
el.className = 'window'
|
||
document.getElementById('window-layer')?.appendChild(el)
|
||
const body = document.createElement('div')
|
||
body.className = 'win-body'
|
||
el.appendChild(body)
|
||
return {
|
||
id: 'test-win',
|
||
appId: 'finder',
|
||
el,
|
||
body,
|
||
timers: [] as any[],
|
||
data: {},
|
||
}
|
||
}
|
||
|
||
describe('17-finder-vue — Finder Vue 组件化', () => {
|
||
let win: any
|
||
|
||
beforeEach(() => {
|
||
localStorage.clear();
|
||
(fs as any).root = null
|
||
fs.init()
|
||
setupDOM()
|
||
win = makeMockWin()
|
||
})
|
||
|
||
afterEach(() => {
|
||
render(null, win.body)
|
||
win.el.remove()
|
||
})
|
||
|
||
function mount() {
|
||
const vnode = h(FinderComponent, { win })
|
||
render(vnode, win.body)
|
||
}
|
||
|
||
// ==================== 初始化 ====================
|
||
describe('初始化', () => {
|
||
it('挂载后在 body 中渲染 .finder 容器', () => {
|
||
mount()
|
||
expect(win.body.querySelector('.finder')).toBeTruthy()
|
||
})
|
||
|
||
it('默认路径为 Desktop', () => {
|
||
mount()
|
||
const cur = win.body.querySelector('.fb-crumb-item.cur')
|
||
expect(cur?.textContent).toBe('Desktop')
|
||
})
|
||
|
||
it('侧边栏包含个人收藏和位置', () => {
|
||
mount()
|
||
const titles = win.body.querySelectorAll('.fb-side-title')
|
||
expect(titles.length).toBeGreaterThanOrEqual(2)
|
||
expect(titles[0].textContent).toBe('个人收藏')
|
||
})
|
||
})
|
||
|
||
// ==================== 导航 ====================
|
||
describe('导航', () => {
|
||
it('点击侧边栏收藏项导航到对应目录', async () => {
|
||
mount()
|
||
const docItem = [...win.body.querySelectorAll('.fb-side-item')]
|
||
.find(el => el.textContent?.includes('文稿')) as HTMLElement
|
||
expect(docItem).toBeTruthy()
|
||
docItem.click()
|
||
await nextTick()
|
||
const cur = win.body.querySelector('.fb-crumb-item.cur')
|
||
expect(cur?.textContent).toBe('Documents')
|
||
})
|
||
|
||
it('点击面包屑导航到上级目录', async () => {
|
||
mount()
|
||
// 先导航到 Desktop/Sample Folder
|
||
const folderEl = [...win.body.querySelectorAll('.fb-item')]
|
||
.find(el => el.querySelector('.fi-name')?.textContent === 'Sample Folder') as HTMLElement
|
||
if (folderEl) {
|
||
folderEl.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }))
|
||
await nextTick()
|
||
// 点击面包屑回到 Desktop
|
||
const crumbs = win.body.querySelectorAll('.fb-crumb-item')
|
||
const desktopCrumb = [...crumbs].find(c => c.textContent?.includes('Desktop')) as HTMLElement
|
||
if (desktopCrumb) {
|
||
desktopCrumb.click()
|
||
await nextTick()
|
||
const cur = win.body.querySelector('.fb-crumb-item.cur')
|
||
expect(cur?.textContent).toBe('Desktop')
|
||
}
|
||
}
|
||
})
|
||
|
||
it('后退按钮初始禁用', () => {
|
||
mount()
|
||
const backBtn = win.body.querySelector('.fb-toolbar .fb-btn[title="后退"]') as HTMLButtonElement
|
||
expect(backBtn.disabled).toBe(true)
|
||
})
|
||
|
||
it('通过 win.data.path 参数指定初始路径', () => {
|
||
win.data = { path: fs.HOME + '/Documents' }
|
||
mount()
|
||
const cur = win.body.querySelector('.fb-crumb-item.cur')
|
||
expect(cur?.textContent).toBe('Documents')
|
||
})
|
||
|
||
it('前进/后退完整循环', async () => {
|
||
mount()
|
||
// 双击进入 Sample Folder
|
||
const folderEl = [...win.body.querySelectorAll('.fb-item')]
|
||
.find(el => el.querySelector('.fi-name')?.textContent === 'Sample Folder') as HTMLElement
|
||
if (!folderEl) return
|
||
folderEl.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }))
|
||
await nextTick()
|
||
expect(win.body.querySelector('.fb-crumb-item.cur')?.textContent).toBe('Sample Folder')
|
||
// 后退
|
||
const backBtn = win.body.querySelector('.fb-toolbar .fb-btn[title="后退"]') as HTMLButtonElement
|
||
backBtn.click()
|
||
await nextTick()
|
||
expect(win.body.querySelector('.fb-crumb-item.cur')?.textContent).toBe('Desktop')
|
||
// 前进
|
||
const fwdBtn = win.body.querySelector('.fb-toolbar .fb-btn[title="前进"]') as HTMLButtonElement
|
||
fwdBtn.click()
|
||
await nextTick()
|
||
expect(win.body.querySelector('.fb-crumb-item.cur')?.textContent).toBe('Sample Folder')
|
||
})
|
||
|
||
it('前进按钮在最新位置禁用', () => {
|
||
mount()
|
||
const fwdBtn = win.body.querySelector('.fb-toolbar .fb-btn[title="前进"]') as HTMLButtonElement
|
||
expect(fwdBtn.disabled).toBe(true)
|
||
})
|
||
|
||
it('iCloud 侧边栏占位点击', () => {
|
||
mount()
|
||
const icloudItem = [...win.body.querySelectorAll('.fb-side-item')]
|
||
.find(el => el.textContent?.includes('iCloud')) as HTMLElement
|
||
// 不导航,仅验证不抛错
|
||
expect(() => icloudItem.click()).not.toThrow()
|
||
// 路径应保持 Desktop(不导航到 iCloud)
|
||
expect(win.body.querySelector('.fb-crumb-item.cur')?.textContent).toBe('Desktop')
|
||
})
|
||
|
||
it('废纸篓侧边栏导航', async () => {
|
||
mount()
|
||
const trashItems = [...win.body.querySelectorAll('.fb-side-item')]
|
||
const trashItem = trashItems.find(el => {
|
||
const text = el.textContent || ''
|
||
return text.includes('Trash') || text.includes('废纸篓')
|
||
}) as HTMLElement
|
||
if (!trashItem) return
|
||
trashItem.click()
|
||
await nextTick()
|
||
const cur = win.body.querySelector('.fb-crumb-item.cur')
|
||
expect(cur).toBeTruthy()
|
||
})
|
||
})
|
||
|
||
// ==================== 视图切换 ====================
|
||
describe('视图切换', () => {
|
||
it('默认图标视图时 .fb-content 有 icon-view 类', () => {
|
||
mount()
|
||
expect(win.body.querySelector('.fb-content')?.classList.contains('icon-view')).toBe(true)
|
||
})
|
||
|
||
it('切换到列表视图后 .fb-content 有 list-view 类', async () => {
|
||
mount()
|
||
const listBtn = win.body.querySelector('.segmented button:last-child') as HTMLElement
|
||
listBtn.click()
|
||
await nextTick()
|
||
expect(win.body.querySelector('.fb-content')?.classList.contains('list-view')).toBe(true)
|
||
// 列表视图应显示额外列
|
||
const cols = win.body.querySelectorAll('.fi-col')
|
||
expect(cols.length).toBeGreaterThan(0)
|
||
})
|
||
|
||
it('视图切换按钮有 on 类', async () => {
|
||
mount()
|
||
const btns = win.body.querySelectorAll('.segmented button')
|
||
const iconBtn = btns[0] as HTMLElement
|
||
const listBtn = btns[1] as HTMLElement
|
||
expect(iconBtn.classList.contains('on')).toBe(true)
|
||
listBtn.click()
|
||
await nextTick()
|
||
expect(listBtn.classList.contains('on')).toBe(true)
|
||
expect(iconBtn.classList.contains('on')).toBe(false)
|
||
})
|
||
})
|
||
|
||
// ==================== 排序 ====================
|
||
describe('排序', () => {
|
||
it('排序下拉存在三个选项', () => {
|
||
mount()
|
||
const sel = win.body.querySelector('.fb-sort') as HTMLSelectElement
|
||
expect(sel.options.length).toBe(3)
|
||
expect(sel.options[0].value).toBe('name')
|
||
expect(sel.options[1].value).toBe('kind')
|
||
expect(sel.options[2].value).toBe('date')
|
||
})
|
||
|
||
it('文件夹排在文件前面', () => {
|
||
mount()
|
||
const names = [...win.body.querySelectorAll('.fi-name')].map(e => e.textContent)
|
||
const firstFolderIdx = names.findIndex(n => n === 'Sample Folder')
|
||
const firstFileIdx = names.findIndex(n => n === 'welcome.txt')
|
||
expect(firstFolderIdx).toBeLessThan(firstFileIdx)
|
||
})
|
||
})
|
||
|
||
// ==================== 文件选择 ====================
|
||
describe('文件选择', () => {
|
||
it('单击选中单个文件', async () => {
|
||
mount()
|
||
const item = win.body.querySelector('.fb-item') as HTMLElement
|
||
item.click()
|
||
await nextTick()
|
||
expect(item.classList.contains('sel')).toBe(true)
|
||
})
|
||
|
||
it('单击另一个文件取消前一个选择', async () => {
|
||
mount()
|
||
const items = win.body.querySelectorAll('.fb-item')
|
||
if (items.length < 2) return
|
||
;(items[0] as HTMLElement).click()
|
||
await nextTick()
|
||
;(items[1] as HTMLElement).click()
|
||
await nextTick()
|
||
expect((items[0] as HTMLElement).classList.contains('sel')).toBe(false)
|
||
expect((items[1] as HTMLElement).classList.contains('sel')).toBe(true)
|
||
})
|
||
|
||
it('Ctrl+单击多选', async () => {
|
||
mount()
|
||
const items = win.body.querySelectorAll('.fb-item')
|
||
if (items.length < 2) return
|
||
;(items[0] as HTMLElement).dispatchEvent(new MouseEvent('click', { ctrlKey: true, bubbles: true }))
|
||
await nextTick()
|
||
;(items[1] as HTMLElement).dispatchEvent(new MouseEvent('click', { ctrlKey: true, bubbles: true }))
|
||
await nextTick()
|
||
expect((items[0] as HTMLElement).classList.contains('sel')).toBe(true)
|
||
expect((items[1] as HTMLElement).classList.contains('sel')).toBe(true)
|
||
})
|
||
|
||
it('Shift+单击范围选择', async () => {
|
||
mount()
|
||
const items = win.body.querySelectorAll('.fb-item')
|
||
if (items.length < 3) return
|
||
// 先单击选中第一个
|
||
const first = items[0] as HTMLElement
|
||
first.click()
|
||
await nextTick()
|
||
// Shift+单击第三个:需要直接在 .fb-item 上触发
|
||
const third = items[2] as HTMLElement
|
||
third.dispatchEvent(new MouseEvent('click', { shiftKey: true, bubbles: true, cancelable: true }))
|
||
await nextTick()
|
||
// 0, 1, 2 都应该被选中
|
||
expect(first.classList.contains('sel')).toBe(true)
|
||
expect((items[1] as HTMLElement).classList.contains('sel')).toBe(true)
|
||
expect(third.classList.contains('sel')).toBe(true)
|
||
})
|
||
})
|
||
|
||
// ==================== 双击打开 ====================
|
||
describe('双击打开', () => {
|
||
it('双击文件夹导航进入', async () => {
|
||
mount()
|
||
// Find a folder item and dblclick
|
||
const folderEl = [...win.body.querySelectorAll('.fb-item')]
|
||
.find(el => el.querySelector('.fi-name')?.textContent === 'Sample Folder') as HTMLElement
|
||
if (!folderEl) return
|
||
folderEl.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }))
|
||
await nextTick()
|
||
const cur = win.body.querySelector('.fb-crumb-item.cur')
|
||
expect(cur?.textContent).toBe('Sample Folder')
|
||
})
|
||
|
||
it('双击文件触发 openPath', async () => {
|
||
mount()
|
||
const fileEl = [...win.body.querySelectorAll('.fb-item')]
|
||
.find(el => el.querySelector('.fi-name')?.textContent === 'welcome.txt') as HTMLElement
|
||
expect(fileEl).toBeTruthy()
|
||
// 双击文件不应该崩溃
|
||
expect(() => {
|
||
fileEl?.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }))
|
||
}).not.toThrow()
|
||
})
|
||
})
|
||
|
||
// ==================== 搜索 ====================
|
||
describe('搜索', () => {
|
||
it('搜索过滤文件列表', async () => {
|
||
mount()
|
||
const searchInput = win.body.querySelector('.fb-search') as HTMLInputElement
|
||
searchInput.value = 'welcome'
|
||
searchInput.dispatchEvent(new Event('input', { bubbles: true }))
|
||
await nextTick()
|
||
const names = [...win.body.querySelectorAll('.fi-name')].map(e => e.textContent)
|
||
expect(names.every(n => n?.toLowerCase().includes('welcome'))).toBe(true)
|
||
})
|
||
|
||
it('无匹配时显示空状态', async () => {
|
||
mount()
|
||
const searchInput = win.body.querySelector('.fb-search') as HTMLInputElement
|
||
searchInput.value = 'zzzz_not_exist'
|
||
searchInput.dispatchEvent(new Event('input', { bubbles: true }))
|
||
await nextTick()
|
||
expect(win.body.querySelector('.empty-state')?.textContent).toContain('没有匹配的结果')
|
||
})
|
||
})
|
||
|
||
// ==================== 键盘操作 ====================
|
||
describe('键盘操作', () => {
|
||
it('Cmd+A 全选所有文件', async () => {
|
||
mount()
|
||
const content = win.body.querySelector('.fb-content') as HTMLElement
|
||
content.dispatchEvent(new KeyboardEvent('keydown', { key: 'a', metaKey: true, bubbles: true, cancelable: true }))
|
||
await nextTick()
|
||
const selCount = win.body.querySelectorAll('.fb-item.sel').length
|
||
const totalCount = win.body.querySelectorAll('.fb-item').length
|
||
expect(selCount).toBe(totalCount)
|
||
})
|
||
|
||
it('Cmd+C 拷贝选中文件', async () => {
|
||
mount()
|
||
const item = win.body.querySelector('.fb-item') as HTMLElement
|
||
item.click()
|
||
await nextTick()
|
||
const content = win.body.querySelector('.fb-content') as HTMLElement
|
||
content.dispatchEvent(new KeyboardEvent('keydown', { key: 'c', metaKey: true, bubbles: true }))
|
||
expect((window as any).__finderClipboard).toBeTruthy()
|
||
expect((window as any).__finderClipboard.op).toBe('copy')
|
||
})
|
||
|
||
it('Cmd+V 粘贴', async () => {
|
||
// 先设置 clipboard
|
||
;(window as any).__finderClipboard = {
|
||
op: 'copy', paths: [fs.HOME + '/Desktop/welcome.txt'], from: fs.HOME + '/Desktop'
|
||
}
|
||
mount()
|
||
const content = win.body.querySelector('.fb-content') as HTMLElement
|
||
content.dispatchEvent(new KeyboardEvent('keydown', { key: 'v', metaKey: true, bubbles: true }))
|
||
// 粘贴后文件出现在桌面
|
||
await nextTick()
|
||
const names = [...win.body.querySelectorAll('.fi-name')].map(e => e.textContent)
|
||
const copies = names.filter(n => n?.includes('welcome'))
|
||
expect(copies.length).toBeGreaterThanOrEqual(1)
|
||
})
|
||
|
||
it('Delete 键移到废纸篓', async () => {
|
||
mount()
|
||
const item = win.body.querySelector('.fb-item') as HTMLElement
|
||
item.click()
|
||
await nextTick()
|
||
const content = win.body.querySelector('.fb-content') as HTMLElement
|
||
content.dispatchEvent(new KeyboardEvent('keydown', { key: 'Delete', bubbles: true }))
|
||
await nextTick()
|
||
// 选中被清除
|
||
expect(win.body.querySelectorAll('.fb-item.sel').length).toBe(0)
|
||
// 文件已移走(选择集被清空,fs trash 已调用)
|
||
})
|
||
})
|
||
|
||
// ==================== 文件操作 ====================
|
||
describe('文件操作', () => {
|
||
it('新建文件夹按钮存在', () => {
|
||
mount()
|
||
const newBtn = win.body.querySelector('.fb-toolbar .fb-btn[title="新建文件夹"]')
|
||
expect(newBtn).toBeTruthy()
|
||
})
|
||
|
||
it('重命名:Enter 键盘触发表单出现', async () => {
|
||
mount()
|
||
const item = win.body.querySelector('.fb-item') as HTMLElement
|
||
item.click()
|
||
await nextTick()
|
||
const content = win.body.querySelector('.fb-content') as HTMLElement
|
||
content.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }))
|
||
await nextTick()
|
||
const renameInput = win.body.querySelector('.fi-rename')
|
||
expect(renameInput).toBeTruthy()
|
||
})
|
||
|
||
it('重命名:Escape 取消重命名', async () => {
|
||
mount()
|
||
const item = win.body.querySelector('.fb-item') as HTMLElement
|
||
item.click()
|
||
await nextTick()
|
||
const content = win.body.querySelector('.fb-content') as HTMLElement
|
||
content.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
|
||
await nextTick()
|
||
const input = win.body.querySelector('.fi-rename') as HTMLInputElement
|
||
expect(input).toBeTruthy()
|
||
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
|
||
await nextTick()
|
||
// 重命名输入框消失
|
||
expect(win.body.querySelector('.fi-rename')).toBeNull()
|
||
})
|
||
})
|
||
|
||
// ==================== 拖放 ====================
|
||
describe('拖放', () => {
|
||
// jsdom 不完全支持 DragEvent + DataTransfer,此测试在真实浏览器验证
|
||
it.skip('拖放设置 dataTransfer', () => {
|
||
mount()
|
||
const item = win.body.querySelector('.fb-item') as HTMLElement
|
||
// jsdom DataTransfer 在新版本可用
|
||
const dt = new DataTransfer()
|
||
const event = new DragEvent('dragstart', { dataTransfer: dt, bubbles: true, cancelable: true })
|
||
item.dispatchEvent(event)
|
||
expect(dt.getData('text/x-fspath')).toBeTruthy()
|
||
})
|
||
})
|
||
|
||
// ==================== 右键菜单 ====================
|
||
describe('右键菜单', () => {
|
||
it('右键空白区触发 contextmenu', () => {
|
||
mount()
|
||
const content = win.body.querySelector('.fb-content') as HTMLElement
|
||
// Vue 的 @contextmenu.prevent 会调用 preventDefault
|
||
const event = new MouseEvent('contextmenu', { bubbles: true, cancelable: true })
|
||
content.dispatchEvent(event)
|
||
expect(event.defaultPrevented).toBe(true)
|
||
})
|
||
|
||
it('右键文件触发文件菜单', () => {
|
||
mount()
|
||
const item = win.body.querySelector('.fb-item') as HTMLElement
|
||
const event = new MouseEvent('contextmenu', { bubbles: true, cancelable: true })
|
||
item.dispatchEvent(event)
|
||
expect(event.defaultPrevented).toBe(true)
|
||
})
|
||
})
|
||
|
||
// ==================== win.appState 暴露 ====================
|
||
describe('win.appState', () => {
|
||
it('暴露 path/selection/setView 给 menus', () => {
|
||
mount()
|
||
expect(win.appState).toBeTruthy()
|
||
expect(typeof win.appState.path).toBe('string')
|
||
expect(win.appState.selection instanceof Set).toBe(true)
|
||
expect(typeof win.appState.setView).toBe('function')
|
||
expect(typeof win.appState.newFolder).toBe('function')
|
||
expect(typeof win.appState.trashSelection).toBe('function')
|
||
expect(typeof win.appState.copySel).toBe('function')
|
||
expect(typeof win.appState.paste).toBe('function')
|
||
expect(typeof win.appState.showInfo).toBe('function')
|
||
})
|
||
|
||
it('selection.size 跟随单击变化', async () => {
|
||
mount()
|
||
const item = win.body.querySelector('.fb-item') as HTMLElement
|
||
item.click()
|
||
await nextTick()
|
||
expect(win.appState.selection.size).toBe(1)
|
||
})
|
||
|
||
it('clipboard 为空时返回 null', () => {
|
||
;(window as any).__finderClipboard = null
|
||
mount()
|
||
expect(win.appState.clipboard).toBeNull()
|
||
})
|
||
})
|
||
|
||
// ==================== FS 变化刷新 ====================
|
||
describe('FS 变化', () => {
|
||
it('fs:changed 事件触发 UI 刷新', async () => {
|
||
mount()
|
||
const beforeCount = win.body.querySelectorAll('.fb-item').length
|
||
// 模拟 FS 外部变化:创建新文件夹
|
||
fs.mkdir(fs.HOME + '/Desktop/_test-refresh', { silent: true })
|
||
// 触发 fs:changed
|
||
const { bus } = await import('../../src/composables/useBus')
|
||
bus.emit('fs:changed', { op: 'mkdir', paths: [fs.HOME + '/Desktop/_test-refresh'] })
|
||
await nextTick()
|
||
const afterCount = win.body.querySelectorAll('.fb-item').length
|
||
expect(afterCount).toBe(beforeCount + 1)
|
||
// 清理
|
||
fs.remove(fs.HOME + '/Desktop/_test-refresh')
|
||
})
|
||
})
|
||
|
||
// ==================== 空文件夹 ====================
|
||
describe('空文件夹', () => {
|
||
it('空文件夹显示空状态', async () => {
|
||
// 创建一个空文件夹并导航
|
||
fs.mkdir(fs.HOME + '/Desktop/_empty-folder')
|
||
win.data = { path: fs.HOME + '/Desktop/_empty-folder' }
|
||
mount()
|
||
await nextTick()
|
||
expect(win.body.querySelector('.empty-state')?.textContent).toContain('文件夹为空')
|
||
// 清理
|
||
fs.remove(fs.HOME + '/Desktop/_empty-folder')
|
||
})
|
||
})
|
||
|
||
// ==================== 拖放高亮 ====================
|
||
describe('拖放', () => {
|
||
// jsdom 中 DragEvent 与 Vue 事件系统不完全兼容,在真实浏览器验证
|
||
it.skip('拖拽到文件夹上显示 drop-hint', async () => {
|
||
mount()
|
||
const folderEl = [...win.body.querySelectorAll('.fb-item')]
|
||
.find(el => el.querySelector('.fi-name')?.textContent === 'Sample Folder') as HTMLElement
|
||
if (!folderEl) return
|
||
folderEl.dispatchEvent(new DragEvent('dragover', { bubbles: true, cancelable: true }))
|
||
await nextTick()
|
||
expect(folderEl).toBeTruthy()
|
||
})
|
||
|
||
// jsdom 不完全支持 DragEvent + DataTransfer
|
||
it.skip('拖放设置 dataTransfer', () => {
|
||
mount()
|
||
const item = win.body.querySelector('.fb-item') as HTMLElement
|
||
const dt = new DataTransfer()
|
||
const event = new DragEvent('dragstart', { dataTransfer: dt, bubbles: true, cancelable: true })
|
||
item.dispatchEvent(event)
|
||
expect(dt.getData('text/x-fspath')).toBeTruthy()
|
||
})
|
||
})
|
||
|
||
// ==================== 图标错误回退 ====================
|
||
describe('图标', () => {
|
||
it('图标加载失败回退到 finder 图标', async () => {
|
||
mount()
|
||
const img = win.body.querySelector('.fi-icon') as HTMLImageElement
|
||
expect(img).toBeTruthy()
|
||
const originalSrc = img.src
|
||
img.dispatchEvent(new Event('error', { bubbles: true }))
|
||
await nextTick()
|
||
expect(img.src).toContain('finder.png')
|
||
})
|
||
})
|
||
|
||
// ==================== 标题更新 ====================
|
||
describe('标题', () => {
|
||
it('导航后调用 wm.setTitle', async () => {
|
||
mount()
|
||
await nextTick()
|
||
const docItem = [...win.body.querySelectorAll('.fb-side-item')]
|
||
.find(el => el.textContent?.includes('文稿')) as HTMLElement
|
||
if (docItem) {
|
||
docItem.click()
|
||
await nextTick()
|
||
expect(win.body.querySelector('.fb-crumb-item.cur')?.textContent).toBe('Documents')
|
||
}
|
||
})
|
||
})
|
||
|
||
// ==================== 卸载清理 ====================
|
||
describe('卸载清理', () => {
|
||
it('卸载后 DOM 为空', () => {
|
||
mount()
|
||
render(null, win.body)
|
||
expect(win.body.children.length).toBe(0)
|
||
})
|
||
})
|
||
})
|