Skip to main content
Glama

documcp

by tosin2013
all-tools.test.ts20.1 kB
// Comprehensive tests for all MCP tools to achieve 80% coverage import { promises as fs } from "fs"; import path from "path"; import os from "os"; import tmp from "tmp"; import { analyzeRepository } from "../../src/tools/analyze-repository"; import { recommendSSG } from "../../src/tools/recommend-ssg"; import { generateConfig } from "../../src/tools/generate-config"; import { setupStructure } from "../../src/tools/setup-structure"; import { deployPages } from "../../src/tools/deploy-pages"; import { verifyDeployment } from "../../src/tools/verify-deployment"; import { evaluateReadmeHealth } from "../../src/tools/evaluate-readme-health"; import { readmeBestPractices } from "../../src/tools/readme-best-practices"; describe("All MCP Tools Coverage Tests", () => { let tempDir: string; beforeAll(async () => { tempDir = path.join(os.tmpdir(), "documcp-coverage-tests"); await fs.mkdir(tempDir, { recursive: true }); }); afterAll(async () => { try { await fs.rm(tempDir, { recursive: true, force: true }); } catch (error) { // Ignore cleanup errors } }); describe("analyze_repository", () => { it("should analyze JavaScript project", async () => { const jsRepo = await createJSRepo(); const result = await analyzeRepository({ path: jsRepo, depth: "standard", }); expect(result.content).toBeDefined(); const analysisData = JSON.parse( result.content.find((c) => c.text.includes('"ecosystem"'))!.text, ); expect(analysisData.dependencies.ecosystem).toBe("javascript"); }); it("should analyze Python project", async () => { const pyRepo = await createPythonRepo(); const result = await analyzeRepository({ path: pyRepo, depth: "standard", }); expect(result.content).toBeDefined(); const analysisData = JSON.parse( result.content.find((c) => c.text.includes('"ecosystem"'))!.text, ); expect(analysisData.dependencies.ecosystem).toBe("python"); }); it("should handle different depths", async () => { const repo = await createJSRepo(); const quickResult = await analyzeRepository({ path: repo, depth: "quick", }); const deepResult = await analyzeRepository({ path: repo, depth: "deep" }); expect(quickResult.content).toBeDefined(); expect(deepResult.content).toBeDefined(); }); it("should detect CI/CD workflows", async () => { const ciRepo = await createRepoWithCI(); const result = await analyzeRepository({ path: ciRepo, depth: "standard", }); const analysisData = JSON.parse( result.content.find((c) => c.text.includes('"hasCI"'))!.text, ); expect(analysisData.structure.hasCI).toBe(true); }); it("should handle repository without dependencies", async () => { const emptyRepo = await createEmptyRepo(); const result = await analyzeRepository({ path: emptyRepo, depth: "standard", }); const analysisData = JSON.parse( result.content.find((c) => c.text.includes('"ecosystem"'))!.text, ); expect(analysisData.dependencies.ecosystem).toBe("unknown"); }); }); describe("recommend_ssg", () => { it("should provide recommendation with confidence", async () => { const result = await recommendSSG({ analysisId: "test-123" }); expect(result.content).toBeDefined(); const recData = JSON.parse( result.content.find((c) => c.text.includes('"confidence"'))!.text, ); expect(recData.confidence).toBeGreaterThan(0); expect(recData.confidence).toBeLessThanOrEqual(1); }); it("should handle preferences", async () => { const result = await recommendSSG({ analysisId: "test-456", preferences: { priority: "simplicity", ecosystem: "javascript", }, }); expect(result.content).toBeDefined(); const recData = JSON.parse( result.content.find((c) => c.text.includes('"recommended"'))!.text, ); expect(["jekyll", "hugo", "docusaurus", "mkdocs", "eleventy"]).toContain( recData.recommended, ); }); it("should provide alternatives", async () => { const result = await recommendSSG({ analysisId: "test-789" }); const recData = JSON.parse( result.content.find((c) => c.text.includes('"alternatives"'))!.text, ); expect(Array.isArray(recData.alternatives)).toBe(true); expect(recData.alternatives.length).toBeGreaterThan(0); }); }); describe("generate_config", () => { it("should generate Docusaurus config", async () => { const outputDir = await createTempDir("docusaurus-config"); const result = await generateConfig({ ssg: "docusaurus", projectName: "Test Docusaurus", outputPath: outputDir, }); expect(result.content).toBeDefined(); expect( await fileExists(path.join(outputDir, "docusaurus.config.js")), ).toBe(true); expect(await fileExists(path.join(outputDir, "package.json"))).toBe(true); }); it("should generate MkDocs config", async () => { const outputDir = await createTempDir("mkdocs-config"); const result = await generateConfig({ ssg: "mkdocs", projectName: "Test MkDocs", outputPath: outputDir, }); expect(result.content).toBeDefined(); expect(await fileExists(path.join(outputDir, "mkdocs.yml"))).toBe(true); expect(await fileExists(path.join(outputDir, "requirements.txt"))).toBe( true, ); }); it("should generate Hugo config", async () => { const outputDir = await createTempDir("hugo-config"); const result = await generateConfig({ ssg: "hugo", projectName: "Test Hugo", outputPath: outputDir, }); expect(result.content).toBeDefined(); expect(await fileExists(path.join(outputDir, "hugo.toml"))).toBe(true); }); it("should generate Jekyll config", async () => { const outputDir = await createTempDir("jekyll-config"); const result = await generateConfig({ ssg: "jekyll", projectName: "Test Jekyll", outputPath: outputDir, }); expect(result.content).toBeDefined(); expect(await fileExists(path.join(outputDir, "_config.yml"))).toBe(true); expect(await fileExists(path.join(outputDir, "Gemfile"))).toBe(true); }); it("should generate Eleventy config", async () => { const outputDir = await createTempDir("eleventy-config"); const result = await generateConfig({ ssg: "eleventy", projectName: "Test Eleventy", outputPath: outputDir, }); expect(result.content).toBeDefined(); expect(await fileExists(path.join(outputDir, ".eleventy.js"))).toBe(true); expect(await fileExists(path.join(outputDir, "package.json"))).toBe(true); }); }); describe("setup_structure", () => { it("should create Diataxis structure", async () => { const docsDir = await createTempDir("diataxis-structure"); const result = await setupStructure({ path: docsDir, ssg: "docusaurus", includeExamples: true, }); expect(result.content).toBeDefined(); const categories = ["tutorials", "how-to", "reference", "explanation"]; for (const category of categories) { expect(await fileExists(path.join(docsDir, category, "index.md"))).toBe( true, ); } expect(await fileExists(path.join(docsDir, "index.md"))).toBe(true); }); it("should create structure without examples", async () => { const docsDir = await createTempDir("no-examples"); const result = await setupStructure({ path: docsDir, ssg: "mkdocs", includeExamples: false, }); expect(result.content).toBeDefined(); const tutorialsFiles = await fs.readdir(path.join(docsDir, "tutorials")); expect(tutorialsFiles).toEqual(["index.md"]); // Only index, no examples }); it("should handle different SSG formats", async () => { const docusaurusDir = await createTempDir("docusaurus-format"); await setupStructure({ path: docusaurusDir, ssg: "docusaurus", includeExamples: true, }); const content = await fs.readFile( path.join(docusaurusDir, "tutorials", "index.md"), "utf-8", ); expect(content).toContain("id: tutorials-index"); const jekyllDir = await createTempDir("jekyll-format"); await setupStructure({ path: jekyllDir, ssg: "jekyll", includeExamples: true, }); const jekyllContent = await fs.readFile( path.join(jekyllDir, "tutorials", "index.md"), "utf-8", ); expect(jekyllContent).toContain("title:"); }); }); describe("deploy_pages", () => { it("should create Docusaurus deployment workflow", async () => { const repoDir = await createTempDir("docusaurus-deploy"); const result = await deployPages({ repository: repoDir, ssg: "docusaurus", }); expect(result.content).toBeDefined(); const workflowPath = path.join( repoDir, ".github", "workflows", "deploy-docs.yml", ); expect(await fileExists(workflowPath)).toBe(true); const workflowContent = await fs.readFile(workflowPath, "utf-8"); expect(workflowContent).toContain("Deploy Docusaurus"); expect(workflowContent).toContain("npm run build"); }); it("should create MkDocs deployment workflow", async () => { const repoDir = await createTempDir("mkdocs-deploy"); const result = await deployPages({ repository: repoDir, ssg: "mkdocs", }); const workflowContent = await fs.readFile( path.join(repoDir, ".github", "workflows", "deploy-docs.yml"), "utf-8", ); expect(workflowContent).toContain("mkdocs gh-deploy"); }); it("should handle custom domain", async () => { const repoDir = await createTempDir("custom-domain"); const result = await deployPages({ repository: repoDir, ssg: "docusaurus", customDomain: "docs.example.com", }); expect(result.content).toBeDefined(); expect(await fileExists(path.join(repoDir, "CNAME"))).toBe(true); const cnameContent = await fs.readFile( path.join(repoDir, "CNAME"), "utf-8", ); expect(cnameContent.trim()).toBe("docs.example.com"); }); it("should handle different branches", async () => { const repoDir = await createTempDir("custom-branch"); await deployPages({ repository: repoDir, ssg: "hugo", branch: "main", }); const workflowContent = await fs.readFile( path.join(repoDir, ".github", "workflows", "deploy-docs.yml"), "utf-8", ); expect(workflowContent).toContain("Deploy Hugo"); }); }); describe("verify_deployment", () => { it("should verify complete setup", async () => { const repoDir = await createCompleteRepo(); const result = await verifyDeployment({ repository: repoDir, }); expect(result.content).toBeDefined(); const verification = JSON.parse(result.content[0].text); expect(verification.overallStatus).toBe("Ready for deployment"); expect(verification.summary.passed).toBeGreaterThan(0); }); it("should identify missing components", async () => { const emptyDir = await createTempDir("empty-verify"); const result = await verifyDeployment({ repository: emptyDir, }); const verification = JSON.parse(result.content[0].text); expect(verification.overallStatus).toContain("Configuration required"); expect(verification.summary.failed).toBeGreaterThan(0); expect( verification.checks.some((check: any) => check.message.includes("No .github/workflows"), ), ).toBe(true); }); it("should handle different repository paths", async () => { const relativeResult = await verifyDeployment({ repository: "." }); expect(relativeResult.content).toBeDefined(); const httpResult = await verifyDeployment({ repository: "https://github.com/user/repo", }); expect(httpResult.content).toBeDefined(); }); it("should provide recommendations", async () => { const incompleteDir = await createTempDir("incomplete"); await fs.writeFile(path.join(incompleteDir, "README.md"), "# Test"); const result = await verifyDeployment({ repository: incompleteDir, }); const resultText = result.content.map((c) => c.text).join("\n"); expect(resultText).toContain("→"); expect(resultText).toContain("deploy_pages tool"); }); it("should check for different config patterns", async () => { const configDir = await createTempDir("config-check"); await fs.writeFile( path.join(configDir, "docusaurus.config.js"), "module.exports = {};", ); const result = await verifyDeployment({ repository: configDir, }); const resultText = result.content.map((c) => c.text).join("\n"); expect(resultText).toContain("SSG Configuration"); expect(resultText).toContain("docusaurus.config.js"); }); }); describe("evaluate_readme_health", () => { it("should evaluate README health with minimal input", async () => { const readmePath = await createReadmeFile("Basic project README"); const result = await evaluateReadmeHealth({ readme_path: readmePath, }); expect(result.content).toBeDefined(); expect(result.isError).toBe(false); const healthData = result.content.find((c) => c.text.includes("healthReport"), ); expect(healthData).toBeDefined(); }); it("should handle different project types", async () => { const readmePath = await createReadmeFile( "Enterprise tool documentation", ); const result = await evaluateReadmeHealth({ readme_path: readmePath, project_type: "enterprise_tool", }); expect(result.content).toBeDefined(); expect(result.isError).toBe(false); }); it("should provide health components and scoring", async () => { const readmePath = await createReadmeFile(`# Complete Project ## Description Detailed description ## Installation Installation steps ## Usage Usage examples ## Contributing Contributing guidelines ## License MIT License`); const result = await evaluateReadmeHealth({ readme_path: readmePath, }); const dataContent = result.content.find((c) => c.text.includes("healthReport"), ); const data = JSON.parse(dataContent!.text); expect(data.healthReport.overallScore).toBeGreaterThanOrEqual(0); expect(data.healthReport.grade).toBeDefined(); expect(data.healthReport.components).toBeDefined(); }); }); describe("readme_best_practices", () => { it("should analyze README best practices", async () => { const readmePath = await createReadmeFile("Basic library README"); const result = await readmeBestPractices({ readme_path: readmePath, project_type: "library", }); expect(result.success).toBe(true); expect(result.data).toBeDefined(); expect(result.data!.bestPracticesReport).toBeDefined(); }); it("should handle template generation", async () => { const outputDir = await createTempDir("best-practices-template"); const result = await readmeBestPractices({ readme_path: path.join(outputDir, "missing.md"), generate_template: true, output_directory: outputDir, project_type: "application", }); expect(result.success).toBe(true); expect(result.data).toBeDefined(); }); it("should provide checklist and recommendations", async () => { const readmePath = await createReadmeFile(`# Library Project ## Installation npm install my-lib ## Usage Basic usage here ## API API documentation `); const result = await readmeBestPractices({ readme_path: readmePath, }); expect(result.success).toBe(true); expect(result.data!.bestPracticesReport.checklist).toBeDefined(); expect(Array.isArray(result.data!.bestPracticesReport.checklist)).toBe( true, ); expect(result.data!.recommendations).toBeDefined(); expect(result.data!.nextSteps).toBeDefined(); }); }); // Helper functions async function createJSRepo(): Promise<string> { const repoPath = path.join(tempDir, `js-repo-${Date.now()}`); await fs.mkdir(repoPath, { recursive: true }); await fs.writeFile( path.join(repoPath, "package.json"), JSON.stringify( { name: "test-js-project", dependencies: { express: "^4.0.0" }, devDependencies: { jest: "^29.0.0" }, }, null, 2, ), ); await fs.writeFile( path.join(repoPath, "index.js"), 'console.log("Hello");', ); await fs.writeFile(path.join(repoPath, "README.md"), "# JS Project"); return repoPath; } async function createPythonRepo(): Promise<string> { const repoPath = path.join(tempDir, `py-repo-${Date.now()}`); await fs.mkdir(repoPath, { recursive: true }); await fs.writeFile(path.join(repoPath, "requirements.txt"), "flask>=2.0.0"); await fs.writeFile(path.join(repoPath, "main.py"), 'print("Hello")'); await fs.writeFile(path.join(repoPath, "README.md"), "# Python Project"); return repoPath; } async function createRepoWithCI(): Promise<string> { const repoPath = path.join(tempDir, `ci-repo-${Date.now()}`); await fs.mkdir(path.join(repoPath, ".github", "workflows"), { recursive: true, }); await fs.writeFile( path.join(repoPath, ".github", "workflows", "ci.yml"), "name: CI\non: push", ); await fs.writeFile(path.join(repoPath, "README.md"), "# CI Project"); return repoPath; } async function createEmptyRepo(): Promise<string> { const repoPath = path.join(tempDir, `empty-repo-${Date.now()}`); await fs.mkdir(repoPath, { recursive: true }); await fs.writeFile(path.join(repoPath, "README.md"), "# Empty Project"); return repoPath; } async function createTempDir(suffix: string): Promise<string> { const dirPath = path.join(tempDir, `${suffix}-${Date.now()}`); await fs.mkdir(dirPath, { recursive: true }); return dirPath; } async function createCompleteRepo(): Promise<string> { const repoPath = await createTempDir("complete-repo"); // Create workflow await fs.mkdir(path.join(repoPath, ".github", "workflows"), { recursive: true, }); await fs.writeFile( path.join(repoPath, ".github", "workflows", "deploy.yml"), "name: Deploy\non: push", ); // Create docs await fs.mkdir(path.join(repoPath, "docs"), { recursive: true }); await fs.writeFile(path.join(repoPath, "docs", "index.md"), "# Docs"); // Create config await fs.writeFile( path.join(repoPath, "docusaurus.config.js"), "module.exports = {};", ); // Create build output await fs.mkdir(path.join(repoPath, "build"), { recursive: true }); await fs.writeFile( path.join(repoPath, "build", "index.html"), "<html></html>", ); return repoPath; } async function fileExists(filePath: string): Promise<boolean> { try { await fs.access(filePath); return true; } catch { return false; } } async function createReadmeFile(content: string): Promise<string> { const file = tmp.fileSync({ postfix: ".md", keep: false }); await fs.writeFile(file.name, content); return file.name; } });

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