feat: add Temporal-backed TaskTree service
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "bun:test";
|
||||
|
||||
import { createTaskTreeDispatcher } from "./dispatcher.ts";
|
||||
import { createTaskTreeHttpApp } from "./http.ts";
|
||||
import { TaskTreeStore } from "./store.ts";
|
||||
|
||||
test("HTTP command endpoint returns the same dispatcher DTO", async () => {
|
||||
const group = {
|
||||
id: "tg_contract",
|
||||
name: "Contract",
|
||||
description: "",
|
||||
createdAt: "2026-07-16T00:00:00.000Z",
|
||||
updatedAt: "2026-07-16T00:00:00.000Z"
|
||||
};
|
||||
const store = {
|
||||
async listGroups() { return [group]; }
|
||||
};
|
||||
const dispatch = createTaskTreeDispatcher({ store: store as TaskTreeStore });
|
||||
const expected = await dispatch({ operation: "group.list" });
|
||||
const app = createTaskTreeHttpApp({ dispatch });
|
||||
const response = await app.fetch(new Request("http://tasktree/v1/tasktree/commands", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({ operation: "group.list" })
|
||||
}));
|
||||
|
||||
assert.equal(response.status, 200);
|
||||
assert.deepEqual(await response.json(), expected);
|
||||
});
|
||||
|
||||
test("native PostgreSQL store exposes timeline DTO and rejects a third task level", async () => {
|
||||
const databaseUrl = process.env.TASKTREE_DATABASE_URL;
|
||||
assert.ok(databaseUrl, "TASKTREE_DATABASE_URL is required for the TaskTree store integration test");
|
||||
const store = new TaskTreeStore(databaseUrl);
|
||||
const group = await store.createGroup(`TaskTree test ${Date.now()}`);
|
||||
try {
|
||||
const task = await store.createTask({
|
||||
groupId: group.id,
|
||||
title: "Root task",
|
||||
startAt: "2026-07-16T00:00:00.000Z",
|
||||
dueAt: "2026-07-18T00:00:00.000Z"
|
||||
});
|
||||
const subtask = await store.createTask({ groupId: group.id, parentId: task.id, title: "Subtask" });
|
||||
await store.createMilestone({ groupId: group.id, taskId: task.id, title: "Review", occursAt: "2026-07-17T00:00:00.000Z" });
|
||||
await store.createReport({ taskId: subtask.id, title: "Execution", body: "passed" });
|
||||
|
||||
await assert.rejects(
|
||||
store.createTask({ groupId: group.id, parentId: subtask.id, title: "Unsupported third level" }),
|
||||
(error: any) => error?.code === "maximum_depth_exceeded"
|
||||
);
|
||||
const timeline = await store.timeline(group.id);
|
||||
assert.equal(timeline?.tasks.length, 2);
|
||||
assert.equal(timeline?.tasks[0]?.kind, "task");
|
||||
assert.equal(timeline?.tasks[1]?.kind, "subtask");
|
||||
assert.equal(timeline?.milestones.length, 1);
|
||||
assert.equal(timeline?.reports.length, 1);
|
||||
} finally {
|
||||
await store.deleteGroup(group.id);
|
||||
await store.close();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user