Skip to main content
Glama

documcp

by tosin2013
all-tools.test.ts19.5 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