import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { SchemaLinkingViewer, buildErDiagram } from "./SchemaLinkingViewer"; vi.mock("./mermaid", () => ({ renderMermaid: vi.fn().mockResolvedValue(''), })); 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(); await waitFor(() => { expect(screen.getByTestId("mm")).toBeInTheDocument(); }); }); test("(b) clicking toggle switches to table listing a promoted table name", async () => { render(); // wait for mermaid to load await waitFor(() => expect(screen.getByTestId("mm")).toBeInTheDocument()); const toggle = screen.getByRole("button", { name: /table/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(); expect( screen.getByText(/too many elements for the graph/i) ).toBeInTheDocument(); }); test("(d) ~10 promoted + ~50 excluded does NOT cap; graph is available", async () => { const mixedLinking = { question: "caso misto", candidates: [ ...Array.from({ length: 10 }, (_, i) => ({ kind: "table" as const, name: `kept_${i}`, decision: "promoted" as const, })), ...Array.from({ length: 50 }, (_, i) => ({ kind: "table" as const, name: `dropped_${i}`, decision: "excluded" as const, })), ], joins: [], excluded: [], open_questions: [], }; render(); expect( screen.queryByText(/troppi elementi per il grafico/i) ).not.toBeInTheDocument(); // Grafico (mermaid) view is the default and renders the mocked svg. await waitFor(() => expect(screen.getByTestId("mm")).toBeInTheDocument()); }); test("(e) buildErDiagram emits entities, attributes and a relation", () => { const def = buildErDiagram( [ { kind: "table", name: "orders", decision: "promoted" }, { kind: "column", name: "orders.id", decision: "promoted" }, { kind: "table", name: "customers", decision: "promoted" }, ], [{ from: "orders.customer_id", to: "customers.id" }], ); expect(def.startsWith("erDiagram")).toBe(true); expect(def).toContain("orders {"); expect(def).toContain("col id"); expect(def).toContain("orders }o--o{ customers : join"); }); test("(f) buildErDiagram uses a column's real type when the data carries one", () => { const def = buildErDiagram( [ { kind: "table", name: "orders", decision: "promoted" }, { kind: "column", name: "orders.total", decision: "promoted", signals: { data_type: "numeric" } }, { kind: "column", name: "orders.id", decision: "promoted" }, // no type -> generic "col" ], [], ); expect(def).toContain("numeric total"); expect(def).toContain("col id"); });