import { test, expect } from '@playwright/test'; import { _electron as electron } from 'playwright'; import { promises as fs } from 'node:fs'; import nodePath from 'node:path'; import os from 'node:os'; const MAIN_JS = nodePath.join(process.cwd(), 'dist-electron/main/index.js'); test('思维导图+知识图谱渲染验证(含可见性)', async () => { const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-graph-fix-')); const userData = nodePath.join(tmp, 'userdata'); const vault = nodePath.join(tmp, 'vault'); await fs.mkdir(userData, { recursive: true }); await fs.mkdir(vault, { recursive: true }); await fs.writeFile(nodePath.join(vault, 'doc1.md'), '---\ntitle: 文档一\nlinks:\n - doc2.md\n---\n# 文档一\n链接到 doc2'); await fs.writeFile(nodePath.join(vault, 'doc2.md'), '---\ntitle: 文档二\n---\n# 文档二\n内容'); const app = await electron.launch({ args: ['--user-data-dir=' + userData, MAIN_JS] }); const page = await app.firstWindow(); await page.waitForLoadState('domcontentloaded'); const invoke = (ch: string, args: any) => page.evaluate(({ ch, args }) => (globalThis as any).dsh.invoke(ch, args), { ch, args }); await invoke('vault:switch', { root: vault }); await page.evaluate(() => (window as any).__STORE__.getState().loadTree()); await page.waitForTimeout(1000); // Switch to graph view (default mode is mindmap) await page.getByTitle('切换 编辑器/图谱').click(); await page.waitForTimeout(2000); // Mindmap: verify SVG has non-zero size AND visible content const mindmap = await page.evaluate(() => { const svg = document.querySelector('.markmap-dark svg'); if (!svg) return { found: false }; const rect = svg.getBoundingClientRect(); const fo = svg.querySelectorAll('foreignObject').length; const g = svg.querySelectorAll('g').length; // Check that content is actually visible (has bounding boxes within the svg) const visibleContent = Array.from(svg.querySelectorAll('g.markmap-node')).some((el) => { const r = el.getBoundingClientRect(); return r.width > 0 && r.height > 0; }); return { found: true, w: rect.width, h: rect.height, foreignObject: fo, g, visibleContent }; }); console.log('Mindmap:', JSON.stringify(mindmap)); expect(mindmap.found).toBe(true); expect(mindmap.h).toBeGreaterThan(100); // svg must have real height expect(mindmap.foreignObject).toBeGreaterThan(0); expect(mindmap.visibleContent).toBe(true); // content must be visibly rendered // Switch to knowledge graph mode await page.getByRole('button', { name: '知识图谱' }).click(); await page.waitForTimeout(3000); const graph = await page.evaluate(() => { const svgs = document.querySelectorAll('svg'); let svg: SVGElement | null = null; for (const s of svgs) { if (s.querySelectorAll('g[transform]').length > 0 || s.querySelectorAll('rect').length > 1) { svg = s; break; } } if (!svg) return { found: false }; const rect = svg.getBoundingClientRect(); const rects = svg.querySelectorAll('rect').length; const texts = svg.querySelectorAll('text').length; const lines = svg.querySelectorAll('line').length; // Check a node card is visible within the svg const visibleCard = Array.from(svg.querySelectorAll('rect')).some((r) => { const b = r.getBoundingClientRect(); return b.width > 0 && b.height > 0; }); return { found: true, w: rect.width, h: rect.height, rects, texts, lines, visibleCard }; }); console.log('Knowledge graph:', JSON.stringify(graph)); expect(graph.found).toBe(true); expect(graph.h).toBeGreaterThan(100); expect(graph.rects).toBeGreaterThanOrEqual(5); expect(graph.lines).toBeGreaterThanOrEqual(1); expect(graph.visibleCard).toBe(true); await app.close(); });