Skip to main content
Glama
test-validation-tools.js13.8 kB
#!/usr/bin/env node /** * Test suite for ECL Validation Tools (Phase 4) * Tests all validation and diagnostic functions */ import { getDatabase, closeDatabase } from './src/db.js'; import * as Validation from './src/validation/index.js'; // Test data const testCases = { // Valid ECL button HTML validButton: ` <button type="button" class="ecl-button ecl-button--primary" aria-label="Submit form"> <span class="ecl-button__container"> <span class="ecl-button__label">Submit</span> </span> </button> `, // Invalid button (missing type, improper structure) invalidButton: ` <button class="ecl-button ecl-button--primary"> Submit </button> `, // Valid card with accessibility validCard: ` <article class="ecl-card" data-ecl-auto-init="Card"> <div class="ecl-card__image"> <img src="image.jpg" alt="Card image description" class="ecl-card__image-element"> </div> <div class="ecl-card__body"> <h3 class="ecl-card__title"> <a href="#" class="ecl-card__link">Card Title</a> </h3> <p class="ecl-card__description">Card description text here.</p> </div> </article> `, // Invalid card (missing alt text, no init) invalidCard: ` <div class="ecl-card"> <div class="ecl-card__image"> <img src="image.jpg" class="ecl-card__image-element"> </div> <div class="ecl-card__body"> <div class="ecl-card__title"> <a href="#">Card Title</a> </div> </div> </div> `, // Accessibility test cases goodAccessibility: ` <nav aria-label="Main navigation"> <ul> <li><a href="#main" class="ecl-link">Skip to main content</a></li> </ul> </nav> <main id="main"> <h1>Page Title</h1> <form> <label for="name">Name</label> <input type="text" id="name" name="name" required> <label for="email">Email</label> <input type="email" id="email" name="email" required> <button type="submit" class="ecl-button ecl-button--primary">Submit</button> </form> </main> `, poorAccessibility: ` <div onclick="navigate()"> <div>Page Title</div> <form> <input type="text" placeholder="Name"> <input type="text" placeholder="Email"> <div class="button" onclick="submit()">Submit</div> </form> </div> `, // Code analysis test fullEclPage: ` <!DOCTYPE html> <html lang="en"> <head> <link rel="stylesheet" href="ecl.css"> <style> .custom { color: #003399; margin: 16px; } </style> </head> <body> <header class="ecl-site-header" data-ecl-auto-init="SiteHeader"> <div class="ecl-site-header__container"> <a href="#" class="ecl-site-header__logo"> <img src="logo.svg" alt="Europa" /> </a> </div> </header> <main class="ecl-u-mt-l ecl-u-mb-l"> <div class="ecl-container"> <button type="button" class="ecl-button ecl-button--primary"> Click me </button> <div class="ecl-card" data-ecl-auto-init="Card"> <div class="ecl-card__body"> <h3 class="ecl-card__title">Card</h3> </div> </div> </div> </main> <script> ECL.autoInit(); </script> </body> </html> `, // JavaScript with good patterns goodJs: ` // Initialize ECL components ECL.autoInit(); // Event delegation document.addEventListener('click', function(e) { if (e.target.matches('.ecl-button')) { handleButtonClick(e.target); } }); `, // JavaScript with issues poorJs: ` // Direct DOM manipulation document.querySelector('.card').innerHTML = '<div>New content</div>'; document.getElementById('test').innerHTML = '<span>More</span>'; // Direct event handlers document.querySelector('.button').onclick = function() { alert('clicked'); }; document.querySelector('.link').onclick = function() { return false; }; // Manual init without checking ECL.Button.init(document.querySelector('.ecl-button')); // More DOM manipulation document.querySelector('.header').style.color = 'red'; `, // CSS with design tokens goodCss: ` .custom-component { color: var(--ecl-color-primary); padding: var(--ecl-spacing-m); font-family: var(--ecl-font-family); } `, // CSS with hardcoded values poorCss: ` .custom-component { color: #003399 !important; background: #ff0000 !important; padding: 16px !important; margin: 24px !important; font-family: Arial, sans-serif !important; font-size: 14px !important; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } ` }; // Test runner async function runTests() { console.log('🧪 ECL Validation Tools Test Suite\n'); console.log('='.repeat(60)); const db = getDatabase(true); let passed = 0; let failed = 0; try { // Test 1: Valid button validation console.log('\n📝 Test 1: Valid Button Validation'); const test1 = await Validation.validateComponentUsage( db, 'button', testCases.validButton ); if (test1.success && test1.data.is_valid && test1.data.score >= 90) { console.log('✅ PASS - Valid button scores high'); passed++; } else { console.log('❌ FAIL - Valid button should pass validation'); console.log('Score:', test1.data.score); console.log('Errors:', test1.data.errors); failed++; } // Test 2: Invalid button validation console.log('\n📝 Test 2: Invalid Button Validation'); const test2 = await Validation.validateComponentUsage( db, 'button', testCases.invalidButton ); if (test2.success && !test2.data.is_valid && test2.data.errors.length > 0) { console.log('✅ PASS - Invalid button detected errors'); console.log(' Errors found:', test2.data.errors.length); passed++; } else { console.log('❌ FAIL - Invalid button should have errors'); failed++; } // Test 3: Valid card validation console.log('\n📝 Test 3: Valid Card Validation'); const test3 = await Validation.validateComponentUsage( db, 'card', testCases.validCard ); if (test3.success && test3.data.score >= 85) { console.log('✅ PASS - Valid card scores high'); console.log(' Score:', test3.data.score); passed++; } else { console.log('❌ FAIL - Valid card should score 85+'); console.log('Score:', test3.data.score); console.log('Errors:', test3.data.errors); failed++; } // Test 4: Invalid card validation console.log('\n📝 Test 4: Invalid Card Validation'); const test4 = await Validation.validateComponentUsage( db, 'card', testCases.invalidCard ); if (test4.success && test4.data.errors.length >= 2) { console.log('✅ PASS - Invalid card has multiple errors'); console.log(' Errors:', test4.data.errors.map(e => e.message).join(', ')); passed++; } else { console.log('❌ FAIL - Invalid card should have 2+ errors'); console.log('Errors:', test4.data.errors); failed++; } // Test 5: Good accessibility check console.log('\n📝 Test 5: Good Accessibility Check (WCAG AA)'); const test5 = await Validation.checkAccessibility( db, testCases.goodAccessibility, null, 'AA' ); if (test5.success && test5.data.wcag_aa_compliant) { console.log('✅ PASS - Good HTML is WCAG AA compliant'); console.log(' Level A:', test5.data.wcag_a_compliant ? '✓' : '✗'); console.log(' Level AA:', test5.data.wcag_aa_compliant ? '✓' : '✗'); passed++; } else { console.log('❌ FAIL - Good HTML should be WCAG AA compliant'); console.log('Issues:', test5.data?.issues || []); console.log('Success:', test5.success); console.log('AA Compliant:', test5.data?.wcag_aa_compliant); failed++; } // Test 6: Poor accessibility check console.log('\n📝 Test 6: Poor Accessibility Check'); const test6 = await Validation.checkAccessibility( db, testCases.poorAccessibility, null, 'AA' ); if (test6.success && !test6.data.wcag_aa_compliant && test6.data.issues.length > 0) { console.log('✅ PASS - Poor HTML fails WCAG compliance'); console.log(' Critical issues:', test6.data.issues.filter(e => e.severity === 'critical').length); console.log(' Serious issues:', test6.data.issues.filter(e => e.severity === 'serious').length); passed++; } else { console.log('❌ FAIL - Poor HTML should fail WCAG compliance'); failed++; } // Test 7: Code analysis - component detection console.log('\n📝 Test 7: Code Analysis - Component Detection'); const test7 = await Validation.analyzeEclCode( db, testCases.fullEclPage, testCases.goodJs ); if (test7.success && test7.data.components_detected.length >= 2) { console.log('✅ PASS - Detected multiple components'); console.log(' Components:', test7.data.components_detected.map(c => c.name).join(', ')); console.log(' Quality score:', test7.data.overall_quality_score); passed++; } else { console.log('❌ FAIL - Should detect 2+ components'); console.log('Detected:', test7.data.components_detected); failed++; } // Test 8: Code analysis - design tokens console.log('\n📝 Test 8: Code Analysis - Design Token Detection'); const test8 = await Validation.analyzeEclCode( db, testCases.fullEclPage, testCases.goodJs, testCases.goodCss ); if (test8.success && test8.data.design_tokens_used.length > 0) { console.log('✅ PASS - Detected design tokens'); console.log(' Tokens:', test8.data.design_tokens_used.length); passed++; } else { console.log('❌ FAIL - Should detect design tokens'); failed++; } // Test 9: Code analysis - quality issues console.log('\n📝 Test 9: Code Analysis - Quality Issues Detection'); const test9 = await Validation.analyzeEclCode( db, testCases.fullEclPage.replace('ecl-u-mt-l', 'custom').replace('data-ecl-auto-init', ''), testCases.poorJs, testCases.poorCss ); if (test9.success && test9.data.overall_quality_score < 80) { console.log('✅ PASS - Poor code has low quality score'); console.log(' Score:', test9.data.overall_quality_score); console.log(' Issues:', test9.data.maintainability.issues.length); passed++; } else { console.log('❌ FAIL - Poor code should have low quality score'); console.log('Score:', test9.data.overall_quality_score); failed++; } // Test 10: Conflict detection console.log('\n📝 Test 10: Component Conflict Detection'); const test10 = await Validation.checkConflicts( db, ['modal', 'message', 'accordion', 'tabs'] ); if (test10.success && (test10.data.conflicts.length > 0 || test10.data.warnings.length > 0)) { console.log('✅ PASS - Detected potential conflicts'); console.log(' Conflicts:', test10.data.conflicts.length); console.log(' Warnings:', test10.data.warnings.length); passed++; } else { console.log('❌ FAIL - Should detect at least warnings'); console.log('Result:', test10.data); failed++; } // Test 11: Performance check console.log('\n📝 Test 11: Performance Check'); const startTime = Date.now(); await Validation.validateComponentUsage(db, 'button', testCases.validButton); await Validation.checkAccessibility(db, testCases.goodAccessibility); await Validation.analyzeEclCode(db, testCases.fullEclPage); const endTime = Date.now(); const totalTime = endTime - startTime; if (totalTime < 500) { console.log('✅ PASS - All validations under 500ms'); console.log(' Total time:', totalTime + 'ms'); passed++; } else { console.log('⚠️ SLOW - Validations took longer than expected'); console.log(' Total time:', totalTime + 'ms'); console.log(' (Not counted as failure)'); passed++; } // Test 12: Error handling console.log('\n📝 Test 12: Error Handling'); const test12 = await Validation.validateComponentUsage( db, 'nonexistent-component', '<div>test</div>' ); if (test12.success === false && test12.errors && test12.errors.length > 0) { console.log('✅ PASS - Handles invalid component gracefully'); console.log(' Error:', test12.errors[0].message); passed++; } else { console.log('❌ FAIL - Should handle errors gracefully'); failed++; } } catch (error) { console.error('\n❌ Test suite error:', error); failed++; } finally { closeDatabase(db); } // Summary console.log('\n' + '='.repeat(60)); console.log('📊 Test Results Summary\n'); console.log(`Total tests: ${passed + failed}`); console.log(`✅ Passed: ${passed}`); console.log(`❌ Failed: ${failed}`); console.log(`Success rate: ${((passed / (passed + failed)) * 100).toFixed(1)}%`); if (failed === 0) { console.log('\n🎉 All tests passed!'); process.exit(0); } else { console.log('\n⚠️ Some tests failed. Review output above.'); process.exit(1); } } // Run tests runTests().catch(error => { console.error('Fatal error:', error); process.exit(1); });

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/brownrl/eco_mcp'

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