dodil/erp-ui

tests/detail-and-timeline.test.tsx

import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import { DetailPage, FilterBar, Timeline } from "../src";
import { a11y, renderInTheme } from "./helpers";

test("a detail page: fields formatted, an unavailable action says why, panels from other modules", async () => {
  const sent: string[] = [];
  const { container } = renderInTheme(
    <DetailPage
      title="Acme AB" subtitle="acme.com · SE" status="blocked"
      actions={[{ label: "Unblock", onClick: () => sent.push("unblock"), tone: "primary" },
                { label: "Send quote", onClick: () => sent.push("send"), disabledReason: "Acme AB is blocked" }]}
      sections={[{ title: "Partner", fields: [{ label: "Tax id", value: "SE5560123401" },
                                              { label: "Open pipeline", value: "2460", kind: "money", currency: "EUR" }] }]}
      panels={[{ title: "Timeline", content: <p>calls here</p> }]}
    />,
  );
  expect(screen.getByRole("heading", { name: "Acme AB", level: 1 })).toBeInTheDocument();
  expect(screen.getByText("2,460.00 EUR")).toBeInTheDocument();
  const send = screen.getByRole("button", { name: "Send quote" });
  expect(send).toBeDisabled();
  expect(send).toHaveAttribute("aria-description", "Acme AB is blocked");
  await userEvent.click(screen.getByRole("button", { name: "Unblock" }));
  expect(sent).toEqual(["unblock"]);
  expect(screen.getByRole("region", { name: "Timeline" })).toHaveTextContent("calls here");
  expect(await a11y(container)).toEqual([]);
});

test("not found is the same answer the API gives", () => {
  renderInTheme(<DetailPage notFound />);
  expect(screen.getByText("Not found")).toBeInTheDocument();
});

test("the timeline is newest first, grouped by day", async () => {
  const { container } = renderInTheme(<Timeline items={[
    { id: "1", kind: "CALL", title: "first call", at: "2026-10-01T09:00:00Z" },
    { id: "2", kind: "NOTE", title: "about Acme", at: "2026-10-05T09:00:00Z" },
    { id: "3", kind: "TASK", title: "send proposal", at: "2026-10-05T12:00:00Z", status: "open" },
  ]} />);
  expect(screen.getAllByRole("listitem").filter((li) => li.querySelector("ul") === null).map((li) => li.textContent))
    .toEqual([expect.stringContaining("send proposal"), expect.stringContaining("about Acme"), expect.stringContaining("first call")]);
  expect(await a11y(container)).toEqual([]);
});

test("the filter bar is controlled and clears everything", async () => {
  const state = { q: "acme", role: "customer" as string | null };
  renderInTheme(<FilterBar search={{ value: state.q, onChange: (v) => (state.q = v) }}
                           filters={[{ key: "role", label: "Role", value: state.role, onChange: (v) => (state.role = v),
                                       options: [{ value: "customer", label: "Customer" }] }]} />);
  await userEvent.click(screen.getByRole("button", { name: "Clear" }));
  expect(state).toEqual({ q: "", role: null });
});