76 lines
3.6 KiB
JavaScript
76 lines
3.6 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { createRequire } from "node:module";
|
|
import { pathToFileURL } from "node:url";
|
|
|
|
const require = createRequire(import.meta.url);
|
|
const { chromium } = require("playwright");
|
|
|
|
const html = process.env.GRAPH_NODE_SLIM_HTML || "";
|
|
assert.notEqual(html, "", "GRAPH_NODE_SLIM_HTML must point at generated HTML");
|
|
|
|
const browser = await chromium.launch({
|
|
// This regression targets the DOM/SVG small-graph fallback. The default offline
|
|
// global route uses Sigma when WebGL is available, which has a different DOM.
|
|
args: ["--disable-webgl", "--disable-webgl2", "--disable-3d-apis"]
|
|
});
|
|
try {
|
|
const page = await browser.newPage({ viewport: { width: 1440, height: 960 } });
|
|
await page.goto(pathToFileURL(html).href);
|
|
await page.waitForSelector("[data-llm-wiki-graph-root='true']");
|
|
|
|
const node = page.locator(".node[data-id='A']");
|
|
await node.waitFor();
|
|
await assertNodeDetailDisplay(node, "none", "none", "default card node should hide type and weight details");
|
|
assert.equal(await node.locator(".node-name").innerText(), "节点A", "default card node should keep the title visible");
|
|
|
|
await node.hover();
|
|
await assertNodeDetailDisplay(node, "block", "flex", "hovered card node should expose type and weight details");
|
|
await page.waitForSelector(".graph-hover-preview[data-state='open']");
|
|
const preview = page.locator(".graph-hover-preview");
|
|
await preview.locator(".graph-hover-preview-title", { hasText: /^节点A$/ }).waitFor();
|
|
await preview.getByText("实体").waitFor();
|
|
await preview.getByText("这是节点A的内容。").waitFor();
|
|
assert.equal(await preview.locator(".graph-hover-preview-summary").count(), 1, "content nodes should show a preview summary");
|
|
|
|
await page.mouse.move(20, 20);
|
|
await waitForPreviewState(page, "closed");
|
|
await assertNodeDetailDisplay(node, "none", "none", "card node details should hide again after hover leaves");
|
|
|
|
await node.click();
|
|
await page.waitForSelector(".graph-reader[data-state='open']");
|
|
await assertNodeDetailDisplay(node, "block", "flex", "selected card node should expose type and weight details");
|
|
|
|
const emptyNode = page.locator(".node[data-id='empty-preview']");
|
|
if (await emptyNode.count()) {
|
|
await emptyNode.hover();
|
|
await page.waitForSelector(".graph-hover-preview[data-state='open']");
|
|
await preview.locator(".graph-hover-preview-title", { hasText: /^空内容节点$/ }).waitFor();
|
|
await preview.getByText("主题").waitFor();
|
|
assert.equal(await preview.locator(".graph-hover-preview-summary").count(), 0, "empty content nodes should omit summary text");
|
|
}
|
|
} finally {
|
|
await browser.close();
|
|
}
|
|
|
|
async function waitForPreviewState(page, state) {
|
|
await page.waitForFunction((state) => {
|
|
return document.querySelector(".graph-hover-preview")?.dataset.state === state;
|
|
}, state);
|
|
}
|
|
|
|
async function assertNodeDetailDisplay(node, expectedKind, expectedMeta, message) {
|
|
const actual = await node.evaluate((element) => {
|
|
const kind = element.querySelector(".node-kind");
|
|
const meta = element.querySelector(".node-meta");
|
|
const styles = element.ownerDocument.defaultView;
|
|
return {
|
|
kind: kind && styles ? styles.getComputedStyle(kind).display : "",
|
|
meta: meta && styles ? styles.getComputedStyle(meta).display : "",
|
|
metaText: meta?.textContent?.trim() || ""
|
|
};
|
|
});
|
|
assert.equal(actual.kind, expectedKind, `${message}: node kind display`);
|
|
assert.equal(actual.meta, expectedMeta, `${message}: node meta display`);
|
|
assert.match(actual.metaText, /\d+|来源暂不可用/, `${message}: node meta text should remain available`);
|
|
}
|