diff --git a/apps/web/src/components/app/agent-surfaces/blocks/block-header.test.tsx b/apps/web/src/components/app/agent-surfaces/blocks/block-header.test.tsx new file mode 100644 index 00000000..73d8c3b6 --- /dev/null +++ b/apps/web/src/components/app/agent-surfaces/blocks/block-header.test.tsx @@ -0,0 +1,41 @@ +// @vitest-environment jsdom +import { cleanup, render, screen } from "@testing-library/react"; +import { afterEach, describe, expect, it } from "vitest"; + +import { BlockHeader } from "./block-header"; + +afterEach(() => { + cleanup(); +}); + +describe("BlockHeader", () => { + it("renders nothing when title, description, and count are all absent", () => { + const { container } = render(); + expect(container.firstChild).toBeNull(); + }); + + it("renders the title alone as an h3, with no description markup", () => { + const { container } = render(); + expect(screen.getByText("Deploy status").tagName).toBe("H3"); + // The description markdown is gated on `description` being present โ€” + // the title row should be the header's only child when it is absent. + expect(container.querySelector(".mb-1\\.5")?.children.length).toBe(1); + }); + + it("renders a count of 0 on its own, proving the check is `!== undefined` not truthiness", () => { + const { container } = render(); + expect(screen.getByText("(0)")).toBeTruthy(); + expect(container.querySelector("h3")).toBeNull(); + }); + + it("renders the count parenthesized next to the title", () => { + render(); + expect(screen.getByText("(5)")).toBeTruthy(); + }); + + it("renders description as markdown when title and count are both absent", () => { + const { container } = render(); + expect(screen.getByText("Extra context.")).toBeTruthy(); + expect(container.querySelector("h3")).toBeNull(); + }); +}); diff --git a/apps/web/src/components/app/agent-surfaces/blocks/status-block.test.tsx b/apps/web/src/components/app/agent-surfaces/blocks/status-block.test.tsx new file mode 100644 index 00000000..9a21a291 --- /dev/null +++ b/apps/web/src/components/app/agent-surfaces/blocks/status-block.test.tsx @@ -0,0 +1,86 @@ +// @vitest-environment jsdom +import { cleanup, render, screen } from "@testing-library/react"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +import type { StatusBlock } from "@/components/app/agent-surfaces/types"; +import { formatSurfaceTime } from "@/components/app/agent-surfaces/format"; +import { TONE_CLASSES } from "@/components/app/agent-surfaces/tone"; +import { StatusBlockView } from "./status-block"; + +afterEach(() => { + vi.useRealTimers(); + cleanup(); +}); + +function block(overrides: Partial = {}): StatusBlock { + return { + id: "s1", + type: "status", + status: "Running", + ...overrides, + } as StatusBlock; +} + +describe("StatusBlockView", () => { + it("defaults to neutral tone when none is authored", () => { + const { container } = render(); + const dot = container.querySelector('[aria-hidden="true"]'); + expect(dot?.className).toContain(TONE_CLASSES.neutral.dot); + expect(screen.getByText("Running").className).toContain( + TONE_CLASSES.neutral.text + ); + }); + + it("applies the authored tone's dot and text classes", () => { + const { container } = render( + + ); + const dot = container.querySelector('[aria-hidden="true"]'); + expect(dot?.className).toContain(TONE_CLASSES.danger.dot); + expect(screen.getByText("Running").className).toContain( + TONE_CLASSES.danger.text + ); + }); + + it("renders no