Display
Test Results
A four-state test report with derived progress, expandable suites, and readable failure stacks.
Preview in your theme
Loading preview…
Installation
npx shadcn@latest add https://ui.zyeon.ai/r/test-results.jsonPrompt
Build a React + TypeScript + Tailwind "TestResults" component with
lucide-react icons and a zod contract.
Contract
- The zod schema is the single source of truth:
{ status: "loading" | "empty" | "error" | "ready"; heading: string;
durationMs?: nonnegative number; errorMessage?: string;
suites: { id, name, tests: { id, name,
status: "passed" | "failed" | "skipped" | "running",
durationMs?: nonnegative number,
error?: { message, stack? } }[] }[] }.
- Export TestStatus, TestCaseResult, TestSuiteResult and TestResultsData from
the contract. Component props extend inferred data with onRetry?: () => void,
defaultExpandedSuiteIds?: string[], className and native section attributes.
Behavior
- Render four first-class branches: report-shaped loading skeleton, helpful
empty panel, error panel with optional retry, and ready summary + suites.
- Derive status counts and the passed percentage from test cases rather than
accepting duplicate summary data. When total === 0, return 0% and render the
no-pass-rate message instead of a progressbar or pass claim; never divide by
zero or display NaN.
- Failed suites start expanded unless the consumer provides explicit default
suite ids. Every suite trigger is a real button with aria-expanded and
aria-controls, keyboard focus, a screen-reader status label derived from the
same status map as the visual icon, and a labelled region for its cases.
- The contract permits a suite with tests: []. Derive that suite as "No tests"
with its own neutral icon and spoken label; never classify an empty suite as
passed. Expanding it shows an explicit no-cases message.
- Show status, duration and optional failure details per case. Error stacks
use a scrollable, focusable pre with preserved wrapping so long paths remain
readable without breaking the card width.
- Respect prefers-reduced-motion for progress transitions, chevrons and the
running spinner. Retry remains consumer-owned through onRetry.
Rendering & styling
- Use semantic tokens only: bg-card, bg-muted, text-muted-foreground,
primary for passed/running emphasis, destructive for failures, border and
ring. Do not hardcode status colors.
- Use cn() to merge className. Allow long suite, test and stack text to wrap;
status chips and durations may wrap rather than forcing horizontal overflow.
- Give the progress track role=progressbar with a descriptive label,
aria-valuemin=0, aria-valuemax=100 and the zero-safe percentage as
aria-valuenow. Decorative icons are aria-hidden.
Customization levers
- Default disclosure: pass suite ids to open a targeted subset, or change the
fallback from failure-first to all-collapsed without altering suite state.
- Summary density: remove status badges or duration while retaining the
derived total and accessible progress label.
- Failure detail: add diff, stdout or retry metadata to the error object and
render it beneath the message as sibling disclosure blocks.
- Status vocabulary: extend both the zod enum and the label/icon maps together
if the runner distinguishes flaky, timed-out or cancelled cases.
- Layout: increase the stack max height for dedicated result pages, or reduce
it for compact deployment checks; keep horizontal overflow inside the pre.Concepts
- Derived summary — counts and percentage come from the case array, so the header cannot disagree with the expanded evidence.
- Zero-safe progress — a test report may legitimately contain no cases; omitting the rate in that boundary keeps the UI and ARIA semantics honest.
- Empty is not passed — an empty suite and a report whose suites contain zero total cases get explicit no-test states, never a green check or a misleading completion percentage.
- Failure-first disclosure — failed suites open by default, reducing the number of clicks between a red summary and its cause.
- Accessible expansion — the button owns
aria-expandedandaria-controls, while the revealed case list is a labelled region. - Status beyond color — every suite trigger announces its derived Passed, Failed, Skipped or Running label even though its compact visual cue is an icon.
- Readable error evidence — stacks preserve line structure, wrap long tokens, scroll within a bounded area, and can receive keyboard focus.