Skip to main content
Glama

documcp

by tosin2013
recommend-ssg.test.ts19.3 kB
/** * Test suite for SSG Recommendation Tool */ import { jest } from "@jest/globals"; import { recommendSSG } from "../../src/tools/recommend-ssg.js"; // Mock the memory and KG integration jest.mock("../../src/memory/kg-integration.js", () => ({ getMemoryManager: jest.fn(), getKnowledgeGraph: jest.fn(), getUserPreferenceManager: jest.fn(), getProjectContext: jest.fn(), saveKnowledgeGraph: (jest.fn() as any).mockResolvedValue(undefined), })); describe("recommendSSG", () => { let mockManager: any; let mockKG: any; let mockPreferenceManager: any; beforeEach(() => { mockManager = { recall: jest.fn() as any, } as any; mockKG = { findNode: (jest.fn() as any).mockResolvedValue(null), findNodes: (jest.fn() as any).mockResolvedValue([]), findEdges: (jest.fn() as any).mockResolvedValue([]), getAllNodes: (jest.fn() as any).mockResolvedValue([]), addNode: (jest.fn() as any).mockImplementation((node: any) => node), addEdge: (jest.fn() as any).mockReturnValue(undefined), } as any; mockPreferenceManager = { getPreference: (jest.fn() as any).mockResolvedValue(null), } as any; const { getMemoryManager, getKnowledgeGraph, getUserPreferenceManager, getProjectContext, } = require("../../src/memory/kg-integration.js"); getMemoryManager.mockResolvedValue(mockManager); getKnowledgeGraph.mockResolvedValue(mockKG); getUserPreferenceManager.mockResolvedValue(mockPreferenceManager); getProjectContext.mockResolvedValue({ previousAnalyses: 0, lastAnalyzed: null, knownTechnologies: [], similarProjects: [], }); }); afterEach(() => { jest.clearAllMocks(); }); describe("Input Validation", () => { it("should validate required analysisId parameter", async () => { await expect(recommendSSG({})).rejects.toThrow(); }); it("should validate analysisId as string", async () => { await expect(recommendSSG({ analysisId: 123 })).rejects.toThrow(); }); it("should accept valid preferences", async () => { mockManager.recall.mockResolvedValue(null); const result = await recommendSSG({ analysisId: "test-id", preferences: { priority: "simplicity", ecosystem: "javascript", }, }); expect(result.content).toBeDefined(); }); it("should reject invalid priority preference", async () => { await expect( recommendSSG({ analysisId: "test-id", preferences: { priority: "invalid" }, }), ).rejects.toThrow(); }); it("should reject invalid ecosystem preference", async () => { await expect( recommendSSG({ analysisId: "test-id", preferences: { ecosystem: "invalid" }, }), ).rejects.toThrow(); }); }); describe("Memory Integration", () => { it("should retrieve analysis from memory when available", async () => { const mockAnalysis = { data: { content: [ { type: "text", text: JSON.stringify({ repository: { language: "JavaScript" }, complexity: "low", size: "small", }), }, ], }, }; mockManager.recall.mockResolvedValue(mockAnalysis); const result = await recommendSSG({ analysisId: "test-id", }); expect(mockManager.recall).toHaveBeenCalledWith("test-id"); expect(result.content).toBeDefined(); }); it("should handle missing analysis gracefully", async () => { mockManager.recall.mockResolvedValue(null); const result = await recommendSSG({ analysisId: "non-existent-id", }); expect(result.content).toBeDefined(); expect(result.content[0].type).toBe("text"); }); it("should handle analysis with direct data structure", async () => { const mockAnalysis = { data: { repository: { language: "Python" }, complexity: "medium", }, }; mockManager.recall.mockResolvedValue(mockAnalysis); const result = await recommendSSG({ analysisId: "test-id", }); expect(result.content).toBeDefined(); }); it("should handle corrupted analysis data", async () => { const mockAnalysis = { data: { content: [ { type: "text", text: "invalid json", }, ], }, }; mockManager.recall.mockResolvedValue(mockAnalysis); const result = await recommendSSG({ analysisId: "test-id", }); expect(result.content).toBeDefined(); }); }); describe("SSG Recommendations", () => { it("should recommend Jekyll for Ruby projects", async () => { const mockAnalysis = { data: { dependencies: { ecosystem: "ruby", }, complexity: "low", }, }; mockManager.recall.mockResolvedValue(mockAnalysis); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.recommended).toBe("jekyll"); }); it("should recommend Hugo for Go projects", async () => { const mockAnalysis = { data: { dependencies: { ecosystem: "go", }, complexity: "medium", }, }; mockManager.recall.mockResolvedValue(mockAnalysis); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.recommended).toBe("hugo"); }); it("should recommend Docusaurus for JavaScript projects", async () => { const mockAnalysis = { data: { dependencies: { ecosystem: "javascript", }, documentation: { estimatedComplexity: "complex", }, recommendations: { teamSize: "large", }, }, }; mockManager.recall.mockResolvedValue(mockAnalysis); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.recommended).toBe("docusaurus"); }); it("should recommend MkDocs for Python projects", async () => { const mockAnalysis = { data: { dependencies: { ecosystem: "python", }, complexity: "medium", }, }; mockManager.recall.mockResolvedValue(mockAnalysis); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.recommended).toBe("mkdocs"); }); it("should recommend Eleventy for simple JavaScript projects with simplicity priority", async () => { const mockAnalysis = { data: { dependencies: { ecosystem: "javascript", }, documentation: { estimatedComplexity: "simple", }, recommendations: { teamSize: "small", }, }, }; mockManager.recall.mockResolvedValue(mockAnalysis); const result = await recommendSSG({ analysisId: "test-id", preferences: { priority: "simplicity" }, }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.recommended).toBe("eleventy"); }); }); describe("Preference-based Recommendations", () => { it("should prioritize simplicity when requested", async () => { mockManager.recall.mockResolvedValue(null); const result = await recommendSSG({ analysisId: "test-id", preferences: { priority: "simplicity" }, }); const recommendation = JSON.parse(result.content[0].text); expect(["jekyll", "eleventy"]).toContain(recommendation.recommended); }); it("should consider ecosystem preferences", async () => { mockManager.recall.mockResolvedValue(null); const result = await recommendSSG({ analysisId: "test-id", preferences: { ecosystem: "javascript" }, }); const recommendation = JSON.parse(result.content[0].text); expect(["docusaurus", "eleventy"]).toContain(recommendation.recommended); }); it("should handle performance preference with fallback", async () => { mockManager.recall.mockResolvedValue(null); const result = await recommendSSG({ analysisId: "test-id", preferences: { priority: "performance" }, }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.recommended).toBe("docusaurus"); }); it("should handle features preference with fallback", async () => { mockManager.recall.mockResolvedValue(null); const result = await recommendSSG({ analysisId: "test-id", preferences: { priority: "features" }, }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.recommended).toBe("docusaurus"); }); }); describe("Scoring and Alternatives", () => { it("should provide confidence scores", async () => { mockManager.recall.mockResolvedValue({ data: { dependencies: { ecosystem: "javascript", }, complexity: "medium", }, }); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.confidence).toBeGreaterThan(0); expect(recommendation.confidence).toBeLessThanOrEqual(1); }); it("should provide alternative recommendations", async () => { mockManager.recall.mockResolvedValue({ data: { dependencies: { ecosystem: "javascript", }, complexity: "medium", }, }); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.alternatives).toBeDefined(); expect(Array.isArray(recommendation.alternatives)).toBe(true); expect(recommendation.alternatives.length).toBeGreaterThan(0); }); it("should include pros and cons for alternatives", async () => { mockManager.recall.mockResolvedValue({ data: { dependencies: { ecosystem: "python", }, complexity: "medium", }, }); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); const alternative = recommendation.alternatives[0]; expect(alternative.name).toBeDefined(); expect(alternative.score).toBeDefined(); expect(Array.isArray(alternative.pros)).toBe(true); expect(Array.isArray(alternative.cons)).toBe(true); }); it("should sort alternatives by score", async () => { mockManager.recall.mockResolvedValue({ data: { dependencies: { ecosystem: "javascript", }, documentation: { estimatedComplexity: "complex", }, }, }); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); const scores = recommendation.alternatives.map((alt: any) => alt.score); for (let i = 1; i < scores.length; i++) { expect(scores[i]).toBeLessThanOrEqual(scores[i - 1]); } }); }); describe("Complex Project Analysis", () => { it("should handle projects with React packages", async () => { mockManager.recall.mockResolvedValue({ data: { dependencies: { ecosystem: "javascript", packages: ["react", "next"], }, }, }); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.recommended).toBe("docusaurus"); expect(recommendation.reasoning.length).toBeGreaterThan(0); }); it("should consider project size in recommendations", async () => { mockManager.recall.mockResolvedValue({ data: { dependencies: { ecosystem: "javascript", }, structure: { totalFiles: 150, // Large project }, documentation: { estimatedComplexity: "complex", hasReadme: true, hasDocs: true, }, }, }); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.confidence).toBeGreaterThan(0.85); // Should have higher confidence with more data }); it("should handle missing ecosystem information", async () => { mockManager.recall.mockResolvedValue({ data: { dependencies: { ecosystem: "unknown", }, documentation: { estimatedComplexity: "moderate", }, }, }); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.recommended).toBeDefined(); }); it("should consider existing documentation structure", async () => { mockManager.recall.mockResolvedValue({ data: { dependencies: { ecosystem: "javascript", }, documentation: { hasReadme: true, hasDocs: true, estimatedComplexity: "moderate", }, }, }); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.confidence).toBeGreaterThan(0.85); // Higher confidence with documentation }); }); describe("Memory Error Handling", () => { it("should handle memory initialization failure", async () => { const { getMemoryManager, } = require("../../src/memory/kg-integration.js"); getMemoryManager.mockRejectedValue(new Error("Memory failed")); const result = await recommendSSG({ analysisId: "test-id", }); expect(result.content).toBeDefined(); expect(result.content[0].type).toBe("text"); // Reset the mock getMemoryManager.mockResolvedValue(mockManager); }); it("should handle memory recall failure", async () => { mockManager.recall.mockRejectedValue(new Error("Recall failed")); const result = await recommendSSG({ analysisId: "test-id", }); expect(result.content).toBeDefined(); }); it("should handle corrupted memory data", async () => { mockManager.recall.mockResolvedValue({ data: { content: [ { type: "text", text: '{"invalid": json}', }, ], }, }); const result = await recommendSSG({ analysisId: "test-id", }); expect(result.content).toBeDefined(); }); }); describe("Performance and Timing", () => { it("should complete recommendation in reasonable time", async () => { mockManager.recall.mockResolvedValue({ data: { repository: { language: "JavaScript" }, complexity: "medium", }, }); const start = Date.now(); await recommendSSG({ analysisId: "test-id", }); const duration = Date.now() - start; expect(duration).toBeLessThan(5000); // Should complete within 5 seconds }); it("should include execution time in response", async () => { mockManager.recall.mockResolvedValue({ data: { repository: { language: "JavaScript" }, }, }); const result = await recommendSSG({ analysisId: "test-id", }); expect(result.content[1].text).toContain("Execution completed in"); }); }); describe("Edge Cases", () => { it("should handle null analysis data", async () => { mockManager.recall.mockResolvedValue({ data: null, }); const result = await recommendSSG({ analysisId: "test-id", }); expect(result.content).toBeDefined(); }); it("should handle empty analysis data", async () => { mockManager.recall.mockResolvedValue({ data: {}, }); const result = await recommendSSG({ analysisId: "test-id", }); expect(result.content).toBeDefined(); }); it("should handle analysis without dependency data", async () => { mockManager.recall.mockResolvedValue({ data: { documentation: { estimatedComplexity: "moderate", }, }, }); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.recommended).toBeDefined(); }); it("should handle unknown programming languages", async () => { mockManager.recall.mockResolvedValue({ data: { dependencies: { ecosystem: "unknown", }, documentation: { estimatedComplexity: "moderate", }, }, }); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation.recommended).toBeDefined(); }); }); describe("Response Format", () => { it("should return properly formatted MCP response", async () => { mockManager.recall.mockResolvedValue({ data: { repository: { language: "JavaScript" }, }, }); const result = await recommendSSG({ analysisId: "test-id", }); expect(result).toHaveProperty("content"); expect(Array.isArray(result.content)).toBe(true); expect(result.content[0]).toHaveProperty("type"); expect(result.content[0]).toHaveProperty("text"); }); it("should include all required recommendation fields", async () => { mockManager.recall.mockResolvedValue({ data: { repository: { language: "Python" }, }, }); const result = await recommendSSG({ analysisId: "test-id", }); const recommendation = JSON.parse(result.content[0].text); expect(recommendation).toHaveProperty("recommended"); expect(recommendation).toHaveProperty("confidence"); expect(recommendation).toHaveProperty("reasoning"); expect(recommendation).toHaveProperty("alternatives"); expect(result.content[1].text).toContain("Execution completed in"); }); }); });

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/tosin2013/documcp'

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