Skip to main content
Glama
comprehensive-validation.js11.8 kB
#!/usr/bin/env node /** * Comprehensive Validation Test Suite * Tests all 26 Mermaid diagram types with valid and invalid examples * Author: Gregorio Elias Roecker Momm */ const http = require('http'); const fs = require('fs'); const path = require('path'); const API_HOST = process.env.API_HOST || 'localhost'; const API_PORT = process.env.API_PORT || 8000; const COLORS = { RED: '\x1b[31m', GREEN: '\x1b[32m', YELLOW: '\x1b[33m', BLUE: '\x1b[34m', NC: '\x1b[0m' }; function log(message, color = COLORS.NC) { console.log(`${color}${message}${COLORS.NC}`); } /** * Test cases with both valid and invalid examples */ const validTestCases = [ { name: 'Flowchart', type: 'flowchart', valid: `flowchart TD A[Start] --> B{Decision} B -->|Yes| C[Process] B -->|No| D[End]`, invalid: `flowchart TD A[Start] --> Invalid syntax here` }, { name: 'C4 Context', type: 'C4Context', valid: `C4Context title System Context Person(customer, "Customer", "A user of the system") System(banking_system, "Banking System", "Handles transactions") Rel(customer, banking_system, "Uses")`, invalid: `C4Context title System Context Person(customer "Customer") InvalidSyntax --> here` }, { name: 'Example Diagram', type: 'exampleDiagram', valid: `example-diagram showInfo`, invalid: `example-diagram invalidCommand syntax error` }, { name: 'Tree Map', type: 'treemap', valid: `treemap-beta Root Branch1 Leaf1 Leaf2 Branch2 Leaf3`, invalid: `treemap-beta Root Branch1 --> Invalid syntax` }, { name: 'Requirement Diagram', type: 'requirementDiagram', valid: `requirementDiagram requirement test_req { id: 1 text: the test text risk: high verifymethod: test }`, invalid: `requirementDiagram requirement invalid { invalidProperty: value syntax error here` }, { name: 'Quadrant Chart', type: 'quadrantChart', valid: `quadrantChart title Reach and engagement x-axis Low Reach --> High Reach y-axis Low Engagement --> High Engagement quadrant-1 We should expand Campaign A: [0.3, 0.6]`, invalid: `quadrantChart title Test x-axis Invalid --> syntax error here` } ]; /** * Test single validation */ async function testValidation(diagram, expectValid = true) { return new Promise((resolve, reject) => { const data = JSON.stringify({ diagrams: [{ content: diagram.content, type: diagram.type }], options: { } }); const options = { hostname: API_HOST, port: API_PORT, path: '/api/v1/validate', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) } }; const req = http.request(options, (res) => { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => { try { const response = JSON.parse(body); const result = response.results?.[0]; const actualValid = result?.valid === true; resolve({ success: actualValid === expectValid, actualValid, expectValid, errors: result?.errors || [], response: response }); } catch (error) { reject(error); } }); }); req.on('error', reject); req.write(data); req.end(); }); } /** * Create test file with all 26 diagram types */ function createTestFile() { const testContent = `# All 26 Mermaid Diagram Types Test File ## 1. Flowchart \`\`\`mermaid flowchart TD A[Start] --> B{Decision} B -->|Yes| C[End] \`\`\` ## 2. Sequence Diagram \`\`\`mermaid sequenceDiagram Alice->>Bob: Hello Bob-->>Alice: Hi \`\`\` ## 3. Class Diagram \`\`\`mermaid classDiagram class Animal { +String name +makeSound() } \`\`\` ## 4. State Diagram \`\`\`mermaid stateDiagram-v2 [*] --> Idle Idle --> Working Working --> [*] \`\`\` ## 5. Entity Relationship \`\`\`mermaid erDiagram CUSTOMER ||--o{ ORDER : places \`\`\` ## 6. Gantt Chart \`\`\`mermaid gantt title Project Schedule section Planning Research :a1, 2024-01-01, 30d \`\`\` ## 7. User Journey \`\`\`mermaid journey title My working day section Go to work Make tea: 5: Me \`\`\` ## 8. Git Graph \`\`\`mermaid gitGraph commit branch develop commit \`\`\` ## 9. Pie Chart \`\`\`mermaid pie title Pets "Dogs" : 386 "Cats" : 85 \`\`\` ## 10. Quadrant Chart \`\`\`mermaid quadrantChart title Reach and engagement x-axis Low --> High y-axis Low --> High Campaign A: [0.3, 0.6] \`\`\` ## 11. Requirement Diagram \`\`\`mermaid requirementDiagram requirement test_req { id: 1 text: the test text risk: high verifymethod: test } \`\`\` ## 12. Mind Map \`\`\`mermaid mindmap root((mindmap)) Origins Long history Research \`\`\` ## 13. Timeline \`\`\`mermaid timeline title Timeline 2020 : Event 1 2021 : Event 2 \`\`\` ## 14. ZenUML \`\`\`mermaid zenuml Alice->Bob: Hello Bob->Alice: Hi \`\`\` ## 15. Sankey \`\`\`mermaid sankey-beta Coal,Electricity,10 Solar,Electricity,5 \`\`\` ## 16. XY Chart \`\`\`mermaid xychart-beta title "Sales Revenue" x-axis [jan, feb, mar] y-axis "Revenue" 0 --> 10000 bar [5000, 6000, 7500] \`\`\` ## 17. Block Diagram \`\`\`mermaid block-beta columns 2 A B C \`\`\` ## 18. Packet Diagram \`\`\`mermaid packet-beta 0-7: Header 8-15: Length \`\`\` ## 19. Architecture \`\`\`mermaid architecture-beta group api(server)[API] group database[Database] api --> database \`\`\` ## 20. Kanban \`\`\`mermaid kanban Todo Task 1 Done Task 2 \`\`\` ## 21. C4 Context \`\`\`mermaid C4Context title System Context Person(customer, "Customer") System(system, "System") Rel(customer, system, "Uses") \`\`\` ## 22. Graph \`\`\`mermaid graph TD A --> B B --> C \`\`\` ## 23. Info \`\`\`mermaid info \`\`\` ## 24. Radar Chart \`\`\`mermaid radar title Skills "Skill A", 80 "Skill B", 60 \`\`\` ## 25. Tree Map \`\`\`mermaid treemap-beta Root Branch1 Leaf1 \`\`\` ## 26. Example Diagram \`\`\`mermaid example-diagram showInfo \`\`\` `; const testDir = path.join(__dirname, 'test-files'); if (!fs.existsSync(testDir)) { fs.mkdirSync(testDir, { recursive: true }); } fs.writeFileSync(path.join(testDir, 'all-26-diagrams.md'), testContent); return path.join(testDir, 'all-26-diagrams.md'); } /** * Test file upload with all 26 diagram types */ async function testFileUpload(filePath) { return new Promise((resolve, reject) => { const FormData = require('form-data'); const form = new FormData(); form.append('file', fs.createReadStream(filePath)); form.append('generateSvg', 'false'); const options = { hostname: API_HOST, port: API_PORT, path: '/api/v1/upload/file', method: 'POST', headers: form.getHeaders() }; const req = http.request(options, (res) => { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => { try { resolve({ statusCode: res.statusCode, body: JSON.parse(body) }); } catch (error) { reject(error); } }); }); req.on('error', reject); form.pipe(req); }); } /** * Main test runner */ async function main() { log('Comprehensive Validation Test Suite', COLORS.BLUE); log('====================================\n', COLORS.BLUE); // Test individual valid/invalid cases log('=== Testing Valid Examples ===', COLORS.BLUE); let validPassed = 0; let validFailed = 0; for (const testCase of validTestCases) { process.stdout.write(`Testing ${testCase.name} (valid)... `); try { const result = await testValidation({ content: testCase.valid, type: testCase.type }, true); if (result.success) { log('✓', COLORS.GREEN); validPassed++; } else { log(`✗ (Expected valid, got ${result.actualValid})`, COLORS.RED); validFailed++; } } catch (error) { log(`✗ (${error.message})`, COLORS.RED); validFailed++; } } log('\\n=== Testing Invalid Examples ===', COLORS.BLUE); let invalidPassed = 0; let invalidFailed = 0; for (const testCase of validTestCases) { process.stdout.write(`Testing ${testCase.name} (invalid)... `); try { const result = await testValidation({ content: testCase.invalid, type: testCase.type }, false); if (result.success) { log('✓', COLORS.GREEN); invalidPassed++; } else { log(`✗ (Expected invalid, got ${result.actualValid})`, COLORS.RED); invalidFailed++; } } catch (error) { log(`✗ (${error.message})`, COLORS.RED); invalidFailed++; } } // Test file upload log('\\n=== Testing File Upload with All 26 Types ===', COLORS.BLUE); const testFile = createTestFile(); try { const uploadResult = await testFileUpload(testFile); if (uploadResult.statusCode === 200) { const { totalDiagrams, validDiagrams, invalidDiagrams } = uploadResult.body; log(`✓ File upload successful: ${validDiagrams}/${totalDiagrams} valid`, COLORS.GREEN); // Show per-diagram results if (uploadResult.body.results) { uploadResult.body.results.forEach(result => { const status = result.valid ? '✓' : '✗'; const color = result.valid ? COLORS.GREEN : COLORS.RED; log(` ${status} ${result.metadata?.diagramType}: ${result.valid ? 'Valid' : result.errors?.[0]?.message || 'Invalid'}`, color); }); } } else { log(`✗ File upload failed: ${uploadResult.statusCode}`, COLORS.RED); } } catch (error) { log(`✗ File upload error: ${error.message}`, COLORS.RED); } // Summary log('\\n=== COMPREHENSIVE TEST SUMMARY ===', COLORS.BLUE); log(`Valid Examples: ${validPassed}/${validTestCases.length} passed`, validPassed === validTestCases.length ? COLORS.GREEN : COLORS.YELLOW); log(`Invalid Examples: ${invalidPassed}/${validTestCases.length} passed`, invalidPassed === validTestCases.length ? COLORS.GREEN : COLORS.YELLOW); const totalTests = validPassed + invalidPassed; const totalPossible = validTestCases.length * 2; log(`Overall: ${totalTests}/${totalPossible} tests passed (${Math.round(totalTests/totalPossible*100)}%)`, totalTests === totalPossible ? COLORS.GREEN : COLORS.YELLOW); // Cleanup fs.rmSync(path.dirname(testFile), { recursive: true, force: true }); process.exit(totalTests === totalPossible ? 0 : 1); } /** * Make HTTP request */ function makeRequest(options, data) { return new Promise((resolve, reject) => { const req = http.request(options, (res) => { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => { try { resolve({ statusCode: res.statusCode, body: body ? JSON.parse(body) : null }); } catch (error) { reject(new Error(`Failed to parse response: ${error.message}`)); } }); }); req.on('error', reject); if (data) { req.write(JSON.stringify(data)); } req.end(); }); } // Run tests if (require.main === module) { main().catch(error => { log(`Fatal error: ${error.message}`, COLORS.RED); process.exit(1); }); }

Latest Blog Posts

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/ai-of-mine/fast-mermaid-validator-mcp'

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