import { MantineProvider } from "@mantine/core"; import { cleanup, render, screen, within } from "@testing-library/react"; import { afterEach, describe, expect, test } from "vitest"; import { fixtureTask } from "./fixtures"; import { durationBetween, formatCompactTokens, formatEstimatedCost, formatReportedDuration, taskReportedWorkView, turnReportedWorkView, turnUsageMetricsView, turnUsageView, usageStillCalculating, usageView, } from "./presentation"; import { ShimmerText } from "./components/ShimmerText"; import { GitHubLinks } from "./components/GitHubLinks"; import { LinkedText } from "./components/LinkedText"; import { UsagePanel } from "./components/UsagePanel"; afterEach(cleanup); describe("token and working presentation", () => { test("keeps pending, calculating, ready cost, and unavailable wording distinct", () => { expect(usageView(fixtureTask()).label).toBe("Token usage pending"); expect(usageView(fixtureTask({ status: "completed", usage: { generationTurnRef: "turn-one", status: "calculating" }, })).label).toBe("Calculating token usage"); expect(usageView(fixtureTask({ status: "completed", usage: { generationTurnRef: "turn-one", status: "available", task: { totalTokens: 12345, estimatedCostUsd: 0.1234 }, }, })).label).toBe("12.35K tokens · Estimated cost $0.12"); expect(usageView(fixtureTask({ status: "completed", usage: { status: "unavailable" } })).label) .toBe("Token usage unavailable"); expect(usageView(fixtureTask({ status: "completed", usage: { status: "unavailable", reason: "This task has no linked Codex thread." }, })).label).toBe("This task has no linked Codex thread."); expect(usageView(fixtureTask({ status: "completed", usage: undefined })).label) .toBe("Calculating token usage"); }); test("keeps cumulative usage visible as known so far during a newer working turn", () => { const view = usageView(fixtureTask({ status: "working", turnRef: "turn-two", usage: { generationTurnRef: "turn-one", status: "calculating", task: { totalTokens: 12345, estimatedCostUsd: 0.1234 }, }, })); expect(view.kind).toBe("ready"); expect(view.label).toBe("12.35K tokens · Estimated cost $0.12 · known so far"); if (view.kind === "ready") expect(view.knownSoFar).toBe(true); }); test("keeps cumulative usage visible while a newer terminal generation is calculating", () => { const view = usageView(fixtureTask({ status: "completed", turnRef: "turn-two", usage: { generationTurnRef: "turn-one", status: "calculating", task: { totalTokens: 12345, estimatedCostUsd: 0.1234 }, }, })); expect(view.kind).toBe("ready"); expect(view.label).toBe("12.35K tokens · Estimated cost $0.12 · known so far"); if (view.kind === "ready") expect(view.knownSoFar).toBe(true); }); test("distinguishes available, pending, calculating, and unavailable per-turn usage", () => { const task = fixtureTask({ usage: { status: "available", turns: { "turn-one": { status: "available", totalTokens: 330, estimatedCostUsd: 0.12 }, }, }, }); const completedTurn = { ...task.turns![0], result: { status: "completed" as const, summary: "Done.", updatedAt: task.updatedAt, }, }; expect(turnUsageView(task, completedTurn).label).toBe("330 tokens · Estimated cost $0.12"); expect(turnUsageView(task, { ...completedTurn, result: null }).label).toBe("Turn usage pending"); expect(turnUsageView({ ...task, usage: { status: "calculating", turns: { "turn-one": { status: "calculating" } } }, }, completedTurn).label).toBe("Calculating turn usage"); expect(turnUsageView({ ...task, usage: { status: "unavailable", turns: {} } }, completedTurn).label) .toBe("Turn usage unavailable"); }); test("polling is reserved for terminal usage that is actually calculating", () => { expect(usageStillCalculating(fixtureTask())).toBe(false); expect(usageStillCalculating(fixtureTask({ status: "completed", usage: { generationTurnRef: "turn-one", status: "calculating" }, }))).toBe(true); expect(usageStillCalculating(fixtureTask({ status: "completed", usage: { status: "unavailable", turns: { old: { status: "calculating" } } }, }))).toBe(true); }); test("marks working text with the approved text shimmer state", () => { render(In progress); expect(screen.getByText("In progress")).toHaveClass("taskchef-shimmer"); expect(screen.getByText("In progress")).toHaveAttribute("data-animation", "text-shimmer"); }); test("summarizes ready usage and reported work as one operator-facing metric group", () => { const completedTurn = { ...fixtureTask().turns![0], result: { status: "completed" as const, summary: "Done.", updatedAt: "2026-08-30T08:18:32.000Z", }, }; render( , ); expect(screen.getByText("Tokens").nextSibling).toHaveTextContent("330"); expect(screen.getByText("Estimated cost").nextSibling).toHaveTextContent("$0.12"); expect(screen.getByText("Duration").nextSibling).toHaveTextContent("18m 32s"); expect(screen.getByLabelText(/reported work 18m 32s.*wall-clock/i)).toBeVisible(); expect(screen.getByText("Models").nextSibling).toHaveTextContent("gpt-5.6-sol, gpt-5.6-luna"); expect(screen.queryByText("Cache ratio")).not.toBeInTheDocument(); expect(screen.getByText("Tokens").closest(".taskchef-metrics")?.children).toHaveLength(4); expect(screen.queryByText(/API-equivalent/i)).not.toBeInTheDocument(); }); test("uses n/a for missing ready usage metrics with explanatory accessibility", () => { render( , ); expect(screen.getByText("Estimated cost").nextSibling).toHaveTextContent("n/a"); expect(screen.getByLabelText("Estimated cost unavailable")).toBeVisible(); expect(screen.getByText("Models").nextSibling).toHaveTextContent("n/a"); expect(screen.getByLabelText("Models unavailable")).toBeVisible(); expect(screen.queryByText("Cache ratio")).not.toBeInTheDocument(); }); test("shimmers known usage values during a running turn without changing card titles", () => { const { container, rerender } = render( , ); expect(screen.getByText("Tokens")).toBeVisible(); expect(screen.queryByText(/known so far/i)).not.toBeInTheDocument(); expect(container.querySelectorAll(".taskchef-shimmer")).toHaveLength(2); rerender( , ); expect(container.querySelectorAll(".taskchef-shimmer")).toHaveLength(1); }); test("keeps reported work visible across pending, calculating, and unavailable usage", () => { for (const [task, expected, accessibleCost] of [ [fixtureTask(), "Pending", "Estimated cost pending"], [ fixtureTask({ status: "completed", usage: { status: "calculating" } }), "Calculating", "Estimated cost calculating", ], [ fixtureTask({ status: "completed", usage: { status: "unavailable" } }), "n/a", "Estimated cost unavailable: Token usage unavailable", ], ] as const) { render(); expect(screen.getByText("Tokens").nextSibling).toHaveTextContent(expected); expect(screen.getByText("Estimated cost").nextSibling).toHaveTextContent(expected); expect(screen.getByLabelText(accessibleCost)).toBeVisible(); expect(screen.getByText("Duration").nextSibling).toHaveTextContent("n/a"); expect(screen.getByText("Models").nextSibling).toHaveTextContent("n/a"); expect(screen.getByText("Tokens").closest(".taskchef-metrics")?.children).toHaveLength(4); cleanup(); } }); test("uses the same borderless link treatment wherever links are rendered", () => { render(); expect(screen.getByRole("link")).toHaveClass("taskchef-github-link"); }); test("formats compact token boundaries without scientific notation", () => { expect([ 0, 999, 1_000, 1_100, 12_345, 999_999, 1_320_000, 1_000_000_000, ].map((value) => formatCompactTokens(value, "en-US"))).toEqual([ "0", "999", "1K", "1.1K", "12.35K", "1M", "1.32M", "1B", ]); }); test("formats estimates to two decimals across zero, sub-cent, missing, and large values", () => { expect(formatEstimatedCost(0, "en-US")).toBe("$0.00"); expect(formatEstimatedCost(0.0049, "en-US")).toBe("$0.00"); expect(formatEstimatedCost(12.344, "en-US")).toBe("$12.34"); expect(formatEstimatedCost(12.345, "en-US")).toBe("$12.35"); expect(formatEstimatedCost(null, "en-US")).toBe("—"); expect(formatEstimatedCost(Number.NaN, "en-US")).toBe("—"); expect(formatEstimatedCost(1_234_567_890.125, "en-US")).toBe("$1,234,567,890.13"); }); test("exposes full token precision and the unrounded estimate on ready metric cards", () => { render( , ); expect(screen.getByLabelText("1,324,567 tokens")).toHaveTextContent("1.32M"); expect(screen.getByLabelText("1,324,567 tokens")).toHaveAttribute("title", "1,324,567 tokens"); expect(screen.getByLabelText("Estimated cost $12.34")).toHaveTextContent("$12.34"); expect(screen.getByLabelText("Estimated cost $12.34")).toHaveAttribute( "title", "Unrounded estimate: $12.3449", ); }); test("groups, deduplicates, and naturally sorts compact related links by repository", () => { const task = fixtureTask({ relatedGitHubLinks: [ ["taskchef", "83", "pull"], ["guzuoshou-workspace", "124", "issue"], ["taskchef", "79", "issue"], ["guzuoshou-workspace", "108", "issue"], ["taskchef", "80", "issue"], ["guzuoshou-workspace", "109", "pull"], ["taskchef", "79", "pull"], ].map(([repository, number, type]) => ({ label: `favoyang/${repository}#${number}`, number, owner: "favoyang", repository, type: type as "issue" | "pull", url: `https://github.com/favoyang/${repository}/${type === "pull" ? "pull" : "issues"}/${number}`, })), }); const { container } = render(); const groups = container.querySelectorAll(".taskchef-github-group"); expect(groups).toHaveLength(2); expect(within(groups[0] as HTMLElement).getAllByRole("link").map((link) => link.textContent)) .toEqual(["guzuoshou-workspace #108", "#109", "#124"]); expect(within(groups[1] as HTMLElement).getAllByRole("link").map((link) => link.textContent)) .toEqual(["taskchef #79", "#80", "#83"]); const first = screen.getByRole("link", { name: /favoyang\/taskchef Issue #79/ }); expect(first).toHaveAttribute("href", "https://github.com/favoyang/taskchef/issues/79"); expect(first).toHaveAttribute("target", "_blank"); expect(first).toHaveAttribute("rel", "noopener noreferrer"); expect(screen.queryByText(/PR #|Issue #/)).not.toBeInTheDocument(); }); test("keeps established inline request and result link labels", () => { const task = fixtureTask({ project: { name: "TaskChef Preview", path: "/tmp/taskchef-preview-project", githubRepos: ["https://github.com/favoyang/taskchef"], }, relatedGitHubRepository: "favoyang/taskchef", }); const { container } = render(
, ); expect(within(container).getByRole("link", { name: /favoyang\/taskchef PR #83/ })) .toHaveTextContent("taskchef PR #83"); }); }); describe("reported wall-clock work presentation", () => { test("covers formatting, derivation, unavailable boundaries, usage states, and accessibility", () => { expect(formatReportedDuration(500)).toBe("<1s"); expect(formatReportedDuration(32_999)).toBe("32s"); expect(formatReportedDuration((18 * 60 + 32) * 1_000 + 999)).toBe("18m 32s"); expect(formatReportedDuration((2 * 60 + 14) * 60 * 1_000 + 59_999)).toBe("2h 14m"); expect(formatReportedDuration((27 * 60 + 59) * 60 * 1_000)).toBe("1d 3h"); expect(formatReportedDuration(-1)).toBeNull(); expect(formatReportedDuration(Number.NaN)).toBeNull(); { const task = fixtureTask({ status: "working", turns: [ { requestSummary: "First turn", startedAt: "2026-08-30T08:00:00.000Z", turnRef: "turn-one", turnId: null, result: { status: "completed", summary: "First done", updatedAt: "2026-08-30T08:18:32.000Z", }, }, { requestSummary: "Second turn after a long idle gap", startedAt: "2026-08-30T18:00:00.000Z", turnRef: "turn-two", turnId: null, result: { status: "failed", summary: "Second done", updatedAt: "2026-08-30T20:14:00.000Z", }, }, { requestSummary: "Active follow-up", startedAt: "2026-08-31T08:00:00.000Z", turnRef: "turn-three", turnId: null, result: null, }, ], }); const view = taskReportedWorkView(task); expect(view.kind).toBe("available"); expect(view.value).toBe("2h 32m"); expect(view.title).toMatch(/idle gaps are excluded/i); } { const invalid = fixtureTask({ status: "completed", turns: [{ requestSummary: "Historical turn", startedAt: "not-a-date", turnRef: "turn-one", turnId: null, result: { status: "completed", summary: "Done", updatedAt: "2026-08-30T08:00:00.000Z" }, }], }); expect(taskReportedWorkView(invalid)).toMatchObject({ kind: "unavailable", value: "n/a" }); expect(durationBetween("2026-08-30T08:01:00.000Z", "2026-08-30T08:00:00.000Z")).toBeNull(); expect(durationBetween("2026-02-30T08:00:00.000Z", "2026-03-02T08:01:00.000Z")).toBeNull(); expect(durationBetween("March 2, 2026 08:00:00 UTC", "2026-03-02T08:01:00.000Z")).toBeNull(); expect(turnReportedWorkView(invalid.turns![0])).toMatchObject({ kind: "unavailable", label: "Elapsed", value: "n/a", }); } { const terminalResult = { status: "completed" as const, summary: "Done.", updatedAt: "2026-08-30T08:00:00.000Z", }; const legacyTurn = { requestSummary: null, startedAt: terminalResult.updatedAt, turnRef: "legacy-turn", turnId: null, provenance: { kind: "legacy" }, result: terminalResult, }; const terminalOnlyTurn = { ...legacyTurn, turnRef: "terminal-only-turn", provenance: { kind: "mcp" }, }; for (const turn of [legacyTurn, terminalOnlyTurn]) { expect(turnReportedWorkView(turn)).toMatchObject({ kind: "unavailable", value: "n/a" }); expect(taskReportedWorkView(fixtureTask({ status: "completed", turns: [turn] }))) .toMatchObject({ kind: "unavailable", value: "n/a" }); } } { const observed = { requestSummary: "Perform the observed turn.", startedAt: "2026-08-30T08:00:00.000Z", turnRef: "observed-turn", turnId: null, provenance: { kind: "mcp" }, result: { status: "completed" as const, summary: "Done.", updatedAt: "2026-08-30T08:00:00.000Z", }, }; expect(turnReportedWorkView(observed)).toMatchObject({ kind: "unavailable", value: "n/a" }); expect(turnReportedWorkView({ ...observed, result: { ...observed.result, updatedAt: "2026-08-30T08:00:00.500Z" }, })).toMatchObject({ kind: "available", value: "<1s" }); } { const compactTerminal = fixtureTask({ status: "completed", turns: undefined, latestTurn: { ...fixtureTask().latestTurn!, result: { status: "completed", summary: "Done.", updatedAt: "2026-08-30T08:18:32.000Z", }, }, }); expect(taskReportedWorkView(compactTerminal)).toMatchObject({ kind: "unavailable", value: "n/a", }); expect(taskReportedWorkView({ ...compactTerminal, reportedWork: { terminalTurns: 1, validTurns: 1, totalMilliseconds: 1_112_000 }, })).toMatchObject({ kind: "available", value: "18m 32s" }); render(); expect(screen.getByText("Duration").nextSibling).toHaveTextContent("n/a"); cleanup(); } { const priorResult = { status: "completed" as const, summary: "Prior turn done.", updatedAt: "2026-08-30T08:18:32.000Z", turnRef: "turn-one", turnId: null, }; expect(taskReportedWorkView(fixtureTask({ status: "working", turnRef: "turn-two", turns: undefined, lastResult: priorResult, results: undefined, }))).toMatchObject({ kind: "unavailable", value: "n/a" }); } { render( , ); expect(screen.getByText("No matching cached boundary.")).toBeVisible(); expect(screen.getByLabelText("No matching cached boundary.")).toBeVisible(); cleanup(); } { const task = fixtureTask(); expect(turnReportedWorkView(task.turns![0], Date.parse("2026-08-30T08:18:32.000Z"))).toMatchObject({ label: "Elapsed so far", value: "18m 32s", }); expect(turnUsageMetricsView(task, task.turns![0])).toMatchObject({ animated: true, cost: { value: "Pending" }, tokens: { value: "Pending" }, }); } }); });