import { useState, useEffect, useCallback } from 'react'; import { Label } from '@/components/ui/label'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import { FlaskConical, Save, RotateCcw, Info } from 'lucide-react'; import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import { getHttpApiClient } from '@/lib/http-api-client'; import { toast } from 'sonner'; import type { Project } from '@/lib/electron'; interface TestingSectionProps { project: Project; } export function TestingSection({ project }: TestingSectionProps) { const [testCommand, setTestCommand] = useState(''); const [originalTestCommand, setOriginalTestCommand] = useState(''); const [isLoading, setIsLoading] = useState(true); const [isSaving, setIsSaving] = useState(false); // Check if there are unsaved changes const hasChanges = testCommand !== originalTestCommand; // Load project settings when project changes useEffect(() => { let isCancelled = false; const currentPath = project.path; const loadProjectSettings = async () => { setIsLoading(true); try { const httpClient = getHttpApiClient(); const response = await httpClient.settings.getProject(currentPath); // Avoid updating state if component unmounted or project changed if (isCancelled) return; if (response.success && response.settings) { const command = response.settings.testCommand || ''; setTestCommand(command); setOriginalTestCommand(command); } } catch (error) { if (!isCancelled) { console.error('Failed to load project settings:', error); } } finally { if (!isCancelled) { setIsLoading(false); } } }; loadProjectSettings(); return () => { isCancelled = true; }; }, [project.path]); // Save test command const handleSave = useCallback(async () => { setIsSaving(true); try { const httpClient = getHttpApiClient(); const normalizedCommand = testCommand.trim(); const response = await httpClient.settings.updateProject(project.path, { testCommand: normalizedCommand || undefined, }); if (response.success) { setTestCommand(normalizedCommand); setOriginalTestCommand(normalizedCommand); toast.success('Test command saved'); } else { toast.error('Failed to save test command', { description: response.error, }); } } catch (error) { console.error('Failed to save test command:', error); toast.error('Failed to save test command'); } finally { setIsSaving(false); } }, [project.path, testCommand]); // Reset to original value const handleReset = useCallback(() => { setTestCommand(originalTestCommand); }, [originalTestCommand]); // Use a preset command const handleUsePreset = useCallback((command: string) => { setTestCommand(command); }, []); return (
Configure how tests are run for this project.
The command to run tests for this project. If not specified, the test runner will auto-detect based on your project structure (package.json, Cargo.toml, go.mod, etc.).
Auto-detection
When no custom command is set, the test runner automatically detects and uses the appropriate test framework based on your project files (Vitest, Jest, Pytest, Cargo, Go Test, etc.).
Click a preset to use it as your test command.