import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { BrowserRouter } from 'react-router-dom'; import { AutomationDashboardPage } from '../AutomationDashboard'; // Helper to create a mock mutation result const mockMutation = (overrides = {}) => ({ mutateAsync: vi.fn().mockResolvedValue({}), isPending: false, isError: false, error: null, data: undefined, ...overrides, }); // Mock the API hooks vi.mock('@/api/automation', () => ({ useAutomations: vi.fn(), useCreateAutomation: vi.fn(() => mockMutation()), useUpdateAutomation: vi.fn(() => mockMutation()), useDeleteAutomation: vi.fn(() => mockMutation()), useExecuteAutomation: vi.fn(() => mockMutation()), useDryRunAutomation: vi.fn(() => mockMutation()), useAutomationRuns: vi.fn(), useAutomationVersions: vi.fn(), useRestoreAutomationVersion: vi.fn(() => mockMutation()), })); // Mock i18next vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key, i18n: { language: 'en' }, }), })); // Mock toast vi.mock('@/components/ui/Toast', () => ({ useToast: () => ({ toast: { success: vi.fn(), error: vi.fn() }, }), })); // Mock lucide-react icons vi.mock('lucide-react', () => ({ AlertCircle: () =>
, CheckCircle2: () =>
, Clock: () =>
, GitBranch: () =>
, History: () =>
, Loader2: () =>
, Play: () =>
, Plus: () =>
, RotateCcw: () =>
, Settings2: () =>
, Trash2: () =>
, Workflow: () =>
, XCircle: () =>
, Zap: () =>
, })); // Mock Modal component vi.mock('@/components/ui/Modal', () => ({ Modal: ({ open, title, children }: any) => open ?

{title}

{children}
: null, })); // Mock AutomationForm vi.mock('@/components/automation/AutomationForm', () => ({ AutomationForm: () =>
, })); // Mock Skeleton vi.mock('@/components/ui/Skeleton', () => ({ Skeleton: ({ className }: any) =>
, })); // Mock Card vi.mock('@/components/ui/Card', () => ({ Card: ({ children, className }: any) =>
{children}
, })); // Mock EmptyState vi.mock('@/components/ui/EmptyState', () => ({ EmptyState: ({ title, description, icon, action }: any) => (

{title}

{description}

{icon} {action}
), })); // Mock Badge vi.mock('@/components/ui/Badge', () => ({ Badge: ({ children, variant }: any) => {children}, })); const mockAutomations = [ { id: '1', name: 'Test Automation', description: 'A test automation', trigger_type: 'manual', is_active: true, created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', }, { id: '2', name: 'Inactive Automation', description: 'An inactive automation', trigger_type: 'event', is_active: false, created_at: '2024-01-02T00:00:00Z', updated_at: '2024-01-02T00:00:00Z', }, ]; function renderWithProviders(ui: React.ReactElement) { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, }, }); return render( {ui} ); } describe('AutomationDashboard', () => { beforeEach(() => { vi.clearAllMocks(); }); it('renders the automation list', async () => { const { useAutomations } = await import('@/api/automation'); (useAutomations as any).mockReturnValue({ data: mockAutomations, isLoading: false, error: null, }); renderWithProviders(); await waitFor(() => { expect(screen.getByText('Test Automation')).toBeDefined(); expect(screen.getByText('Inactive Automation')).toBeDefined(); }); }); it('shows loading state', async () => { const { useAutomations } = await import('@/api/automation'); (useAutomations as any).mockReturnValue({ data: undefined, isLoading: true, error: null, }); renderWithProviders(); expect(screen.getAllByTestId('skeleton').length).toBe(3); }); it('shows empty state when no automations', async () => { const { useAutomations } = await import('@/api/automation'); (useAutomations as any).mockReturnValue({ data: [], isLoading: false, error: null, }); renderWithProviders(); await waitFor(() => { expect(screen.getByText('automation.noAutomations')).toBeDefined(); }); }); it('opens create form when create button is clicked', async () => { const { useAutomations } = await import('@/api/automation'); (useAutomations as any).mockReturnValue({ data: mockAutomations, isLoading: false, error: null, }); renderWithProviders(); const createButton = screen.getByText('automation.create'); fireEvent.click(createButton); await waitFor(() => { expect(screen.getByTestId('modal')).toBeDefined(); }); }); it('calls execute API when execute button is clicked', async () => { const { useAutomations, useExecuteAutomation } = await import('@/api/automation'); const mockExecute = vi.fn().mockResolvedValue({}); (useAutomations as any).mockReturnValue({ data: mockAutomations, isLoading: false, error: null, }); (useExecuteAutomation as any).mockReturnValue({ mutateAsync: mockExecute, isPending: false, }); renderWithProviders(); // Execute buttons have title="automation.execute" - find by title attribute const executeButtons = screen.getAllByTitle('automation.execute'); expect(executeButtons.length).toBeGreaterThan(0); fireEvent.click(executeButtons[0]); await waitFor(() => { expect(mockExecute).toHaveBeenCalledWith('1'); }); }); });