import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import nodePath from 'node:path'; import os from 'node:os'; import { promises as fs } from 'node:fs'; import { FileService } from '../../apps/desktop/src/main/services/file-service'; import { buildGraphData } from '../../apps/desktop/src/main/services/graph-builder'; import type { TreeNode } from '@hunter/shared'; const tmp = nodePath.join(os.tmpdir(), 'dsh-graph-test'); beforeEach(async () => { await fs.rm(tmp, { recursive: true, force: true }); await fs.mkdir(tmp, { recursive: true }); }); afterEach(async () => { await fs.rm(tmp, { recursive: true, force: true }); }); describe('M7 buildGraphData (FR-G1/G2/G3)', () => { it('节点=文档,按顶层分组着色', async () => { const s = new FileService(tmp); await s.create('', 'grpA', true); await s.create('', 'grpB', true); await s.create('grpA', 'd1', false); await s.create('grpB', 'd2', false); await s.writeDoc({ path: 'grpA/d1.md', meta: { title: '文档一' }, body: 'x' }); await s.writeDoc({ path: 'grpB/d2.md', meta: { star: true }, body: 'y' }); const tree = await s.listTree(); const g = await buildGraphData(tmp, tree); expect(g.nodes.length).toBe(2); const n1 = g.nodes.find(n => n.id === 'grpA/d1.md'); expect(n1?.group).toBe('grpA'); expect(n1?.title).toBe('文档一'); const n2 = g.nodes.find(n => n.id === 'grpB/d2.md'); expect(n2?.star).toBe(true); expect(n1?.color).not.toBe(n2?.color); // 不同组不同色 }); it('边=关联链接,仅目标存在且 .md', async () => { const s = new FileService(tmp); await s.create('', 'a', false); await s.create('', 'b', false); await s.create('', 'c', false); await s.writeDoc({ path: 'a.md', meta: { links: ['b.md', 'c.md', 'nope.md'] }, body: '1' }); await s.writeDoc({ path: 'b.md', meta: {}, body: '2' }); await s.writeDoc({ path: 'c.md', meta: {}, body: '3' }); const tree = await s.listTree(); const g = await buildGraphData(tmp, tree); expect(g.edges.length).toBe(2); // b.md, c.md 存在;nope.md 忽略 expect(g.edges.some(e => e.target === 'b.md')).toBe(true); expect(g.edges.some(e => e.target === 'c.md')).toBe(true); expect(g.edges.some(e => e.target === 'nope.md')).toBe(false); }); });