Skip to main content
Glama

Task Trellis MCP

updateParentHierarchy.test.ts6.74 kB
import { TrellisObject } from "../../models/TrellisObject"; import { TrellisObjectPriority } from "../../models/TrellisObjectPriority"; import { TrellisObjectStatus } from "../../models/TrellisObjectStatus"; import { TrellisObjectType } from "../../models/TrellisObjectType"; import { Repository } from "../../repositories/Repository"; import { updateParentHierarchy } from "../updateParentHierarchy"; describe("updateParentHierarchy", () => { let mockRepository: jest.Mocked<Repository>; beforeEach(() => { mockRepository = { getObjectById: jest.fn(), getObjects: jest.fn(), saveObject: jest.fn(), deleteObject: jest.fn(), getChildrenOf: jest.fn(), }; jest.clearAllMocks(); }); const createMockObject = ( id: string, status: TrellisObjectStatus = TrellisObjectStatus.OPEN, parent: string | null = null, ): TrellisObject => ({ id, type: TrellisObjectType.TASK, title: `Test ${id}`, status, priority: TrellisObjectPriority.MEDIUM, parent, prerequisites: [], affectedFiles: new Map(), log: [], schema: "v1.0", childrenIds: [], created: "2023-01-01T00:00:00.000Z", updated: "2023-01-01T00:00:00.000Z", body: "", }); describe("when parentId is undefined", () => { it("should return early without making any repository calls", async () => { await updateParentHierarchy(null, mockRepository); expect(mockRepository.getObjectById).not.toHaveBeenCalled(); expect(mockRepository.saveObject).not.toHaveBeenCalled(); }); }); describe("when parent does not exist", () => { it("should return early without making save calls", async () => { mockRepository.getObjectById.mockResolvedValue(null); await updateParentHierarchy("P-parent", mockRepository); expect(mockRepository.getObjectById).toHaveBeenCalledWith("P-parent"); expect(mockRepository.saveObject).not.toHaveBeenCalled(); }); }); describe("when parent is already in progress", () => { it("should return early without making save calls", async () => { const parentObject = createMockObject( "P-parent", TrellisObjectStatus.IN_PROGRESS, ); mockRepository.getObjectById.mockResolvedValue(parentObject); await updateParentHierarchy("P-parent", mockRepository); expect(mockRepository.getObjectById).toHaveBeenCalledWith("P-parent"); expect(mockRepository.saveObject).not.toHaveBeenCalled(); }); }); describe("when parent needs to be updated", () => { it("should update parent status to in-progress", async () => { const parentObject = createMockObject( "P-parent", TrellisObjectStatus.OPEN, ); mockRepository.getObjectById.mockResolvedValue(parentObject); await updateParentHierarchy("P-parent", mockRepository); expect(mockRepository.getObjectById).toHaveBeenCalledWith("P-parent"); expect(mockRepository.saveObject).toHaveBeenCalledWith({ ...parentObject, status: TrellisObjectStatus.IN_PROGRESS, }); }); it("should update parent hierarchy recursively", async () => { const grandParentObject = createMockObject( "GP-grandparent", TrellisObjectStatus.OPEN, ); const parentObject = createMockObject( "P-parent", TrellisObjectStatus.OPEN, "GP-grandparent", ); mockRepository.getObjectById .mockResolvedValueOnce(parentObject) .mockResolvedValueOnce(grandParentObject); await updateParentHierarchy("P-parent", mockRepository); expect(mockRepository.getObjectById).toHaveBeenCalledWith("P-parent"); expect(mockRepository.getObjectById).toHaveBeenCalledWith( "GP-grandparent", ); expect(mockRepository.saveObject).toHaveBeenCalledWith({ ...parentObject, status: TrellisObjectStatus.IN_PROGRESS, }); expect(mockRepository.saveObject).toHaveBeenCalledWith({ ...grandParentObject, status: TrellisObjectStatus.IN_PROGRESS, }); }); it("should stop recursion when encountering an already in-progress parent", async () => { const grandParentObject = createMockObject( "GP-grandparent", TrellisObjectStatus.IN_PROGRESS, ); const parentObject = createMockObject( "P-parent", TrellisObjectStatus.OPEN, "GP-grandparent", ); mockRepository.getObjectById .mockResolvedValueOnce(parentObject) .mockResolvedValueOnce(grandParentObject); await updateParentHierarchy("P-parent", mockRepository); expect(mockRepository.getObjectById).toHaveBeenCalledWith("P-parent"); expect(mockRepository.getObjectById).toHaveBeenCalledWith( "GP-grandparent", ); expect(mockRepository.saveObject).toHaveBeenCalledTimes(1); expect(mockRepository.saveObject).toHaveBeenCalledWith({ ...parentObject, status: TrellisObjectStatus.IN_PROGRESS, }); }); }); describe("infinite recursion prevention", () => { it("should prevent infinite recursion with visited IDs", async () => { const parentObject = createMockObject( "P-parent", TrellisObjectStatus.OPEN, "P-parent", ); mockRepository.getObjectById.mockResolvedValue(parentObject); await updateParentHierarchy("P-parent", mockRepository); expect(mockRepository.getObjectById).toHaveBeenCalledTimes(1); expect(mockRepository.saveObject).toHaveBeenCalledTimes(1); }); it("should handle circular references in parent hierarchy", async () => { const parentA = createMockObject("P-A", TrellisObjectStatus.OPEN, "P-B"); const parentB = createMockObject("P-B", TrellisObjectStatus.OPEN, "P-A"); mockRepository.getObjectById.mockImplementation((id: string) => { if (id === "P-A") return Promise.resolve(parentA); if (id === "P-B") return Promise.resolve(parentB); return Promise.resolve(null); }); await updateParentHierarchy("P-A", mockRepository); expect(mockRepository.getObjectById).toHaveBeenCalledWith("P-A"); expect(mockRepository.getObjectById).toHaveBeenCalledWith("P-B"); expect(mockRepository.saveObject).toHaveBeenCalledTimes(2); }); }); describe("with custom visited IDs set", () => { it("should respect pre-existing visited IDs", async () => { const visitedIds = new Set(["P-parent"]); await updateParentHierarchy("P-parent", mockRepository, visitedIds); expect(mockRepository.getObjectById).not.toHaveBeenCalled(); expect(mockRepository.saveObject).not.toHaveBeenCalled(); }); }); });

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