'use client'; import { useState } from 'react'; import { Play, CheckCircle2, XCircle, Clock, ChevronDown, ChevronUp, AlertTriangle, Loader2, Terminal, FileCode, } from 'lucide-react'; import { clsx } from 'clsx'; import type { TestResult } from '@/types'; interface TestRunnerProps { userCode: string; testCode: string; entryPoint: string; onTestComplete: (result: TestResult) => void; initialResult?: TestResult | null; } export function TestRunner({ userCode, testCode, entryPoint, onTestComplete, initialResult = null, }: TestRunnerProps) { const [isRunning, setIsRunning] = useState(false); const [result, setResult] = useState(initialResult); const [isExpanded, setIsExpanded] = useState(false); const [showTraceback, setShowTraceback] = useState(false); const runTests = async () => { if (isRunning) return; setIsRunning(true); setResult(null); setShowTraceback(false); try { const response = await fetch('/api/test', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userCode, testCode, entryPoint, timeout: 30, }), }); const data = await response.json(); setResult(data); onTestComplete(data); // Auto-expand on failure if (!data.passed) { setIsExpanded(true); } } catch (error) { const errorResult: TestResult = { passed: false, total: 0, failed: 0, details: [], executionTime: 0, error: error instanceof Error ? error.message : 'Failed to run tests', }; setResult(errorResult); onTestComplete(errorResult); setIsExpanded(true); } finally { setIsRunning(false); } }; const hasDetails = result && (result.error || result.details.length > 0 || result.traceback || result.output); const passedCount = result?.details?.filter(t => t.passed).length ?? 0; const totalCount = result?.total ?? result?.details?.length ?? 0; return (
{/* Compact header with Run button and status */}
{result && (
{result.passed ? ( Passed {totalCount > 0 && ( ({passedCount}/{totalCount} tests) )} ) : ( Failed {totalCount > 0 && ( ({passedCount}/{totalCount} tests) )} )} {result.executionTime}ms
)}
{result && ( )}
{/* Expandable details section */} {isExpanded && result && (
{/* Summary for passed tests */} {result.passed && !result.error && (
All {totalCount} test{totalCount !== 1 ? 's' : ''} passed successfully!
)} {/* Main error message */} {result.error && (
                  {result.error}
                
)} {/* Traceback toggle and display */} {result.traceback && result.traceback !== result.error && (
{showTraceback && (
                    {result.traceback}
                  
)}
)} {/* Output display */} {result.output && (
Output
                  {result.output}
                
)} {/* Test details - always show */} {result.details && result.details.length > 0 && (
Test Results:
{result.details.map((test, idx) => (
{test.passed ? ( ) : ( )} {test.name}
{!test.passed && (test.expected || test.actual || test.error) && (
{test.expected && (

Expected: {test.expected}

)} {test.actual && (

Actual: {test.actual}

)} {test.error && !result.error && (

{test.error}

)}
)}
))}
)}
)}
); }