"use client"; import { Badge } from "@/components/ui/badge"; import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible"; import { cn } from "@/lib/utils"; import { CheckCircle2Icon, ChevronRightIcon, CircleDotIcon, CircleIcon, XCircleIcon, } from "lucide-react"; import type { ComponentProps, HTMLAttributes } from "react"; import { createContext, useContext, useMemo } from "react"; type TestStatus = "passed" | "failed" | "skipped" | "running"; interface TestResultsSummary { passed: number; failed: number; skipped: number; total: number; duration?: number; } interface TestResultsContextType { summary?: TestResultsSummary; } const TestResultsContext = createContext({}); const formatDuration = (ms: number) => { if (ms < 1000) { return `${ms}ms`; } return `${(ms / 1000).toFixed(2)}s`; }; export type TestResultsHeaderProps = HTMLAttributes; export const TestResultsHeader = ({ className, children, ...props }: TestResultsHeaderProps) => (
{children}
); export type TestResultsDurationProps = HTMLAttributes; export const TestResultsDuration = ({ className, children, ...props }: TestResultsDurationProps) => { const { summary } = useContext(TestResultsContext); if (!summary?.duration) { return null; } return ( {children ?? formatDuration(summary.duration)} ); }; export type TestResultsSummaryProps = HTMLAttributes; export const TestResultsSummary = ({ className, children, ...props }: TestResultsSummaryProps) => { const { summary } = useContext(TestResultsContext); if (!summary) { return null; } return (
{children ?? ( <> {summary.passed} passed {summary.failed > 0 && ( {summary.failed} failed )} {summary.skipped > 0 && ( {summary.skipped} skipped )} )}
); }; export type TestResultsProps = HTMLAttributes & { summary?: TestResultsSummary; }; export const TestResults = ({ summary, className, children, ...props }: TestResultsProps) => { const contextValue = useMemo(() => ({ summary }), [summary]); return (
{children ?? (summary && ( ))}
); }; export type TestResultsProgressProps = HTMLAttributes; export const TestResultsProgress = ({ className, children, ...props }: TestResultsProgressProps) => { const { summary } = useContext(TestResultsContext); if (!summary) { return null; } const passedPercent = (summary.passed / summary.total) * 100; const failedPercent = (summary.failed / summary.total) * 100; return (
{children ?? ( <>
{summary.passed}/{summary.total} tests passed {passedPercent.toFixed(0)}%
)}
); }; export type TestResultsContentProps = HTMLAttributes; export const TestResultsContent = ({ className, children, ...props }: TestResultsContentProps) => (
{children}
); interface TestSuiteContextType { name: string; status: TestStatus; } const TestSuiteContext = createContext({ name: "", status: "passed", }); const statusStyles: Record = { failed: "text-red-600 dark:text-red-400", passed: "text-green-600 dark:text-green-400", running: "text-blue-600 dark:text-blue-400", skipped: "text-yellow-600 dark:text-yellow-400", }; const statusIcons: Record = { failed: , passed: , running: , skipped: , }; const TestStatusIcon = ({ status }: { status: TestStatus }) => ( {statusIcons[status]} ); export type TestSuiteProps = ComponentProps & { name: string; status: TestStatus; }; export const TestSuite = ({ name, status, className, children, ...props }: TestSuiteProps) => { const contextValue = useMemo(() => ({ name, status }), [name, status]); return ( {children} ); }; export type TestSuiteNameProps = ComponentProps; export const TestSuiteName = ({ className, children, ...props }: TestSuiteNameProps) => { const { name, status } = useContext(TestSuiteContext); return ( {children ?? name} ); }; export type TestSuiteStatsProps = HTMLAttributes & { passed?: number; failed?: number; skipped?: number; }; export const TestSuiteStats = ({ passed = 0, failed = 0, skipped = 0, className, children, ...props }: TestSuiteStatsProps) => (
{children ?? ( <> {passed > 0 && ( {passed} passed )} {failed > 0 && ( {failed} failed )} {skipped > 0 && ( {skipped} skipped )} )}
); export type TestSuiteContentProps = ComponentProps; export const TestSuiteContent = ({ className, children, ...props }: TestSuiteContentProps) => (
{children}
); interface TestContextType { name: string; status: TestStatus; duration?: number; } const TestContext = createContext({ name: "", status: "passed", }); export type TestNameProps = HTMLAttributes; export const TestName = ({ className, children, ...props }: TestNameProps) => { const { name } = useContext(TestContext); return ( {children ?? name} ); }; export type TestDurationProps = HTMLAttributes; export const TestDuration = ({ className, children, ...props }: TestDurationProps) => { const { duration } = useContext(TestContext); if (duration === undefined) { return null; } return ( {children ?? `${duration}ms`} ); }; export type TestStatusProps = HTMLAttributes; export const TestStatus = ({ className, children, ...props }: TestStatusProps) => { const { status } = useContext(TestContext); return ( {children ?? statusIcons[status]} ); }; export type TestProps = HTMLAttributes & { name: string; status: TestStatus; duration?: number; }; export const Test = ({ name, status, duration, className, children, ...props }: TestProps) => { const contextValue = useMemo( () => ({ duration, name, status }), [duration, name, status] ); return (
{children ?? ( <> {duration !== undefined && } )}
); }; export type TestErrorProps = HTMLAttributes; export const TestError = ({ className, children, ...props }: TestErrorProps) => (
{children}
); export type TestErrorMessageProps = HTMLAttributes; export const TestErrorMessage = ({ className, children, ...props }: TestErrorMessageProps) => (

{children}

); export type TestErrorStackProps = HTMLAttributes; export const TestErrorStack = ({ className, children, ...props }: TestErrorStackProps) => (
    {children}
  
);