All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Fixes all 542 ESLint problems in the web package to achieve 0 errors and 0 warnings. Changes: - Fixed 144 issues: nullish coalescing, return types, unused variables - Fixed 118 issues: unnecessary conditions, type safety, template literals - Fixed 79 issues: non-null assertions, unsafe assignments, empty functions - Fixed 67 issues: explicit return types, promise handling, enum comparisons - Fixed 45 final warnings: missing return types, optional chains - Fixed 25 typecheck-related issues: async/await, type assertions, formatting - Fixed JSX.Element namespace errors across 90+ files All Quality Rails violations resolved. Lint and typecheck both pass with 0 problems. Files modified: 118 components, tests, hooks, and utilities Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
175 lines
5.8 KiB
TypeScript
175 lines
5.8 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { render, screen } from "@testing-library/react";
|
|
import { TaskList } from "./TaskList";
|
|
import { TaskStatus, TaskPriority, type Task } from "@mosaic/shared";
|
|
|
|
describe("TaskList", (): void => {
|
|
const mockTasks: Task[] = [
|
|
{
|
|
id: "task-1",
|
|
title: "Review pull request",
|
|
description: "Review and provide feedback on frontend PR",
|
|
status: TaskStatus.IN_PROGRESS,
|
|
priority: TaskPriority.HIGH,
|
|
dueDate: new Date("2026-01-29"),
|
|
creatorId: "user-1",
|
|
assigneeId: "user-1",
|
|
workspaceId: "workspace-1",
|
|
projectId: null,
|
|
parentId: null,
|
|
sortOrder: 0,
|
|
metadata: {},
|
|
completedAt: null,
|
|
createdAt: new Date("2026-01-28"),
|
|
updatedAt: new Date("2026-01-28"),
|
|
},
|
|
{
|
|
id: "task-2",
|
|
title: "Update documentation",
|
|
description: "Add setup instructions",
|
|
status: TaskStatus.NOT_STARTED,
|
|
priority: TaskPriority.MEDIUM,
|
|
dueDate: new Date("2026-02-05"),
|
|
creatorId: "user-1",
|
|
assigneeId: "user-1",
|
|
workspaceId: "workspace-1",
|
|
projectId: null,
|
|
parentId: null,
|
|
sortOrder: 1,
|
|
metadata: {},
|
|
completedAt: null,
|
|
createdAt: new Date("2026-01-28"),
|
|
updatedAt: new Date("2026-01-28"),
|
|
},
|
|
];
|
|
|
|
it("should render empty state when no tasks", (): void => {
|
|
render(<TaskList tasks={[]} isLoading={false} />);
|
|
expect(screen.getByText(/no tasks scheduled/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it("should render loading state", (): void => {
|
|
render(<TaskList tasks={[]} isLoading={true} />);
|
|
expect(screen.getByText(/loading/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it("should render tasks list", (): void => {
|
|
render(<TaskList tasks={mockTasks} isLoading={false} />);
|
|
expect(screen.getByText("Review pull request")).toBeInTheDocument();
|
|
expect(screen.getByText("Update documentation")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should group tasks by date", (): void => {
|
|
render(<TaskList tasks={mockTasks} isLoading={false} />);
|
|
// Should have date group sections (Today, This Week, etc.)
|
|
// The exact sections depend on the current date, so just verify grouping works
|
|
const sections = screen.getAllByRole("heading", { level: 2 });
|
|
expect(sections.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("should use PDA-friendly language", (): void => {
|
|
render(<TaskList tasks={mockTasks} isLoading={false} />);
|
|
// Should NOT contain demanding language
|
|
const text = screen.getByRole("main").textContent;
|
|
expect(text).not.toMatch(/overdue/i);
|
|
expect(text).not.toMatch(/urgent/i);
|
|
expect(text).not.toMatch(/must do/i);
|
|
});
|
|
|
|
it("should display status indicators", (): void => {
|
|
render(<TaskList tasks={mockTasks} isLoading={false} />);
|
|
// Check for emoji status indicators (rendered as text)
|
|
const listItems = screen.getAllByRole("listitem");
|
|
expect(listItems.length).toBe(mockTasks.length);
|
|
});
|
|
|
|
describe("error states", (): void => {
|
|
it("should handle undefined tasks gracefully", (): void => {
|
|
render(<TaskList tasks={undefined as unknown as Task[]} isLoading={false} />);
|
|
expect(screen.getByText(/no tasks scheduled/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it("should handle null tasks gracefully", (): void => {
|
|
render(<TaskList tasks={null as unknown as Task[]} isLoading={false} />);
|
|
expect(screen.getByText(/no tasks scheduled/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it("should handle tasks with missing required fields", (): void => {
|
|
const firstTask = mockTasks[0];
|
|
if (!firstTask) {
|
|
throw new Error("Mock task not found");
|
|
}
|
|
const malformedTasks: Task[] = [
|
|
{
|
|
...firstTask,
|
|
title: "", // Empty title
|
|
},
|
|
];
|
|
|
|
render(<TaskList tasks={malformedTasks} isLoading={false} />);
|
|
// Component should render without crashing
|
|
expect(screen.getByRole("main")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should handle tasks with invalid dates", (): void => {
|
|
const firstTask = mockTasks[0];
|
|
if (!firstTask) {
|
|
throw new Error("Mock task not found");
|
|
}
|
|
const tasksWithBadDates: Task[] = [
|
|
{
|
|
...firstTask,
|
|
dueDate: new Date("invalid-date"),
|
|
},
|
|
];
|
|
|
|
render(<TaskList tasks={tasksWithBadDates} isLoading={false} />);
|
|
expect(screen.getByRole("main")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should handle extremely large task lists", (): void => {
|
|
const firstTask = mockTasks[0];
|
|
if (!firstTask) {
|
|
throw new Error("Mock task not found");
|
|
}
|
|
const largeTasks: Task[] = Array.from({ length: 1000 }, (_, i) => ({
|
|
...firstTask,
|
|
id: `task-${String(i)}`,
|
|
title: `Task ${String(i)}`,
|
|
}));
|
|
|
|
render(<TaskList tasks={largeTasks} isLoading={false} />);
|
|
expect(screen.getByRole("main")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should handle tasks with very long titles", (): void => {
|
|
const firstTask = mockTasks[0];
|
|
if (!firstTask) {
|
|
throw new Error("Mock task not found");
|
|
}
|
|
const longTitleTask: Task = {
|
|
...firstTask,
|
|
title: "A".repeat(500),
|
|
};
|
|
|
|
render(<TaskList tasks={[longTitleTask]} isLoading={false} />);
|
|
expect(screen.getByText(/A{500}/)).toBeInTheDocument();
|
|
});
|
|
|
|
it("should handle tasks with special characters in title", (): void => {
|
|
const firstTask = mockTasks[0];
|
|
if (!firstTask) {
|
|
throw new Error("Mock task not found");
|
|
}
|
|
const specialCharTask: Task = {
|
|
...firstTask,
|
|
title: '<script>alert("xss")</script>',
|
|
};
|
|
|
|
render(<TaskList tasks={[specialCharTask]} isLoading={false} />);
|
|
// Should render escaped, not execute
|
|
expect(screen.getByRole("main").innerHTML).not.toContain("<script>");
|
|
});
|
|
});
|
|
});
|