deer-flow/frontend/tests/unit/components/workspace/artifacts/artifact-table-preview.dom.test.tsx
Ryker_Feng 9fda432ba1
feat(artifacts): preview CSV and TSV files as bounded tables (#5284)
* feat(artifacts): preview CSV and TSV files as bounded tables

* chore: keep preview screenshots out of the PR file diff

* fix(artifacts): detect record newlines outside quoted fields

* test(auth): include project permissions in me contract expectations
2026-09-08 19:11:11 +08:00

95 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { afterEach, beforeEach, describe, expect, it, rs } from "@rstest/core";
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
const state = rs.hoisted(() => ({
result: {
rows: [] as string[][],
columnCount: 2,
limited: false,
unevenRows: false,
},
status: "ready",
retry: rs.fn(),
}));
rs.mock("@/core/artifacts/use-delimited-preview", () => ({
useDelimitedPreview: () => state,
}));
import { ArtifactTablePreview } from "@/components/workspace/artifacts/artifact-table-preview";
import { I18nProvider } from "@/core/i18n/context";
function mount() {
return render(
<I18nProvider initialLocale="en-US">
<ArtifactTablePreview
content="fixture"
delimiter=","
truncated={false}
identity="file-1"
/>
</I18nProvider>,
);
}
afterEach(cleanup);
beforeEach(() => {
state.status = "ready";
state.result = {
rows: [
["ID", "Note"],
["00123", "<script>alert(1)</script>"],
],
columnCount: 2,
limited: false,
unevenRows: false,
};
});
describe("ArtifactTablePreview", () => {
it("preserves literal data and lets the first row become data", () => {
const { container } = mount();
expect(screen.getByRole("columnheader", { name: "ID" })).toBeTruthy();
expect(screen.getByText("00123")).toBeTruthy();
expect(container.querySelector("script")).toBeNull();
fireEvent.click(
screen.getByRole("checkbox", { name: "First row as header" }),
);
expect(screen.getByRole("columnheader", { name: "Column 1" })).toBeTruthy();
expect(screen.getByRole("cell", { name: "ID" })).toBeTruthy();
});
it("paginates locally and labels bounded samples honestly", () => {
state.result.rows = [
["ID", "Note"],
...Array.from({ length: 202 }, (_, i) => [String(i + 1), "note"]),
];
mount();
expect(screen.getByText("Preview of first 200 rows")).toBeTruthy();
expect(screen.getByText("150 of preview")).toBeTruthy();
fireEvent.click(screen.getByRole("button", { name: "Next page" }));
expect(screen.getByText("51100 of preview")).toBeTruthy();
expect(screen.getByRole("cell", { name: "51" })).toBeTruthy();
expect(screen.queryByRole("cell", { name: "1" })).toBeNull();
});
it("keeps long fields available without enlarging every row", () => {
const longText = "first line\n" + "x".repeat(200);
state.result.rows = [
["ID", "Note"],
["00123", longText],
];
mount();
fireEvent.click(
screen.getByRole("button", { name: "View cell: row 1, column 2" }),
);
expect(
screen.getByRole<HTMLTextAreaElement>("textbox", {
name: "Cell value",
}).value,
).toBe(longText);
});
it("offers an explicit retry without displaying stale data on failure", () => {
state.status = "error";
mount();
expect(screen.queryByRole("table")).toBeNull();
fireEvent.click(screen.getByRole("button", { name: "Retry preview" }));
expect(state.retry).toHaveBeenCalled();
});
});