Files
ThothII/frontend/src/viewers/CteResultViewer.test.tsx
T

135 lines
5.1 KiB
TypeScript

import { render, screen } from "@testing-library/react";
import { CteResultViewer } from "./CteResultViewer";
import type { CteResultV2 } from "./artifactV2";
vi.mock("./highlight", () => ({
highlightSql: vi.fn().mockResolvedValue('<pre data-testid="hl">SQL</pre>'),
}));
const okResult: CteResultV2 = {
schema_version: 2,
name: "pazienti_idonei",
index: 1,
total: 2,
purpose: "Seleziona i pazienti con follow-up attivo",
rationale: "Base della catena",
depends_on: [],
sql: "WITH pazienti_idonei AS (SELECT 1)",
status: "ok",
execution_ms: 142,
row_sample: 10,
warnings: [],
columns: [{ name: "paziente_id", description: "Identificativo paziente" }],
preview: { columns: ["paziente_id"], rows: [[1], [2]] },
note: "Nota del modello",
};
test("renders header meta: index/total badge, mono name, status badge, execution_ms, row_sample", async () => {
render(<CteResultViewer result={okResult} />);
await screen.findByTestId("hl");
expect(screen.getByText("CTE 1/2")).toBeInTheDocument();
expect(screen.getAllByText("pazienti_idonei").length).toBeGreaterThan(0);
expect(screen.getByText(/success|ok/i)).toBeInTheDocument();
expect(screen.getByText(/142 ms/)).toBeInTheDocument();
expect(screen.getByText(/10 rows/)).toBeInTheDocument();
});
test("renders warnings as badges", async () => {
const withWarnings: CteResultV2 = { ...okResult, warnings: ["colonna troncata"] };
render(<CteResultViewer result={withWarnings} />);
await screen.findByTestId("hl");
expect(screen.getByText("colonna troncata")).toBeInTheDocument();
});
test("passes sql to SqlViewer with mapped test status", async () => {
render(<CteResultViewer result={okResult} />);
await screen.findByTestId("hl");
expect(screen.getByText(/passed/i)).toBeInTheDocument();
expect(screen.queryByRole("button", { name: /horizontal|vertical/i })).not.toBeInTheDocument();
});
test("error status maps to failed test status and destructive badge", async () => {
const errored: CteResultV2 = { ...okResult, status: "error" };
render(<CteResultViewer result={errored} />);
await screen.findByTestId("hl");
expect(screen.getByText(/failed/i)).toBeInTheDocument();
});
test("renders PreviewGrid rows when preview is present", async () => {
render(<CteResultViewer result={okResult} />);
await screen.findByTestId("hl");
const cells = screen.getAllByRole("gridcell").map((c) => c.textContent);
expect(cells).toContain("1");
expect(cells).toContain("2");
});
test("shows a discreet empty-state when preview is absent", async () => {
const noPreview: CteResultV2 = { ...okResult, preview: undefined };
render(<CteResultViewer result={noPreview} />);
await screen.findByTestId("hl");
expect(screen.getByText(/no preview rows/i)).toBeInTheDocument();
});
test("shows empty-state when preview has no rows", async () => {
const emptyPreview: CteResultV2 = { ...okResult, preview: { columns: ["paziente_id"], rows: [] } };
render(<CteResultViewer result={emptyPreview} />);
await screen.findByTestId("hl");
expect(screen.getByText(/no preview rows/i)).toBeInTheDocument();
});
test("shows empty-state, no crash, when preview.rows is null (pre-upgrade records)", async () => {
const nullRows = {
...okResult,
preview: { columns: ["paziente_id"], rows: null as unknown as (string | number)[][] },
};
render(<CteResultViewer result={nullRows} />);
await screen.findByTestId("hl");
expect(screen.getByText(/no preview rows/i)).toBeInTheDocument();
});
test("renders columns definition list with descriptions", async () => {
const { container } = render(<CteResultViewer result={okResult} />);
await screen.findByTestId("hl");
const dt = container.querySelector("dl dt");
expect(dt).toHaveTextContent("paziente_id");
expect(screen.getByText("Identificativo paziente")).toBeInTheDocument();
});
test("omits the columns definition list when all descriptions are empty", async () => {
const noDescriptions: CteResultV2 = {
...okResult,
columns: [{ name: "paziente_id", description: "" }],
};
const { container } = render(<CteResultViewer result={noDescriptions} />);
await screen.findByTestId("hl");
// No <dl> definition list should render when all descriptions are empty.
expect(container.querySelector("dl")).not.toBeInTheDocument();
});
test("renders note at the end", async () => {
render(<CteResultViewer result={okResult} />);
await screen.findByTestId("hl");
expect(screen.getByText("Nota del modello")).toBeInTheDocument();
});
test("renders depends_on chips when present", async () => {
const withDeps: CteResultV2 = { ...okResult, depends_on: ["cte_base"] };
render(<CteResultViewer result={withDeps} />);
await screen.findByTestId("hl");
expect(screen.getByText("cte_base")).toBeInTheDocument();
});
test("does not render 'undefined' strings for missing optional fields", async () => {
const minimal: CteResultV2 = {
schema_version: 2,
name: "final",
index: 2,
total: 2,
sql: "SELECT 1",
status: "ok",
};
render(<CteResultViewer result={minimal} />);
await screen.findByTestId("hl");
expect(screen.queryByText(/undefined/i)).not.toBeInTheDocument();
});