feat(frontend): schema-linking viewer (mermaid+table) + markdown view

TDD: SchemaLinkingViewer with mocked renderMermaid, toggle flowchart↔table,
≤45 element cap with Italian notice. MarkdownView renders mermaid fences.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-28 12:43:11 +02:00
co-authored by Claude Sonnet 4.6
parent f933b544ff
commit 2a23de6825
6 changed files with 2825 additions and 10 deletions
@@ -0,0 +1,57 @@
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { SchemaLinkingViewer } from "./SchemaLinkingViewer";
vi.mock("./mermaid", () => ({
renderMermaid: vi.fn().mockResolvedValue('<svg data-testid="mm"></svg>'),
}));
const smallLinking = {
question: "quante ordini?",
candidates: [
{ kind: "table" as const, name: "orders", decision: "promoted" as const },
{ kind: "column" as const, name: "orders.id", decision: "promoted" as const },
{ kind: "table" as const, name: "users", decision: "excluded" as const },
],
joins: [{ from: "orders", to: "orders.id" }],
excluded: [{ kind: "table" as const, name: "users" }],
open_questions: [],
};
const bigLinking = {
question: "grossa query",
candidates: Array.from({ length: 46 }, (_, i) => ({
kind: "table" as const,
name: `table_${i}`,
decision: "promoted" as const,
})),
joins: [],
excluded: [],
open_questions: [],
};
test("(a) default renders the mermaid container (mocked svg appears)", async () => {
render(<SchemaLinkingViewer linking={smallLinking} />);
await waitFor(() => {
expect(screen.getByTestId("mm")).toBeInTheDocument();
});
});
test("(b) clicking toggle switches to table listing a promoted table name", async () => {
render(<SchemaLinkingViewer linking={smallLinking} />);
// wait for mermaid to load
await waitFor(() => expect(screen.getByTestId("mm")).toBeInTheDocument());
const toggle = screen.getByRole("button", { name: /tabella/i });
await userEvent.click(toggle);
expect(screen.getByText("orders")).toBeInTheDocument();
expect(screen.queryByTestId("mm")).not.toBeInTheDocument();
});
test("(c) oversized linking (>45) shows cap notice", () => {
render(<SchemaLinkingViewer linking={bigLinking} />);
expect(
screen.getByText(/troppi elementi per il grafico/i)
).toBeInTheDocument();
});