148 lines
3.9 KiB
TypeScript
148 lines
3.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { Task } from "@/model/task";
|
|
import {
|
|
TASK_STATUS_META,
|
|
TASK_STATUS_ORDER,
|
|
TaskStatus,
|
|
} from "@/model/taskStatus";
|
|
import { buildKanbanBoard } from "./buildKanbanBoard";
|
|
|
|
function task(partial: Partial<Task> & Pick<Task, "id" | "title">): Task {
|
|
return {
|
|
description: "",
|
|
status: TaskStatus.TODO,
|
|
priority: "medium",
|
|
tags: [],
|
|
assignee: "",
|
|
created: "2026-01-01T00:00:00.000Z",
|
|
updated: "2026-01-01T00:00:00.000Z",
|
|
...partial,
|
|
};
|
|
}
|
|
|
|
const visibleStatuses = TASK_STATUS_ORDER.filter(
|
|
(status) => !TASK_STATUS_META[status].defaultHidden,
|
|
);
|
|
|
|
describe("buildKanbanBoard", () => {
|
|
const tasks: Task[] = [
|
|
task({
|
|
id: "a",
|
|
title: "Done one",
|
|
status: TaskStatus.DONE,
|
|
updated: "2026-01-01T00:00:02.000Z",
|
|
}),
|
|
task({
|
|
id: "b",
|
|
title: "Todo older",
|
|
status: TaskStatus.TODO,
|
|
updated: "2026-01-01T00:00:01.000Z",
|
|
}),
|
|
task({
|
|
id: "c",
|
|
title: "Todo newer",
|
|
status: TaskStatus.TODO,
|
|
updated: "2026-01-01T00:00:03.000Z",
|
|
}),
|
|
task({
|
|
id: "d",
|
|
title: "In progress",
|
|
status: TaskStatus.IN_PROGRESS,
|
|
updated: "2026-01-01T00:00:04.000Z",
|
|
}),
|
|
task({
|
|
id: "e",
|
|
title: "Backlog item",
|
|
status: TaskStatus.BACKLOG,
|
|
updated: "2026-01-01T00:00:00.000Z",
|
|
}),
|
|
task({
|
|
id: "f",
|
|
title: "Cancelled",
|
|
status: TaskStatus.CANCELLED,
|
|
updated: "2026-01-01T00:00:05.000Z",
|
|
}),
|
|
];
|
|
|
|
it("hides defaultHidden statuses by default", () => {
|
|
const board = buildKanbanBoard(tasks);
|
|
const statuses = board.columns.map((col) => col.status);
|
|
|
|
expect(statuses).toEqual(visibleStatuses);
|
|
for (const col of board.columns) {
|
|
expect(TASK_STATUS_META[col.status].defaultHidden).toBe(false);
|
|
expect(col.label).toBe(TASK_STATUS_META[col.status].label);
|
|
}
|
|
});
|
|
|
|
it("includes all statuses when showHiddenStatuses is true", () => {
|
|
const board = buildKanbanBoard(tasks, { showHiddenStatuses: true });
|
|
|
|
expect(board.columns.map((col) => col.status)).toEqual(TASK_STATUS_ORDER);
|
|
for (const col of board.columns) {
|
|
expect(col.label).toBe(TASK_STATUS_META[col.status].label);
|
|
}
|
|
});
|
|
|
|
it("places each task into the column matching its status", () => {
|
|
const board = buildKanbanBoard(tasks, { showHiddenStatuses: true });
|
|
|
|
for (const col of board.columns) {
|
|
for (const t of col.tasks) {
|
|
expect(t.status).toBe(col.status);
|
|
}
|
|
}
|
|
|
|
const byStatus = Object.fromEntries(
|
|
board.columns.map((col) => [col.status, col.tasks.map((t) => t.id)]),
|
|
);
|
|
expect(byStatus[TaskStatus.TODO]).toEqual(["c", "b"]);
|
|
expect(byStatus[TaskStatus.IN_PROGRESS]).toEqual(["d"]);
|
|
expect(byStatus[TaskStatus.DONE]).toEqual(["a"]);
|
|
expect(byStatus[TaskStatus.BACKLOG]).toEqual(["e"]);
|
|
expect(byStatus[TaskStatus.CANCELLED]).toEqual(["f"]);
|
|
});
|
|
|
|
it("sorts tasks within a column by updated desc", () => {
|
|
const board = buildKanbanBoard(tasks);
|
|
const todo = board.columns.find((col) => col.status === TaskStatus.TODO);
|
|
expect(todo?.tasks.map((t) => t.id)).toEqual(["c", "b"]);
|
|
});
|
|
|
|
it("returns empty visible columns when there are no tasks", () => {
|
|
const board = buildKanbanBoard([]);
|
|
|
|
expect(board.columns.map((col) => col.status)).toEqual(visibleStatuses);
|
|
for (const col of board.columns) {
|
|
expect(col.tasks).toEqual([]);
|
|
}
|
|
});
|
|
|
|
it("preserves input order for tasks with same updated timestamp (stable sort)", () => {
|
|
const sameUpdated = "2026-01-01T00:00:00.000Z";
|
|
const tasks: Task[] = [
|
|
task({
|
|
id: "a",
|
|
title: "A",
|
|
status: TaskStatus.TODO,
|
|
updated: sameUpdated,
|
|
}),
|
|
task({
|
|
id: "b",
|
|
title: "B",
|
|
status: TaskStatus.TODO,
|
|
updated: sameUpdated,
|
|
}),
|
|
task({
|
|
id: "c",
|
|
title: "C",
|
|
status: TaskStatus.TODO,
|
|
updated: sameUpdated,
|
|
}),
|
|
];
|
|
const board = buildKanbanBoard(tasks);
|
|
const todo = board.columns.find((col) => col.status === TaskStatus.TODO);
|
|
expect(todo?.tasks.map((t) => t.id)).toEqual(["a", "b", "c"]);
|
|
});
|
|
});
|