All checks were successful
ci/woodpecker/push/ci Pipeline was successful
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
125 lines
3.5 KiB
TypeScript
125 lines
3.5 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
import { render, screen, waitFor } from "@testing-library/react";
|
|
import { TaskStatus, TaskPriority, type Task } from "@mosaic/shared";
|
|
import { TasksWidget } from "../TasksWidget";
|
|
import { fetchTasks } from "@/lib/api/tasks";
|
|
|
|
vi.mock("@/lib/api/tasks", () => ({
|
|
fetchTasks: vi.fn(),
|
|
}));
|
|
|
|
const mockTasks: Task[] = [
|
|
{
|
|
id: "task-1",
|
|
title: "API task one",
|
|
description: null,
|
|
status: TaskStatus.IN_PROGRESS,
|
|
priority: TaskPriority.HIGH,
|
|
dueDate: new Date("2026-02-03T09:00:00Z"),
|
|
creatorId: "user-1",
|
|
assigneeId: "user-1",
|
|
workspaceId: "workspace-1",
|
|
projectId: null,
|
|
parentId: null,
|
|
sortOrder: 0,
|
|
metadata: {},
|
|
completedAt: null,
|
|
createdAt: new Date("2026-02-01T09:00:00Z"),
|
|
updatedAt: new Date("2026-02-01T09:00:00Z"),
|
|
},
|
|
{
|
|
id: "task-2",
|
|
title: "API task two",
|
|
description: null,
|
|
status: TaskStatus.NOT_STARTED,
|
|
priority: TaskPriority.MEDIUM,
|
|
dueDate: new Date("2026-02-04T09:00:00Z"),
|
|
creatorId: "user-1",
|
|
assigneeId: "user-1",
|
|
workspaceId: "workspace-1",
|
|
projectId: null,
|
|
parentId: null,
|
|
sortOrder: 1,
|
|
metadata: {},
|
|
completedAt: null,
|
|
createdAt: new Date("2026-02-01T09:00:00Z"),
|
|
updatedAt: new Date("2026-02-01T09:00:00Z"),
|
|
},
|
|
{
|
|
id: "task-3",
|
|
title: "API task three",
|
|
description: null,
|
|
status: TaskStatus.COMPLETED,
|
|
priority: TaskPriority.LOW,
|
|
dueDate: new Date("2026-02-05T09:00:00Z"),
|
|
creatorId: "user-1",
|
|
assigneeId: "user-1",
|
|
workspaceId: "workspace-1",
|
|
projectId: null,
|
|
parentId: null,
|
|
sortOrder: 2,
|
|
metadata: {},
|
|
completedAt: new Date("2026-02-02T09:00:00Z"),
|
|
createdAt: new Date("2026-02-01T09:00:00Z"),
|
|
updatedAt: new Date("2026-02-02T09:00:00Z"),
|
|
},
|
|
];
|
|
|
|
async function finishWidgetLoad(): Promise<void> {
|
|
await waitFor(() => {
|
|
expect(screen.queryByText("Loading tasks...")).not.toBeInTheDocument();
|
|
});
|
|
}
|
|
|
|
describe("TasksWidget", (): void => {
|
|
beforeEach((): void => {
|
|
vi.clearAllMocks();
|
|
vi.mocked(fetchTasks).mockResolvedValue(mockTasks);
|
|
});
|
|
|
|
it("renders loading state initially", (): void => {
|
|
render(<TasksWidget id="tasks-1" />);
|
|
|
|
expect(screen.getByText("Loading tasks...")).toBeInTheDocument();
|
|
});
|
|
|
|
it("fetches tasks and renders summary stats", async (): Promise<void> => {
|
|
render(<TasksWidget id="tasks-1" />);
|
|
|
|
await finishWidgetLoad();
|
|
|
|
expect(fetchTasks).toHaveBeenCalledTimes(1);
|
|
expect(screen.getByText("Total")).toBeInTheDocument();
|
|
expect(screen.getByText("In Progress")).toBeInTheDocument();
|
|
expect(screen.getByText("Done")).toBeInTheDocument();
|
|
expect(screen.getByText("3")).toBeInTheDocument();
|
|
});
|
|
|
|
it("renders task rows from API response", async (): Promise<void> => {
|
|
render(<TasksWidget id="tasks-1" />);
|
|
|
|
await finishWidgetLoad();
|
|
|
|
expect(screen.getByText("API task one")).toBeInTheDocument();
|
|
expect(screen.getByText("API task two")).toBeInTheDocument();
|
|
expect(screen.getByText("API task three")).toBeInTheDocument();
|
|
});
|
|
|
|
it("shows due date labels for each task", async (): Promise<void> => {
|
|
render(<TasksWidget id="tasks-1" />);
|
|
|
|
await finishWidgetLoad();
|
|
|
|
expect(screen.getAllByText(/Due:/).length).toBe(3);
|
|
});
|
|
|
|
it("shows empty state when API returns no tasks", async (): Promise<void> => {
|
|
vi.mocked(fetchTasks).mockResolvedValueOnce([]);
|
|
|
|
render(<TasksWidget id="tasks-1" />);
|
|
await finishWidgetLoad();
|
|
|
|
expect(screen.getByText("No tasks yet")).toBeInTheDocument();
|
|
});
|
|
});
|