Fix/frontend review findings #4
@@ -0,0 +1,57 @@
|
|||||||
|
// @vitest-environment happy-dom
|
||||||
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
||||||
|
import { mount, type VueWrapper } from '@vue/test-utils'
|
||||||
|
import { createPinia, setActivePinia } from 'pinia'
|
||||||
|
import { createMemoryHistory, createRouter } from 'vue-router'
|
||||||
|
import FileTreePanel from './FileTreePanel.vue'
|
||||||
|
import { useEditorStore } from '@/stores/editor'
|
||||||
|
import { useWorkspaceStore } from '@/stores/workspace'
|
||||||
|
|
||||||
|
let wrapper: VueWrapper | null = null
|
||||||
|
|
||||||
|
async function waitForPath(path: string) {
|
||||||
|
const editorStore = useEditorStore()
|
||||||
|
for (let attempt = 0; attempt < 100; attempt++) {
|
||||||
|
if (editorStore.currentFilePath === path) return
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||||
|
}
|
||||||
|
throw new Error(`Editor did not open ${path}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
localStorage.clear()
|
||||||
|
setActivePinia(createPinia())
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
wrapper?.unmount()
|
||||||
|
wrapper = null
|
||||||
|
document.body.innerHTML = ''
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('FileTreePanel file switching', () => {
|
||||||
|
it('switches both workspace selection and editor content on consecutive clicks', async () => {
|
||||||
|
const router = createRouter({
|
||||||
|
history: createMemoryHistory(),
|
||||||
|
routes: [{ path: '/workspace', component: { template: '<div />' } }],
|
||||||
|
})
|
||||||
|
await router.push('/workspace')
|
||||||
|
await router.isReady()
|
||||||
|
|
||||||
|
const workspaceStore = useWorkspaceStore()
|
||||||
|
const editorStore = useEditorStore()
|
||||||
|
await workspaceStore.openVault('/mock-vault')
|
||||||
|
wrapper = mount(FileTreePanel, { attachTo: document.body, global: { plugins: [router] } })
|
||||||
|
|
||||||
|
const findNode = (name: string) => wrapper!.findAll('.tree-node').find((node) => node.text().includes(name))!
|
||||||
|
await findNode('红黑树.md').trigger('click')
|
||||||
|
await waitForPath('/数据结构/红黑树.md')
|
||||||
|
expect(workspaceStore.activeFilePath).toBe('/数据结构/红黑树.md')
|
||||||
|
expect(editorStore.content).toContain('# 红黑树')
|
||||||
|
|
||||||
|
await findNode('二叉搜索树.md').trigger('click')
|
||||||
|
await waitForPath('/数据结构/二叉搜索树.md')
|
||||||
|
expect(workspaceStore.activeFilePath).toBe('/数据结构/二叉搜索树.md')
|
||||||
|
expect(editorStore.content).toContain('# 二叉搜索树')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -44,9 +44,18 @@ async function createItem() {
|
|||||||
|
|
||||||
async function openNode(node: FileNode) {
|
async function openNode(node: FileNode) {
|
||||||
if (node.type === 'folder') return workspaceStore.toggleFolder(node.path)
|
if (node.type === 'folder') return workspaceStore.toggleFolder(node.path)
|
||||||
await editorStore.loadFile(node.path)
|
// 先同步活动文件,让真实点击立即生效;内容加载失败时再恢复原状态。
|
||||||
|
const previousPath = workspaceStore.activeFilePath
|
||||||
|
const wasOpen = workspaceStore.openFiles.includes(node.path)
|
||||||
workspaceStore.openFile(node.path)
|
workspaceStore.openFile(node.path)
|
||||||
await router.push('/workspace')
|
try {
|
||||||
|
await editorStore.loadFile(node.path)
|
||||||
|
await router.push('/workspace')
|
||||||
|
} catch (error) {
|
||||||
|
if (!wasOpen) workspaceStore.closeFile(node.path)
|
||||||
|
workspaceStore.setActiveFile(previousPath)
|
||||||
|
console.error(`打开文件失败:${node.path}`, error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openContextMenu(event: MouseEvent, node: FileNode) {
|
function openContextMenu(event: MouseEvent, node: FileNode) {
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// @vitest-environment happy-dom
|
||||||
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
||||||
|
import { mount, type VueWrapper } from '@vue/test-utils'
|
||||||
|
import { createPinia, setActivePinia } from 'pinia'
|
||||||
|
import WorkspaceView from './WorkspaceView.vue'
|
||||||
|
import { useWorkspaceStore } from '@/stores/workspace'
|
||||||
|
|
||||||
|
let wrapper: VueWrapper | null = null
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
localStorage.clear()
|
||||||
|
setActivePinia(createPinia())
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
wrapper?.unmount()
|
||||||
|
wrapper = null
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('WorkspaceView initial file', () => {
|
||||||
|
it('does not overwrite a file selected while the welcome note is loading', async () => {
|
||||||
|
const workspaceStore = useWorkspaceStore()
|
||||||
|
wrapper = mount(WorkspaceView, {
|
||||||
|
global: { stubs: { EditorHeader: true, EditorPane: true } },
|
||||||
|
})
|
||||||
|
|
||||||
|
workspaceStore.openFile('/数据结构/红黑树.md')
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 0))
|
||||||
|
|
||||||
|
expect(workspaceStore.activeFilePath).toBe('/数据结构/红黑树.md')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -16,7 +16,10 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
if (!workspaceStore.activeFilePath && workspaceStore.fileTree.length === 0) {
|
if (!workspaceStore.activeFilePath && workspaceStore.fileTree.length === 0) {
|
||||||
void editorStore.loadFile('/欢迎使用知笔知己.md').then(() => {
|
void editorStore.loadFile('/欢迎使用知笔知己.md').then(() => {
|
||||||
workspaceStore.openFile('/欢迎使用知笔知己.md')
|
// 默认文件加载期间用户可能已经点击了其他文件,不能覆盖用户的选择。
|
||||||
|
if (!workspaceStore.activeFilePath && editorStore.currentFilePath === '/欢迎使用知笔知己.md') {
|
||||||
|
workspaceStore.openFile('/欢迎使用知笔知己.md')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user