{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ai-test-results",
  "title": "AI: Test Results",
  "description": "A test-run summary with suite results, statuses, durations and expandable failures.",
  "dependencies": [
    "@untitledui/icons@^0.0.23"
  ],
  "registryDependencies": [
    "@nx-ui/utils",
    "@nx-ui/badge",
    "@nx-ui/collapsible"
  ],
  "files": [
    {
      "path": "components/ai/test-results.tsx",
      "content": "// Ported from vercel/ai-elements@6a9d5b1822ffb10bba4bd97175f01edd7d8651cd.\n\"use client\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport {\n  Collapsible,\n  CollapsibleContent,\n  CollapsibleTrigger,\n} from \"@/components/ui/collapsible\";\nimport { cn } from \"@/lib/utils\";\nimport {\n  CheckCircle as CheckCircle2Icon,\n  ChevronRight as ChevronRightIcon,\n  Circle as CircleDotIcon,\n  Circle as CircleIcon,\n  XCircle as XCircleIcon,\n} from \"@untitledui/icons\";\nimport type { ComponentProps, HTMLAttributes } from \"react\";\nimport { createContext, useContext, useMemo } from \"react\";\n\ntype TestStatus = \"passed\" | \"failed\" | \"skipped\" | \"running\";\n\ninterface TestResultsSummary {\n  passed: number;\n  failed: number;\n  skipped: number;\n  total: number;\n  duration?: number;\n}\n\ninterface TestResultsContextType {\n  summary?: TestResultsSummary;\n}\n\nconst TestResultsContext = createContext<TestResultsContextType>({});\n\nconst formatDuration = (ms: number) => {\n  if (ms < 1000) {\n    return `${ms}ms`;\n  }\n  return `${(ms / 1000).toFixed(2)}s`;\n};\n\nexport type TestResultsHeaderProps = HTMLAttributes<HTMLDivElement>;\n\nexport const TestResultsHeader = ({\n  className,\n  children,\n  ...props\n}: TestResultsHeaderProps) => (\n  <div\n    className={cn(\n      \"flex items-center justify-between border-b px-4 py-3\",\n      className\n    )}\n    {...props}\n  >\n    {children}\n  </div>\n);\n\nexport type TestResultsDurationProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const TestResultsDuration = ({\n  className,\n  children,\n  ...props\n}: TestResultsDurationProps) => {\n  const { summary } = useContext(TestResultsContext);\n\n  if (!summary?.duration) {\n    return null;\n  }\n\n  return (\n    <span className={cn(\"text-muted-foreground text-sm\", className)} {...props}>\n      {children ?? formatDuration(summary.duration)}\n    </span>\n  );\n};\n\nexport type TestResultsSummaryProps = HTMLAttributes<HTMLDivElement>;\n\nexport const TestResultsSummary = ({\n  className,\n  children,\n  ...props\n}: TestResultsSummaryProps) => {\n  const { summary } = useContext(TestResultsContext);\n\n  if (!summary) {\n    return null;\n  }\n\n  return (\n    <div className={cn(\"flex items-center gap-3\", className)} {...props}>\n      {children ?? (\n        <>\n          <Badge\n            className=\"gap-1 bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400\"\n            variant=\"secondary\"\n          >\n            <CheckCircle2Icon className=\"size-3\" />\n            {summary.passed} passed\n          </Badge>\n          {summary.failed > 0 && (\n            <Badge\n              className=\"gap-1 bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400\"\n              variant=\"secondary\"\n            >\n              <XCircleIcon className=\"size-3\" />\n              {summary.failed} failed\n            </Badge>\n          )}\n          {summary.skipped > 0 && (\n            <Badge\n              className=\"gap-1 bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400\"\n              variant=\"secondary\"\n            >\n              <CircleIcon className=\"size-3\" />\n              {summary.skipped} skipped\n            </Badge>\n          )}\n        </>\n      )}\n    </div>\n  );\n};\n\nexport type TestResultsProps = HTMLAttributes<HTMLDivElement> & {\n  summary?: TestResultsSummary;\n};\n\nexport const TestResults = ({\n  summary,\n  className,\n  children,\n  ...props\n}: TestResultsProps) => {\n  const contextValue = useMemo(() => ({ summary }), [summary]);\n\n  return (\n    <TestResultsContext.Provider value={contextValue}>\n      <div\n        className={cn(\"rounded-lg border bg-background\", className)}\n        {...props}\n      >\n        {children ??\n          (summary && (\n            <TestResultsHeader>\n              <TestResultsSummary />\n              <TestResultsDuration />\n            </TestResultsHeader>\n          ))}\n      </div>\n    </TestResultsContext.Provider>\n  );\n};\n\nexport type TestResultsProgressProps = HTMLAttributes<HTMLDivElement>;\n\nexport const TestResultsProgress = ({\n  className,\n  children,\n  ...props\n}: TestResultsProgressProps) => {\n  const { summary } = useContext(TestResultsContext);\n\n  if (!summary) {\n    return null;\n  }\n\n  const passedPercent = (summary.passed / summary.total) * 100;\n  const failedPercent = (summary.failed / summary.total) * 100;\n\n  return (\n    <div className={cn(\"space-y-2\", className)} {...props}>\n      {children ?? (\n        <>\n          <div className=\"flex h-2 overflow-hidden rounded-full bg-muted\">\n            <div\n              className=\"bg-green-500 transition-all\"\n              style={{ width: `${passedPercent}%` }}\n            />\n            <div\n              className=\"bg-red-500 transition-all\"\n              style={{ width: `${failedPercent}%` }}\n            />\n          </div>\n          <div className=\"flex justify-between text-muted-foreground text-xs\">\n            <span>\n              {summary.passed}/{summary.total} tests passed\n            </span>\n            <span>{passedPercent.toFixed(0)}%</span>\n          </div>\n        </>\n      )}\n    </div>\n  );\n};\n\nexport type TestResultsContentProps = HTMLAttributes<HTMLDivElement>;\n\nexport const TestResultsContent = ({\n  className,\n  children,\n  ...props\n}: TestResultsContentProps) => (\n  <div className={cn(\"space-y-2 p-4\", className)} {...props}>\n    {children}\n  </div>\n);\n\ninterface TestSuiteContextType {\n  name: string;\n  status: TestStatus;\n}\n\nconst TestSuiteContext = createContext<TestSuiteContextType>({\n  name: \"\",\n  status: \"passed\",\n});\n\nconst statusStyles: Record<TestStatus, string> = {\n  failed: \"text-red-600 dark:text-red-400\",\n  passed: \"text-green-600 dark:text-green-400\",\n  running: \"text-blue-600 dark:text-blue-400\",\n  skipped: \"text-yellow-600 dark:text-yellow-400\",\n};\n\nconst statusIcons: Record<TestStatus, React.ReactNode> = {\n  failed: <XCircleIcon className=\"size-4\" />,\n  passed: <CheckCircle2Icon className=\"size-4\" />,\n  running: <CircleDotIcon className=\"size-4 animate-pulse\" />,\n  skipped: <CircleIcon className=\"size-4\" />,\n};\n\nconst TestStatusIcon = ({ status }: { status: TestStatus }) => (\n  <span className={cn(\"shrink-0\", statusStyles[status])}>\n    {statusIcons[status]}\n  </span>\n);\n\nexport type TestSuiteProps = ComponentProps<typeof Collapsible> & {\n  name: string;\n  status: TestStatus;\n};\n\nexport const TestSuite = ({\n  name,\n  status,\n  className,\n  children,\n  ...props\n}: TestSuiteProps) => {\n  const contextValue = useMemo(() => ({ name, status }), [name, status]);\n\n  return (\n    <TestSuiteContext.Provider value={contextValue}>\n      <Collapsible className={cn(\"rounded-lg border\", className)} {...props}>\n        {children}\n      </Collapsible>\n    </TestSuiteContext.Provider>\n  );\n};\n\nexport type TestSuiteNameProps = ComponentProps<typeof CollapsibleTrigger>;\n\nexport const TestSuiteName = ({\n  className,\n  children,\n  ...props\n}: TestSuiteNameProps) => {\n  const { name, status } = useContext(TestSuiteContext);\n\n  return (\n    <CollapsibleTrigger\n      className={cn(\n        \"group flex w-full items-center gap-2 px-4 py-3 text-left transition-colors hover:bg-muted/50\",\n        className\n      )}\n      {...props}\n    >\n      <ChevronRightIcon className=\"size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90\" />\n      <TestStatusIcon status={status} />\n      <span className=\"font-medium text-sm\">{children ?? name}</span>\n    </CollapsibleTrigger>\n  );\n};\n\nexport type TestSuiteStatsProps = HTMLAttributes<HTMLDivElement> & {\n  passed?: number;\n  failed?: number;\n  skipped?: number;\n};\n\nexport const TestSuiteStats = ({\n  passed = 0,\n  failed = 0,\n  skipped = 0,\n  className,\n  children,\n  ...props\n}: TestSuiteStatsProps) => (\n  <div\n    className={cn(\"ml-auto flex items-center gap-2 text-xs\", className)}\n    {...props}\n  >\n    {children ?? (\n      <>\n        {passed > 0 && (\n          <span className=\"text-green-600 dark:text-green-400\">\n            {passed} passed\n          </span>\n        )}\n        {failed > 0 && (\n          <span className=\"text-red-600 dark:text-red-400\">\n            {failed} failed\n          </span>\n        )}\n        {skipped > 0 && (\n          <span className=\"text-yellow-600 dark:text-yellow-400\">\n            {skipped} skipped\n          </span>\n        )}\n      </>\n    )}\n  </div>\n);\n\nexport type TestSuiteContentProps = ComponentProps<typeof CollapsibleContent>;\n\nexport const TestSuiteContent = ({\n  className,\n  children,\n  ...props\n}: TestSuiteContentProps) => (\n  <CollapsibleContent className={cn(\"border-t\", className)} {...props}>\n    <div className=\"divide-y\">{children}</div>\n  </CollapsibleContent>\n);\n\ninterface TestContextType {\n  name: string;\n  status: TestStatus;\n  duration?: number;\n}\n\nconst TestContext = createContext<TestContextType>({\n  name: \"\",\n  status: \"passed\",\n});\n\nexport type TestNameProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const TestName = ({ className, children, ...props }: TestNameProps) => {\n  const { name } = useContext(TestContext);\n\n  return (\n    <span className={cn(\"flex-1\", className)} {...props}>\n      {children ?? name}\n    </span>\n  );\n};\n\nexport type TestDurationProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const TestDuration = ({\n  className,\n  children,\n  ...props\n}: TestDurationProps) => {\n  const { duration } = useContext(TestContext);\n\n  if (duration === undefined) {\n    return null;\n  }\n\n  return (\n    <span\n      className={cn(\"ml-auto text-muted-foreground text-xs\", className)}\n      {...props}\n    >\n      {children ?? `${duration}ms`}\n    </span>\n  );\n};\n\nexport type TestStatusProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const TestStatus = ({\n  className,\n  children,\n  ...props\n}: TestStatusProps) => {\n  const { status } = useContext(TestContext);\n\n  return (\n    <span\n      className={cn(\"shrink-0\", statusStyles[status], className)}\n      {...props}\n    >\n      {children ?? statusIcons[status]}\n    </span>\n  );\n};\n\nexport type TestProps = HTMLAttributes<HTMLDivElement> & {\n  name: string;\n  status: TestStatus;\n  duration?: number;\n};\n\nexport const Test = ({\n  name,\n  status,\n  duration,\n  className,\n  children,\n  ...props\n}: TestProps) => {\n  const contextValue = useMemo(\n    () => ({ duration, name, status }),\n    [duration, name, status]\n  );\n\n  return (\n    <TestContext.Provider value={contextValue}>\n      <div\n        className={cn(\"flex items-center gap-2 px-4 py-2 text-sm\", className)}\n        {...props}\n      >\n        {children ?? (\n          <>\n            <TestStatus />\n            <TestName />\n            {duration !== undefined && <TestDuration />}\n          </>\n        )}\n      </div>\n    </TestContext.Provider>\n  );\n};\n\nexport type TestErrorProps = HTMLAttributes<HTMLDivElement>;\n\nexport const TestError = ({\n  className,\n  children,\n  ...props\n}: TestErrorProps) => (\n  <div\n    className={cn(\n      \"mt-2 rounded-md bg-red-50 p-3 dark:bg-red-900/20\",\n      className\n    )}\n    {...props}\n  >\n    {children}\n  </div>\n);\n\nexport type TestErrorMessageProps = HTMLAttributes<HTMLParagraphElement>;\n\nexport const TestErrorMessage = ({\n  className,\n  children,\n  ...props\n}: TestErrorMessageProps) => (\n  <p\n    className={cn(\n      \"font-medium text-red-700 text-sm dark:text-red-400\",\n      className\n    )}\n    {...props}\n  >\n    {children}\n  </p>\n);\n\nexport type TestErrorStackProps = HTMLAttributes<HTMLPreElement>;\n\nexport const TestErrorStack = ({\n  className,\n  children,\n  ...props\n}: TestErrorStackProps) => (\n  <pre\n    className={cn(\n      \"mt-2 overflow-auto font-mono text-red-600 text-xs dark:text-red-400\",\n      className\n    )}\n    {...props}\n  >\n    {children}\n  </pre>\n);\n",
      "type": "registry:ui",
      "target": "components/ai/test-results.tsx"
    }
  ],
  "type": "registry:ui"
}