test: add edge case tests

This commit is contained in:
2026-07-18 07:13:51 +05:00
parent 3b34171ea0
commit f57b181e99
7 changed files with 177 additions and 0 deletions
+40
View File
@@ -68,4 +68,44 @@ body
if (result.isOk()) return; if (result.isOk()) return;
expect(result.error.variant).toBe(AppErrorVariant.INVALID_TASK_FILE); expect(result.error.variant).toBe(AppErrorVariant.INVALID_TASK_FILE);
}); });
it("handles raw content with fields in different order", () => {
const raw = `---
status: done
id: "should-be-ignored"
title: Reordered
priority: low
tags: [x, y]
assignee: ""
created: 2099-01-01T00:00:00.000Z
updated: 2026-01-02T00:00:00.000Z
---
body text
`;
const result = applyRawTaskContent(raw, previous);
expect(result.isOk()).toBe(true);
if (result.isErr()) return;
expect(result.value.title).toBe("Reordered");
expect(result.value.id).toBe(previous.id);
expect(result.value.created).toBe(previous.created);
expect(result.value.status).toBe(TaskStatus.DONE);
});
it("handles raw content with empty description body", () => {
const raw = `---
id: "x"
title: No body
status: todo
priority: medium
tags: []
assignee: ""
created: 2026-01-01T00:00:00.000Z
updated: 2026-01-01T00:00:00.000Z
---
`;
const result = applyRawTaskContent(raw, previous);
expect(result.isOk()).toBe(true);
if (result.isErr()) return;
expect(result.value.description).toBe("");
});
}); });
+7
View File
@@ -80,4 +80,11 @@ describe("buildDashboardView", () => {
const view = buildDashboardView(tasks, { selectedId: "missing" }); const view = buildDashboardView(tasks, { selectedId: "missing" });
expect(view.selected).toBeUndefined(); expect(view.selected).toBeUndefined();
}); });
it("handles empty tasks array", () => {
const view = buildDashboardView([]);
expect(view.visibleTasks).toEqual([]);
expect(view.groups).toEqual([]);
expect(view.selected).toBeUndefined();
});
}); });
+5
View File
@@ -98,4 +98,9 @@ describe("filterTasks", () => {
}); });
expect(result.map((t) => t.id)).toEqual(["4"]); expect(result.map((t) => t.id)).toEqual(["4"]);
}); });
it("returns empty array for empty input", () => {
expect(filterTasks([], {})).toEqual([]);
expect(filterTasks([], { statuses: ["todo"] })).toEqual([]);
});
}); });
+26
View File
@@ -93,4 +93,30 @@ describe("groupTasks", () => {
expect(groupTasks([], GroupBy.STATUS)).toEqual([]); expect(groupTasks([], GroupBy.STATUS)).toEqual([]);
expect(groupTasks([], GroupBy.NONE)).toEqual([]); expect(groupTasks([], GroupBy.NONE)).toEqual([]);
}); });
it("silently drops tasks with unknown status from groups", () => {
const tasks: Task[] = [
task({ id: "a", title: "A", status: "__garbage__" as TaskStatus }),
task({ id: "b", title: "B", status: TaskStatus.TODO }),
];
const groups = groupTasks(tasks, GroupBy.STATUS);
const allGrouped = groups.flatMap((g) => g.tasks.map((t) => t.id));
expect(allGrouped).toEqual(["b"]);
expect(allGrouped).not.toContain("a");
});
it("silently drops tasks with unknown priority from groups", () => {
const tasks: Task[] = [
task({
id: "a",
title: "A",
priority: "__garbage__" as TaskPriority,
}),
task({ id: "b", title: "B", priority: TaskPriority.LOW }),
];
const groups = groupTasks(tasks, GroupBy.PRIORITY);
const allGrouped = groups.flatMap((g) => g.tasks.map((t) => t.id));
expect(allGrouped).toEqual(["b"]);
expect(allGrouped).not.toContain("a");
});
}); });
+24
View File
@@ -61,4 +61,28 @@ describe("sortTasks", () => {
sortTasks(tasks, TaskSortDirection.DESC); sortTasks(tasks, TaskSortDirection.DESC);
expect(tasks.map((t) => t.id)).toEqual(copy.map((t) => t.id)); expect(tasks.map((t) => t.id)).toEqual(copy.map((t) => t.id));
}); });
it("returns empty array for empty input", () => {
expect(sortTasks([])).toEqual([]);
});
it("preserves input order when created dates are identical (stable sort)", () => {
const sameDate = "2026-01-01T00:00:00.000Z";
const tasks: Task[] = [
task({ id: "a", title: "A", created: sameDate }),
task({ id: "b", title: "B", created: sameDate }),
task({ id: "c", title: "C", created: sameDate }),
];
const result = sortTasks(tasks, TaskSortDirection.ASC);
expect(result.map((t) => t.id)).toEqual(["a", "b", "c"]);
});
it("handles invalid date strings without crashing", () => {
const tasks: Task[] = [
task({ id: "a", title: "A", created: "invalid-date" }),
task({ id: "b", title: "B", created: "2026-01-01T00:00:00.000Z" }),
];
const result = sortTasks(tasks, TaskSortDirection.ASC);
expect(result).toHaveLength(2);
});
}); });
+27
View File
@@ -117,4 +117,31 @@ describe("buildKanbanBoard", () => {
expect(col.tasks).toEqual([]); 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"]);
});
}); });
+48
View File
@@ -195,4 +195,52 @@ describe("FsTaskRepository", () => {
expect(tasks[0].id).not.toBe(first.id); expect(tasks[0].id).not.toBe(first.id);
expect(tasks[0].description).toBe("second"); expect(tasks[0].description).toBe("second");
}); });
it("creates task with Cyrillic title and slug", async () => {
const task = await repo.create(folder, {
...sampleTask,
title: "Тестовая задача",
});
expect(task.title).toBe("Тестовая задача");
const files = await fs.readdir(folder);
expect(files).toEqual([`тестовая-задача${TASK_FILE_EXTENSION}`]);
});
it("creates task with title exactly at MAX_TASK_TITLE_LENGTH", async () => {
const title = "a".repeat(80);
const task = await repo.create(folder, { ...sampleTask, title });
expect(task.title).toBe(title);
const files = await fs.readdir(folder);
expect(files).toEqual([`${title}${TASK_FILE_EXTENSION}`]);
const found = await repo.getById(folder, task.id);
expect(found?.title).toBe(title);
});
it("creates task with tags containing special characters", async () => {
const task = await repo.create(folder, {
...sampleTask,
tags: ["c#", "c++", "tag name", "tag:value"],
});
const files = await fs.readdir(folder);
expect(files).toHaveLength(1);
const content = await fs.readFile(
`${folder}/fix-login-bug${TASK_FILE_EXTENSION}`,
);
expect(content).toContain("c#");
expect(content).toContain("tag:value");
});
it("getFilePath produces consistent slug regardless of special characters", async () => {
const task = await repo.create(folder, {
...sampleTask,
title: "Fix___bug...",
});
const files = await fs.readdir(folder);
expect(files).toEqual([`fix-bug${TASK_FILE_EXTENSION}`]);
});
}); });