真正根因: GraphView 容器有 flex:1(在行布局中)但不是 display:flex, 子组件 MindmapTree/LinkGraph 的 flex:1 被忽略 → 高度 auto = 0 (子内容全是绝对定位,无在流内容) → SVG 高度 0 → fit() 计算 NaN 持续报 translate(NaN,NaN) 错误,内容不可见 之前 E2E 只数 DOM 元素数量不检查可见性,掩盖了此 bug 修复: GraphView 容器加 display:flex + flexDirection:column, 子组件 flex:1 正常生效,容器高度正确,内容可见 附带: - 主进程转发渲染进程 console 到终端(便于 dev 调试) - graph-render E2E 测试改为检查可见性(getBoundingClientRect) - 修复 TabBar 关闭全部测试的 flaky 断言(expect.poll 自动重试)
78 lines
3.7 KiB
TypeScript
78 lines
3.7 KiB
TypeScript
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();
|
|
}); |