/** * TaskProgressWidget Component Tests */ import { describe, it, expect, vi, beforeEach } from "vitest"; import { render, screen, waitFor } from "@testing-library/react"; import { TaskProgressWidget } from "../TaskProgressWidget"; const mockFetch = vi.fn(); global.fetch = mockFetch as unknown as typeof fetch; describe("TaskProgressWidget", (): void => { beforeEach((): void => { vi.clearAllMocks(); }); it("should render loading state initially", (): void => { mockFetch.mockImplementation( () => new Promise(() => { // Never-resolving promise for loading state }) ); render(); expect(screen.getByText(/loading task progress/i)).toBeInTheDocument(); }); it("should display tasks after successful fetch", async (): Promise => { const mockTasks = [ { agentId: "agent-1", taskId: "TASK-001", status: "running", agentType: "worker", spawnedAt: new Date().toISOString(), }, { agentId: "agent-2", taskId: "TASK-002", status: "completed", agentType: "reviewer", spawnedAt: new Date(Date.now() - 3600000).toISOString(), completedAt: new Date().toISOString(), }, ]; mockFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve(mockTasks), } as unknown as Response); render(); await waitFor(() => { expect(screen.getByText("TASK-001")).toBeInTheDocument(); expect(screen.getByText("TASK-002")).toBeInTheDocument(); }); // Check stats expect(screen.getByText("2")).toBeInTheDocument(); // Total }); it("should display error state when fetch fails", async (): Promise => { mockFetch.mockRejectedValueOnce(new Error("Network error")); render(); await waitFor(() => { expect(screen.getByText(/unable to reach orchestrator/i)).toBeInTheDocument(); }); }); it("should display empty state when no tasks", async (): Promise => { mockFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve([]), } as unknown as Response); render(); await waitFor(() => { expect(screen.getByText(/no agent tasks in progress/i)).toBeInTheDocument(); }); }); it("should show agent type badges", async (): Promise => { const mockTasks = [ { agentId: "agent-1", taskId: "TASK-001", status: "running", agentType: "worker", spawnedAt: new Date().toISOString(), }, { agentId: "agent-2", taskId: "TASK-002", status: "running", agentType: "reviewer", spawnedAt: new Date().toISOString(), }, { agentId: "agent-3", taskId: "TASK-003", status: "running", agentType: "tester", spawnedAt: new Date().toISOString(), }, ]; mockFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve(mockTasks), } as unknown as Response); render(); await waitFor(() => { expect(screen.getByText("Worker")).toBeInTheDocument(); expect(screen.getByText("Reviewer")).toBeInTheDocument(); expect(screen.getByText("Tester")).toBeInTheDocument(); }); }); it("should display error message for failed tasks", async (): Promise => { const mockTasks = [ { agentId: "agent-1", taskId: "TASK-FAIL", status: "failed", agentType: "worker", spawnedAt: new Date().toISOString(), error: "Build failed: type errors", }, ]; mockFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve(mockTasks), } as unknown as Response); render(); await waitFor(() => { expect(screen.getByText("Build failed: type errors")).toBeInTheDocument(); }); }); it("should sort active tasks before completed ones", async (): Promise => { const mockTasks = [ { agentId: "agent-completed", taskId: "COMPLETED-TASK", status: "completed", agentType: "worker", spawnedAt: new Date(Date.now() - 7200000).toISOString(), completedAt: new Date().toISOString(), }, { agentId: "agent-running", taskId: "RUNNING-TASK", status: "running", agentType: "worker", spawnedAt: new Date().toISOString(), }, ]; mockFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve(mockTasks), } as unknown as Response); render(); await waitFor(() => { const taskElements = screen.getAllByText(/TASK/); expect(taskElements).toHaveLength(2); // Running task should appear before completed expect(taskElements[0]?.textContent).toBe("RUNNING-TASK"); expect(taskElements[1]?.textContent).toBe("COMPLETED-TASK"); }); }); });