You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
3.0 KiB
TypeScript
109 lines
3.0 KiB
TypeScript
// frontend/tests/tasks/tree.test.ts
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
buildIndex,
|
|
dueLabel,
|
|
editTree,
|
|
findPath,
|
|
isSoon,
|
|
pct,
|
|
stat,
|
|
} from "@/lib/tasks/tree";
|
|
import type { Folder, Task } from "@/lib/types";
|
|
|
|
function t(id: string, status: Task["status"], children: Task[] = [], due: string | null = null): Task {
|
|
return {
|
|
id,
|
|
project_id: "biz-report",
|
|
parent_id: null,
|
|
title: id,
|
|
status,
|
|
assignee_id: "jiwoo",
|
|
due,
|
|
prio: "보통",
|
|
notes: "",
|
|
est: "",
|
|
delegated: false,
|
|
sort_order: 0,
|
|
created_at: "",
|
|
updated_at: "",
|
|
comments: [],
|
|
children,
|
|
};
|
|
}
|
|
|
|
describe("tree utils", () => {
|
|
it("findPath 무한 중첩 경로", () => {
|
|
const tree = [t("k1", "doing", [t("kx7", "doing", [t("kx9", "todo")])])];
|
|
const p = findPath(tree, "kx9");
|
|
expect(p?.map((n) => n.id)).toEqual(["k1", "kx7", "kx9"]);
|
|
});
|
|
|
|
it("editTree 깊은 노드 갱신 (형제 불변)", () => {
|
|
const tree = [t("k1", "doing", [t("a", "todo"), t("b", "todo")])];
|
|
const next = editTree(tree, "b", (n) => ({ ...n, status: "done" }));
|
|
expect(next[0].children[0].status).toBe("todo"); // a 불변
|
|
expect(next[0].children[1].status).toBe("done"); // b 변경
|
|
});
|
|
|
|
it("stat/pct 진행률", () => {
|
|
const node = t("k", "doing", [t("a", "done"), t("b", "done"), t("c", "todo")]);
|
|
expect(stat(node)).toEqual({ total: 3, done: 2 });
|
|
expect(pct(node)).toBe(67);
|
|
});
|
|
|
|
it("dueLabel ISO → 6/8", () => {
|
|
expect(dueLabel("2026-06-08")).toBe("6/8");
|
|
expect(dueLabel(null)).toBe("—");
|
|
});
|
|
|
|
it("isSoon: due<=8 && !done", () => {
|
|
expect(isSoon(t("a", "todo", [], "2026-06-08"))).toBe(true);
|
|
expect(isSoon(t("a", "done", [], "2026-06-08"))).toBe(false);
|
|
expect(isSoon(t("a", "todo", [], "2026-06-20"))).toBe(false);
|
|
});
|
|
|
|
it("buildIndex isDescendant 필터", () => {
|
|
const folders: Folder[] = [
|
|
{
|
|
id: "work",
|
|
name: "업무",
|
|
tone: "ink",
|
|
icon: "folder",
|
|
sort_order: 0,
|
|
is_system: true,
|
|
projects: [
|
|
{
|
|
id: "biz",
|
|
folder_id: "work",
|
|
parent_id: null,
|
|
name: "경영",
|
|
tone: "coral",
|
|
sort_order: 0,
|
|
pinned: false,
|
|
task_count: 0,
|
|
children: [
|
|
{
|
|
id: "biz-report",
|
|
folder_id: "work",
|
|
parent_id: "biz",
|
|
name: "리포트",
|
|
tone: "coral",
|
|
sort_order: 0,
|
|
pinned: false,
|
|
task_count: 0,
|
|
children: [],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
];
|
|
const ix = buildIndex(folders);
|
|
expect(ix.isDescendant("biz-report", "work")).toBe(true);
|
|
expect(ix.isDescendant("biz-report", "biz")).toBe(true);
|
|
expect(ix.isDescendant("biz", "biz-report")).toBe(false);
|
|
expect(ix.pathOf("biz-report").map((r) => r.id)).toEqual(["work", "biz", "biz-report"]);
|
|
});
|
|
});
|