import { describe, it, expect, vi, beforeEach } from 'vitest' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import InstanceCard from '@/components/InstanceCard' import type { Instance } from '@/types/instance' // Mock the health hook since we're not testing health logic here vi.mock('@/hooks/useInstanceHealth', () => ({ useInstanceHealth: vi.fn(() => ({ status: 'ok', lastChecked: new Date() })) })) describe('InstanceCard - Instance Actions and State', () => { const mockStartInstance = vi.fn() const mockStopInstance = vi.fn() const mockDeleteInstance = vi.fn() const mockEditInstance = vi.fn() const stoppedInstance: Instance = { name: 'test-instance', running: false, options: { model: 'test-model.gguf' } } const runningInstance: Instance = { name: 'running-instance', running: true, options: { model: 'running-model.gguf' } } beforeEach(() => { vi.clearAllMocks() }) describe('Instance Action Buttons', () => { it('calls startInstance when start button clicked on stopped instance', async () => { const user = userEvent.setup() render( ) const startButton = screen.getByTitle('Start instance') expect(startButton).not.toBeDisabled() await user.click(startButton) expect(mockStartInstance).toHaveBeenCalledWith('test-instance') }) it('calls stopInstance when stop button clicked on running instance', async () => { const user = userEvent.setup() render( ) const stopButton = screen.getByTitle('Stop instance') expect(stopButton).not.toBeDisabled() await user.click(stopButton) expect(mockStopInstance).toHaveBeenCalledWith('running-instance') }) it('calls editInstance when edit button clicked', async () => { const user = userEvent.setup() render( ) const editButton = screen.getByTitle('Edit instance') await user.click(editButton) expect(mockEditInstance).toHaveBeenCalledWith(stoppedInstance) }) it('opens logs modal when logs button clicked', async () => { const user = userEvent.setup() render( ) const logsButton = screen.getByTitle('View logs') await user.click(logsButton) // Should open logs modal (we can verify this by checking if modal title appears) expect(screen.getByText(`Logs: ${stoppedInstance.name}`)).toBeInTheDocument() }) }) describe('Delete Confirmation Logic', () => { it('shows confirmation dialog and calls deleteInstance when confirmed', async () => { const user = userEvent.setup() const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(true) render( ) const deleteButton = screen.getByTitle('Delete instance') await user.click(deleteButton) expect(confirmSpy).toHaveBeenCalledWith('Are you sure you want to delete instance "test-instance"?') expect(mockDeleteInstance).toHaveBeenCalledWith('test-instance') confirmSpy.mockRestore() }) it('does not call deleteInstance when confirmation cancelled', async () => { const user = userEvent.setup() const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(false) render( ) const deleteButton = screen.getByTitle('Delete instance') await user.click(deleteButton) expect(confirmSpy).toHaveBeenCalled() expect(mockDeleteInstance).not.toHaveBeenCalled() confirmSpy.mockRestore() }) }) describe('Button State Based on Instance Status', () => { it('disables start button and enables stop button for running instance', () => { render( ) expect(screen.getByTitle('Start instance')).toBeDisabled() expect(screen.getByTitle('Stop instance')).not.toBeDisabled() expect(screen.getByTitle('Delete instance')).toBeDisabled() // Can't delete running instance }) it('enables start button and disables stop button for stopped instance', () => { render( ) expect(screen.getByTitle('Start instance')).not.toBeDisabled() expect(screen.getByTitle('Stop instance')).toBeDisabled() expect(screen.getByTitle('Delete instance')).not.toBeDisabled() // Can delete stopped instance }) it('edit and logs buttons are always enabled', () => { render( ) expect(screen.getByTitle('Edit instance')).not.toBeDisabled() expect(screen.getByTitle('View logs')).not.toBeDisabled() }) }) describe('Instance Information Display', () => { it('displays instance name correctly', () => { render( ) expect(screen.getByText('test-instance')).toBeInTheDocument() }) it('shows health badge for running instances', () => { render( ) // Health badge should be present for running instances // The exact text depends on the health status from the mock expect(screen.getByText('Ready')).toBeInTheDocument() }) it('does not show health badge for stopped instances', () => { render( ) // Health badge should not be present for stopped instances expect(screen.queryByText('Ready')).not.toBeInTheDocument() }) }) describe('Integration with LogsModal', () => { it('passes correct props to LogsModal', async () => { const user = userEvent.setup() render( ) // Open logs modal await user.click(screen.getByTitle('View logs')) // Verify modal opened with correct instance data expect(screen.getByText('Logs: running-instance')).toBeInTheDocument() // Close modal to test close functionality const closeButtons = screen.getAllByText('Close') const modalCloseButton = closeButtons.find(button => button.closest('[data-slot="dialog-content"]') ) expect(modalCloseButton).toBeTruthy() await user.click(modalCloseButton!) // Modal should close expect(screen.queryByText('Logs: running-instance')).not.toBeInTheDocument() }) }) describe('Error Edge Cases', () => { it('handles instance with minimal data', () => { const minimalInstance: Instance = { name: 'minimal', running: false, options: {} } render( ) // Should still render basic structure expect(screen.getByText('minimal')).toBeInTheDocument() expect(screen.getByTitle('Start instance')).toBeInTheDocument() }) it('handles instance with undefined options', () => { const instanceWithoutOptions: Instance = { name: 'no-options', running: true, options: undefined } render( ) // Should still work expect(screen.getByText('no-options')).toBeInTheDocument() expect(screen.getByTitle('Stop instance')).not.toBeDisabled() }) }) })