Skip to main content
Glama

Task Trellis MCP

isRequiredForOtherObjects.test.ts11.2 kB
import { TrellisObject, TrellisObjectPriority, TrellisObjectStatus, TrellisObjectType, } from "../../models"; import { Repository } from "../../repositories/Repository"; import { isRequiredForOtherObjects } from "../isRequiredForOtherObjects"; // Mock repository implementation for testing class MockRepository implements Repository { private objects: Map<string, TrellisObject> = new Map(); constructor(objects: TrellisObject[] = []) { objects.forEach((obj) => this.objects.set(obj.id, obj)); } async getObjectById(id: string): Promise<TrellisObject | null> { return Promise.resolve(this.objects.get(id) || null); } async getObjects(_includeClosed?: boolean): Promise<TrellisObject[]> { return Promise.resolve(Array.from(this.objects.values())); } async saveObject(trellisObject: TrellisObject): Promise<void> { this.objects.set(trellisObject.id, trellisObject); return Promise.resolve(); } async deleteObject(id: string): Promise<void> { this.objects.delete(id); return Promise.resolve(); } async getChildrenOf( parentId: string, _includeClosed?: boolean, ): Promise<TrellisObject[]> { const children = Array.from(this.objects.values()).filter( (obj) => obj.parent === parentId, ); return Promise.resolve(children); } } describe("isRequiredForOtherObjects", () => { const createMockObject = ( id: string, status: TrellisObjectStatus, prerequisites: string[] = [], ): TrellisObject => ({ id, title: `Task ${id}`, status, priority: TrellisObjectPriority.MEDIUM, prerequisites, affectedFiles: new Map(), log: [], schema: "v1.0", childrenIds: [], body: `Body for ${id}`, type: TrellisObjectType.TASK, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }); it("should return false when no other objects exist", async () => { const object = createMockObject("task-1", TrellisObjectStatus.OPEN); const repository = new MockRepository([object]); const result = await isRequiredForOtherObjects(object, repository); expect(result).toBe(false); }); it("should return false when no other objects have this object as prerequisite", async () => { const object1 = createMockObject("task-1", TrellisObjectStatus.OPEN); const object2 = createMockObject("task-2", TrellisObjectStatus.OPEN, [ "task-3", ]); const object3 = createMockObject("task-3", TrellisObjectStatus.DONE); const repository = new MockRepository([object1, object2, object3]); const result = await isRequiredForOtherObjects(object1, repository); expect(result).toBe(false); }); it("should return true when an open object has this object as prerequisite", async () => { const prerequisiteObject = createMockObject( "prereq-1", TrellisObjectStatus.DONE, ); const dependentObject = createMockObject( "task-1", TrellisObjectStatus.OPEN, ["prereq-1"], ); const repository = new MockRepository([ prerequisiteObject, dependentObject, ]); const result = await isRequiredForOtherObjects( prerequisiteObject, repository, ); expect(result).toBe(true); }); it("should return true when an in-progress object has this object as prerequisite", async () => { const prerequisiteObject = createMockObject( "prereq-1", TrellisObjectStatus.DONE, ); const dependentObject = createMockObject( "task-1", TrellisObjectStatus.IN_PROGRESS, ["prereq-1"], ); const repository = new MockRepository([ prerequisiteObject, dependentObject, ]); const result = await isRequiredForOtherObjects( prerequisiteObject, repository, ); expect(result).toBe(true); }); it("should return true when a draft object has this object as prerequisite", async () => { const prerequisiteObject = createMockObject( "prereq-1", TrellisObjectStatus.DONE, ); const dependentObject = createMockObject( "task-1", TrellisObjectStatus.DRAFT, ["prereq-1"], ); const repository = new MockRepository([ prerequisiteObject, dependentObject, ]); const result = await isRequiredForOtherObjects( prerequisiteObject, repository, ); expect(result).toBe(true); }); it("should return false when only closed objects have this object as prerequisite", async () => { const prerequisiteObject = createMockObject( "prereq-1", TrellisObjectStatus.DONE, ); const doneObject = createMockObject("task-1", TrellisObjectStatus.DONE, [ "prereq-1", ]); const wontDoObject = createMockObject( "task-2", TrellisObjectStatus.WONT_DO, ["prereq-1"], ); const repository = new MockRepository([ prerequisiteObject, doneObject, wontDoObject, ]); const result = await isRequiredForOtherObjects( prerequisiteObject, repository, ); expect(result).toBe(false); }); it("should return true when mix of closed and non-closed objects have this object as prerequisite", async () => { const prerequisiteObject = createMockObject( "prereq-1", TrellisObjectStatus.DONE, ); const doneObject = createMockObject("task-1", TrellisObjectStatus.DONE, [ "prereq-1", ]); const openObject = createMockObject("task-2", TrellisObjectStatus.OPEN, [ "prereq-1", ]); const repository = new MockRepository([ prerequisiteObject, doneObject, openObject, ]); const result = await isRequiredForOtherObjects( prerequisiteObject, repository, ); expect(result).toBe(true); }); it("should handle multiple objects requiring the same object", async () => { const prerequisiteObject = createMockObject( "prereq-1", TrellisObjectStatus.DONE, ); const openObject1 = createMockObject("task-1", TrellisObjectStatus.OPEN, [ "prereq-1", ]); const openObject2 = createMockObject("task-2", TrellisObjectStatus.OPEN, [ "prereq-1", ]); const repository = new MockRepository([ prerequisiteObject, openObject1, openObject2, ]); const result = await isRequiredForOtherObjects( prerequisiteObject, repository, ); expect(result).toBe(true); }); it("should handle objects with multiple prerequisites where target is one of them", async () => { const prerequisiteObject = createMockObject( "prereq-1", TrellisObjectStatus.DONE, ); const otherPrereq = createMockObject("prereq-2", TrellisObjectStatus.DONE); const dependentObject = createMockObject( "task-1", TrellisObjectStatus.OPEN, ["prereq-1", "prereq-2", "prereq-3"], ); const repository = new MockRepository([ prerequisiteObject, otherPrereq, dependentObject, ]); const result = await isRequiredForOtherObjects( prerequisiteObject, repository, ); expect(result).toBe(true); }); it("should not consider the object itself as a dependent", async () => { const object = createMockObject("task-1", TrellisObjectStatus.OPEN, [ "task-1", ]); // Self-referencing prerequisites (edge case) const repository = new MockRepository([object]); const result = await isRequiredForOtherObjects(object, repository); expect(result).toBe(false); }); it("should handle empty repository", async () => { const object = createMockObject("task-1", TrellisObjectStatus.OPEN); const repository = new MockRepository([]); const result = await isRequiredForOtherObjects(object, repository); expect(result).toBe(false); }); it("should work with different object types", async () => { const prerequisiteProject = { ...createMockObject("proj-1", TrellisObjectStatus.DONE), type: TrellisObjectType.PROJECT, }; const dependentEpic = { ...createMockObject("epic-1", TrellisObjectStatus.OPEN, ["proj-1"]), type: TrellisObjectType.EPIC, }; const repository = new MockRepository([prerequisiteProject, dependentEpic]); const result = await isRequiredForOtherObjects( prerequisiteProject, repository, ); expect(result).toBe(true); }); it("should handle repository errors gracefully", async () => { const object = createMockObject("task-1", TrellisObjectStatus.OPEN); // Mock repository that throws an error const mockRepository = { getObjectById: jest.fn(), getObjects: jest.fn().mockRejectedValue(new Error("Repository error")), saveObject: jest.fn(), deleteObject: jest.fn(), getChildrenOf: jest.fn(), }; await expect( isRequiredForOtherObjects(object, mockRepository), ).rejects.toThrow("Repository error"); }); it("should work regardless of the target object's status", async () => { const prerequisiteObject = createMockObject( "prereq-1", TrellisObjectStatus.OPEN, // Target object is open ); const dependentObject = createMockObject( "task-1", TrellisObjectStatus.IN_PROGRESS, ["prereq-1"], ); const repository = new MockRepository([ prerequisiteObject, dependentObject, ]); const result = await isRequiredForOtherObjects( prerequisiteObject, repository, ); expect(result).toBe(true); }); it("should handle complex scenario with multiple objects and statuses", async () => { const prereq1 = createMockObject("prereq-1", TrellisObjectStatus.DONE); const prereq2 = createMockObject("prereq-2", TrellisObjectStatus.OPEN); // Objects that depend on prereq-1 const doneTask = createMockObject("task-1", TrellisObjectStatus.DONE, [ "prereq-1", ]); const wontDoTask = createMockObject("task-2", TrellisObjectStatus.WONT_DO, [ "prereq-1", ]); const openTask = createMockObject("task-3", TrellisObjectStatus.OPEN, [ "prereq-1", ]); // Object that depends on prereq-2 const inProgressTask = createMockObject( "task-4", TrellisObjectStatus.IN_PROGRESS, ["prereq-2"], ); // Object with no dependencies const independentTask = createMockObject( "task-5", TrellisObjectStatus.OPEN, ); const repository = new MockRepository([ prereq1, prereq2, doneTask, wontDoTask, openTask, inProgressTask, independentTask, ]); // prereq-1 should be required because openTask depends on it and is not closed const result1 = await isRequiredForOtherObjects(prereq1, repository); expect(result1).toBe(true); // prereq-2 should be required because inProgressTask depends on it and is not closed const result2 = await isRequiredForOtherObjects(prereq2, repository); expect(result2).toBe(true); // independentTask should not be required by anyone const result3 = await isRequiredForOtherObjects( independentTask, repository, ); expect(result3).toBe(false); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/langadventurellc/task-trellis-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server