From 3ecfed5d3d88a1e771597642b1894896df61d8dd Mon Sep 17 00:00:00 2001 From: mptyl Date: Sun, 28 Jun 2026 13:00:50 +0200 Subject: [PATCH] fix(frontend): valid scalar markup + selector/truncated coverage in ResultsPanel - Replace invalid role="strong" with data-testid="scalar-value" - Add test (d): selecting "tutti" re-fetches preview with the large limit - Render "(risultati troncati)" indicator when truncated; assert in test (a) Co-Authored-By: Claude Opus 4.8 --- frontend/src/viewers/ResultsPanel.test.tsx | 42 ++++++++++++++++++++-- frontend/src/viewers/ResultsPanel.tsx | 11 +++--- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/frontend/src/viewers/ResultsPanel.test.tsx b/frontend/src/viewers/ResultsPanel.test.tsx index 002c2e0a..d205e485 100644 --- a/frontend/src/viewers/ResultsPanel.test.tsx +++ b/frontend/src/viewers/ResultsPanel.test.tsx @@ -30,7 +30,7 @@ test("(a) renders grid cells for a 2×2 preview result", async () => { ["Bob", 25], ], execution_ms: 5, - truncated: false, + truncated: true, limit: 10, offset: 0, }) @@ -46,7 +46,10 @@ test("(a) renders grid cells for a 2×2 preview result", async () => { expect(screen.getByText("25")).toBeInTheDocument(); // Grid must be present, not bold scalar - expect(screen.queryByRole("strong")).not.toBeInTheDocument(); + expect(screen.queryByTestId("scalar-value")).not.toBeInTheDocument(); + + // truncated:true → show the "risultati troncati" indicator + expect(screen.getByText(/risultati troncati/i)).toBeInTheDocument(); }); // (b) 1×1 preview → bold scalar shown, no grid @@ -67,7 +70,7 @@ test("(b) renders bold scalar for a 1×1 result", async () => { render(wrap()); // Should show the scalar value in bold - const bold = await screen.findByRole("strong"); + const bold = await screen.findByTestId("scalar-value"); expect(bold).toHaveTextContent("42"); // No grid @@ -107,3 +110,36 @@ test("(c) Esporta CSV button calls the export endpoint", async () => { await waitFor(() => expect(exportCalled).toBe(true)); }); + +// (d) selecting "tutti" drives sqlPreview with the large/unlimited limit +test("(d) selecting tutti re-fetches preview with the large limit", async () => { + const limits: unknown[] = []; + + server.use( + http.post(`${BASE}/sessions/sess-4/sql/preview`, async ({ request }) => { + const body = (await request.json()) as { limit?: number }; + limits.push(body.limit); + return HttpResponse.json({ + columns: ["id"], + rows: [[1], [2]], + execution_ms: 3, + truncated: false, + limit: body.limit ?? 10, + offset: 0, + }); + }) + ); + + const user = userEvent.setup(); + render(wrap()); + + // Initial fetch uses limit 10 + await waitFor(() => expect(limits).toContain(10)); + + // Select "tutti" + const select = screen.getByLabelText(/righe da visualizzare/i); + await user.selectOptions(select, "tutti"); + + // A re-fetch with the large/unlimited limit must occur + await waitFor(() => expect(limits.some((l) => (l as number) > 10)).toBe(true)); +}); diff --git a/frontend/src/viewers/ResultsPanel.tsx b/frontend/src/viewers/ResultsPanel.tsx index af1b6fb2..3200d9c7 100644 --- a/frontend/src/viewers/ResultsPanel.tsx +++ b/frontend/src/viewers/ResultsPanel.tsx @@ -64,14 +64,17 @@ export function ResultsPanel({ sessionId }: Props) { {/* Scalar result: 1 col × 1 row → bold value */} {data && isScalar && ( - {String(data.rows[0][0])} + {String(data.rows[0][0])} )} {/* Grid for everything else */} {data && !isScalar && ( -
- -
+ <> +
+ +
+ {data.truncated &&
(risultati troncati)
} + )} );