/**
* 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");
});
});
});