Skip to main content
Glama

Task Trellis MCP

serializationRoundTrip.test.ts16 kB
import { TrellisObject, TrellisObjectPriority, TrellisObjectStatus, TrellisObjectType, } from "../../models"; import { deserializeTrellisObject } from "../deserializeTrellisObject"; import { serializeTrellisObject } from "../serializeTrellisObject"; describe("TrellisObject Serialization/Deserialization Integration Tests", () => { describe("Round-trip serialization compatibility", () => { it("should handle basic TrellisObject round-trip", () => { const original: TrellisObject = { id: "T-basic-test", title: "Basic Test Task", status: TrellisObjectStatus.OPEN, priority: TrellisObjectPriority.MEDIUM, prerequisites: ["prereq-1", "prereq-2"], affectedFiles: new Map([ ["src/component.ts", "modified"], ["tests/component.test.ts", "created"], ]), log: ["Initial commit", "Added tests"], schema: "v1.0", childrenIds: ["child-1"], body: "Basic task description", type: TrellisObjectType.TASK, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }; const serialized = serializeTrellisObject(original); const deserialized = deserializeTrellisObject(serialized); expect(deserialized).toEqual(original); }); it("should handle complex multi-line content round-trip", () => { const complexBody = `# Complex Task This task involves multiple steps: ## Prerequisites - Set up environment - Install dependencies ## Implementation Steps 1. Create the main component 2. Add unit tests 3. Update documentation \`\`\`typescript interface Example { name: string; value: number; } \`\`\` ## Notes > **Important**: This requires careful attention to detail. ### Edge Cases - Handle empty inputs - Validate user permissions - Graceful error handling --- Additional section with --- delimiters for testing.`; const original: TrellisObject = { id: "T-complex-content-test", title: 'Complex Content Test with "quotes" and symbols: @#$%', status: TrellisObjectStatus.IN_PROGRESS, priority: TrellisObjectPriority.HIGH, prerequisites: [ "setup environment", 'install deps with "quotes"', "config: with: colons", ], affectedFiles: new Map([ ["src/complex file name.ts", "created"], ["docs/README.md", "updated"], ["config/settings.json", "modified"], ["tests/integration/complex.test.ts", "created"], ]), log: [ "Initial implementation", "Multi-line commit message:\n- Added feature A\n- Fixed bug B\n- Updated docs", "Code review feedback:\n\n> Reviewer comments:\n> - Good implementation\n> - Consider edge cases", 'Final commit with special chars: "quotes" and symbols @#$%', ], schema: "v2.1-beta", childrenIds: ["subtask-1", "subtask-2", "cleanup-task"], body: complexBody, type: TrellisObjectType.TASK, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }; const serialized = serializeTrellisObject(original); const deserialized = deserializeTrellisObject(serialized); expect(deserialized).toEqual(original); }); it("should handle empty collections round-trip", () => { const original: TrellisObject = { id: "T-empty-collections-test", title: "Empty Collections Test", status: TrellisObjectStatus.DRAFT, priority: TrellisObjectPriority.LOW, prerequisites: [], affectedFiles: new Map(), log: [], schema: "v1.0", childrenIds: [], body: "", type: TrellisObjectType.TASK, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }; const serialized = serializeTrellisObject(original); const deserialized = deserializeTrellisObject(serialized); expect(deserialized).toEqual(original); }); it("should handle special characters and unicode round-trip", () => { const original: TrellisObject = { id: "T-unicode-test-🚀", title: "Unicode Test: 你好世界 🌍 émojis & spëcial chars", status: TrellisObjectStatus.OPEN, priority: TrellisObjectPriority.MEDIUM, prerequisites: [ "Setup with émojis 🔧", "Config files: ~/.bashrc", 'Path with spaces and "quotes"', ], affectedFiles: new Map([ ["src/émoji-component.ts", "créated"], ["docs/中文文档.md", "updated"], ["files/with spaces & symbols.json", "modified"], ]), log: [ "Added unicode support 🎉", "Fixed encoding issues:\n- UTF-8 properly handled\n- Special chars: àáâãäåæç", "Emoji support: 😀😃😄😁😆😅🤣😂", ], schema: "v1.0", childrenIds: ["子任务-1", "tâche-2"], body: `# Unicode Support Test This task tests unicode and special character handling. ## Examples: - Chinese: 你好世界 - French: Bonjour le monde - Spanish: Hola mundo - Emojis: 🚀🌟💫⭐🎯 ### Code Example: \`\`\`javascript const greeting = "Hello 世界! 🌍"; console.log(greeting); \`\`\` > Note: All unicode characters should be preserved.`, type: TrellisObjectType.TASK, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }; const serialized = serializeTrellisObject(original); const deserialized = deserializeTrellisObject(serialized); expect(deserialized).toEqual(original); }); it("should handle body content with YAML-like structure round-trip", () => { const yamlLikeBody = `# Task with YAML-like content This task contains content that might confuse the parser: \`\`\`yaml --- config: name: example values: - item1 - item2 --- \`\`\` ## Configuration Example \`\`\` key: value list: - first - second nested: deep: property: "value with --- markers" \`\`\` --- This section starts with --- which could be problematic. ### More content after --- The parser should handle all of this correctly.`; const original: TrellisObject = { id: "T-yaml-body-test", title: "YAML Body Content Test", status: TrellisObjectStatus.OPEN, priority: TrellisObjectPriority.HIGH, prerequisites: ["yaml-parser-setup"], affectedFiles: new Map([["config/app.yaml", "created"]]), log: ["Added YAML config support"], schema: "v1.0", childrenIds: [], body: yamlLikeBody, type: TrellisObjectType.TASK, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }; const serialized = serializeTrellisObject(original); const deserialized = deserializeTrellisObject(serialized); expect(deserialized).toEqual(original); }); it("should handle very large content round-trip", () => { // Create large arrays and content to test performance and memory handling const largePrerequistes = Array.from( { length: 100 }, (_, i) => `prerequisite-${i}`, ); const largeLog = Array.from( { length: 50 }, (_, i) => `Log entry ${i}:\nThis is a multi-line log entry\nwith detailed information\nabout step ${i}`, ); const largeChildrenIds = Array.from( { length: 200 }, (_, i) => `child-task-${i}`, ); const largeAffectedFiles = new Map<string, string>(); for (let i = 0; i < 150; i++) { largeAffectedFiles.set( `src/component-${i}.ts`, i % 3 === 0 ? "created" : i % 3 === 1 ? "modified" : "deleted", ); } const largeBody = `# Large Content Test ${"This is a large body content section that repeats many times. ".repeat(500)} ## Large Section ${"Another section with repeated content for testing serialization performance. ".repeat(300)} ### Code Blocks \`\`\`typescript ${Array.from({ length: 50 }, (_, i) => `const variable${i} = "value${i}";`).join("\n")} \`\`\` ## Final Notes ${"Final section content repeated multiple times to test large content handling. ".repeat(200)}`; const original: TrellisObject = { id: "T-large-content-test", title: "Large Content Performance Test", status: TrellisObjectStatus.OPEN, priority: TrellisObjectPriority.LOW, prerequisites: largePrerequistes, affectedFiles: largeAffectedFiles, log: largeLog, schema: "v1.0", childrenIds: largeChildrenIds, body: largeBody, type: TrellisObjectType.TASK, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }; const serialized = serializeTrellisObject(original); const deserialized = deserializeTrellisObject(serialized); expect(deserialized).toEqual(original); }); it("should maintain Map order and exact string content", () => { const original: TrellisObject = { id: "T-map-order-test", title: "Map Order Preservation Test", status: TrellisObjectStatus.OPEN, priority: TrellisObjectPriority.MEDIUM, prerequisites: ["first-prereq", "second-prereq", "third-prereq"], affectedFiles: new Map([ ["z-last-file.ts", "created"], ["a-first-file.ts", "modified"], ["m-middle-file.ts", "deleted"], ["1-numeric-start.ts", "created"], ["special@file#name.ts", "modified"], ]), log: [ "First log entry", "Second log with\nmultiple\nlines", "Third log entry", ], schema: "v1.0", childrenIds: ["z-child", "a-child", "m-child"], body: "Test body content", type: TrellisObjectType.TASK, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }; const serialized = serializeTrellisObject(original); const deserialized = deserializeTrellisObject(serialized); // Check that the Map maintains the same entries expect(deserialized.affectedFiles.size).toBe(original.affectedFiles.size); // Check each entry individually for (const [key, value] of original.affectedFiles) { expect(deserialized.affectedFiles.get(key)).toBe(value); } // Verify complete equality expect(deserialized).toEqual(original); }); }); describe("Serialization format validation", () => { it("should produce valid YAML frontmatter structure", () => { const original: TrellisObject = { id: "F-format-test", title: "Format Validation Test", status: TrellisObjectStatus.OPEN, priority: TrellisObjectPriority.HIGH, prerequisites: ["test-setup"], affectedFiles: new Map([["test.ts", "created"]]), log: ["Format test"], schema: "v1.0", childrenIds: ["format-child"], body: "Format validation body", type: TrellisObjectType.FEATURE, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }; const serialized = serializeTrellisObject(original); // Check overall structure expect(serialized).toMatch( /^---\n[\s\S]+\n---\n\nFormat validation body$/, ); // Verify it can be deserialized const deserialized = deserializeTrellisObject(serialized); expect(deserialized).toEqual(original); }); it("should handle edge case: body starting with ---", () => { const original: TrellisObject = { id: "E-edge-case-test", title: "Edge Case Test", status: TrellisObjectStatus.OPEN, priority: TrellisObjectPriority.MEDIUM, prerequisites: [], affectedFiles: new Map(), log: [], schema: "v1.0", childrenIds: [], body: "---\nThis body starts with --- which is tricky\n---\nAnd has more --- markers", type: TrellisObjectType.EPIC, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }; const serialized = serializeTrellisObject(original); const deserialized = deserializeTrellisObject(serialized); expect(deserialized).toEqual(original); }); }); describe("Cross-validation with multiple objects", () => { it("should handle multiple different objects in sequence", () => { const objects: TrellisObject[] = [ { id: "T-seq-1", title: "First Object", status: TrellisObjectStatus.DONE, priority: TrellisObjectPriority.LOW, prerequisites: [], affectedFiles: new Map([["file1.ts", "created"]]), log: ["First object log"], schema: "v1.0", childrenIds: [], body: "First body", type: TrellisObjectType.TASK, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }, { id: "P-seq-2", title: "Second Object", status: TrellisObjectStatus.IN_PROGRESS, priority: TrellisObjectPriority.HIGH, prerequisites: ["T-seq-1"], affectedFiles: new Map([ ["file1.ts", "modified"], ["file2.ts", "created"], ]), log: [ "Started second object", "Multi-line log:\nwith details\nand more info", ], schema: "v2.0", childrenIds: ["seq-2-child"], body: "# Second Object\n\nMore complex content.", type: TrellisObjectType.PROJECT, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }, { id: "F-seq-3", title: 'Third Object with "quotes"', status: TrellisObjectStatus.OPEN, priority: TrellisObjectPriority.MEDIUM, prerequisites: ["T-seq-1", "P-seq-2"], affectedFiles: new Map(), log: [], schema: "v1.5", childrenIds: ["seq-3a", "seq-3b"], body: "", type: TrellisObjectType.FEATURE, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }, ]; // Serialize all objects const serializedObjects = objects.map((obj) => serializeTrellisObject(obj), ); // Deserialize all objects const deserializedObjects = serializedObjects.map((str) => deserializeTrellisObject(str), ); // Verify each object matches the original deserializedObjects.forEach((deserialized, index) => { expect(deserialized).toEqual(objects[index]); }); }); it("should handle TrellisObject with undefined parent round-trip", () => { const original: TrellisObject = { id: "T-no-parent-round-trip", title: "No Parent Round Trip Test", status: TrellisObjectStatus.OPEN, priority: TrellisObjectPriority.MEDIUM, // parent is undefined (not included in object) prerequisites: ["setup"], affectedFiles: new Map([["test.ts", "created"]]), log: ["Initial setup"], schema: "v1.0", childrenIds: [], body: "Test content with no parent", type: TrellisObjectType.TASK, created: "2025-01-15T10:00:00Z", updated: "2025-01-15T10:00:00Z", parent: null, }; const serialized = serializeTrellisObject(original); const deserialized = deserializeTrellisObject(serialized); expect(deserialized).toEqual(original); expect(deserialized.parent).toBeNull(); }); }); });

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