#!/usr/bin/env node const { execSync } = require('child_process'); const fs = require('fs'); const path = require('path'); const COLORS = { reset: '\x1b[0m', bright: '\x1b[1m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', magenta: '\x1b[35m', cyan: '\x1b[36m', }; function log(message, color = COLORS.reset) { console.log(`${color}${message}${COLORS.reset}`); } function logStep(step, message) { console.log(`\n${COLORS.cyan}[${step}]${COLORS.reset} ${message}`); } function logSuccess(message) { console.log(`${COLORS.green}✅${COLORS.reset} ${message}`); } function logError(message) { console.log(`${COLORS.red}❌${COLORS.reset} ${message}`); } function logWarning(message) { console.log(`${COLORS.yellow}⚠️${COLORS.reset} ${message}`); } function executeCommand(command, description) { try { logStep('EXEC', description); const result = execSync(command, { encoding: 'utf8', stdio: 'inherit' }); logSuccess(description); return true; } catch (error) { logError(`${description} failed: ${error.message}`); return false; } } function runUnitTests() { logStep(1, 'Running Unit Tests'); try { const testResults = { server: runServerUnitTests(), dashboard: runDashboardUnitTests(), client: runClientUnitTests(), extension: runExtensionUnitTests() }; const totalTests = Object.values(testResults).reduce((sum, result) => sum + result.total, 0); const passedTests = Object.values(testResults).reduce((sum, result) => sum + result.passed, 0); const failedTests = Object.values(testResults).reduce((sum, result) => sum + result.failed, 0); console.log(`\n${COLORS.cyan}Unit Tests Summary:${COLORS.reset}`); console.log(` Total: ${totalTests}`); console.log(` ${COLORS.green}Passed: ${passedTests}${COLORS.reset}`); console.log(` ${COLORS.red}Failed: ${failedTests}${COLORS.reset}`); console.log(` Success Rate: ${((passedTests / totalTests) * 100).toFixed(2)}%`); return failedTests === 0; } catch (error) { logError(`Unit tests failed: ${error.message}`); return false; } } function runServerUnitTests() { try { const output = execSync('cd server && npm test -- --coverage --json', { encoding: 'utf8', stdio: 'pipe' }); const results = JSON.parse(output); const total = results.numTotalTests; const passed = results.numPassedTests; const failed = results.numFailedTests; console.log(`\n${COLORS.cyan}Server Unit Tests:${COLORS.reset}`); console.log(` Total: ${total}, Passed: ${passed}, Failed: ${failed}`); console.log(` Coverage: ${results.coverageMap ? 'Generated' : 'Not available'}`); return { total, passed, failed }; } catch (error) { logError('Server unit tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runDashboardUnitTests() { try { const output = execSync('cd dashboard && npm test -- --coverage --json', { encoding: 'utf8', stdio: 'pipe' }); const results = JSON.parse(output); const total = results.numTotalTests; const passed = results.numPassedTests; const failed = results.numFailedTests; console.log(`\n${COLORS.cyan}Dashboard Unit Tests:${COLORS.reset}`); console.log(` Total: ${total}, Passed: ${passed}, Failed: ${failed}`); console.log(` Coverage: ${results.coverageMap ? 'Generated' : 'Not available'}`); return { total, passed, failed }; } catch (error) { logError('Dashboard unit tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runClientUnitTests() { try { const output = execSync('cd client && npm test -- --coverage --json', { encoding: 'utf8', stdio: 'pipe' }); const results = JSON.parse(output); const total = results.numTotalTests; const passed = results.numPassedTests; const failed = results.numFailedTests; console.log(`\n${COLORS.cyan}Client Unit Tests:${COLORS.reset}`); console.log(` Total: ${total}, Passed: ${passed}, Failed: ${failed}`); console.log(` Coverage: ${results.coverageMap ? 'Generated' : 'Not available'}`); return { total, passed, failed }; } catch (error) { logError('Client unit tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runExtensionUnitTests() { try { const output = execSync('cd extension && npm test -- --coverage --json', { encoding: 'utf8', stdio: 'pipe' }); const results = JSON.parse(output); const total = results.numTotalTests; const passed = results.numPassedTests; const failed = results.numFailedTests; console.log(`\n${COLORS.cyan}Extension Unit Tests:${COLORS.reset}`); console.log(` Total: ${total}, Passed: ${passed}, Failed: ${failed}`); console.log(` Coverage: ${results.coverageMap ? 'Generated' : 'Not available'}`); return { total, passed, failed }; } catch (error) { logError('Extension unit tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runIntegrationTests() { logStep(2, 'Running Integration Tests'); try { const testResults = { api: runAPIIntegrationTests(), database: runDatabaseIntegrationTests(), redis: runRedisIntegrationTests(), websocket: runWebSocketIntegrationTests() }; const totalTests = Object.values(testResults).reduce((sum, result) => sum + result.total, 0); const passedTests = Object.values(testResults).reduce((sum, result) => sum + result.passed, 0); const failedTests = Object.values(testResults).reduce((sum, result) => sum + result.failed, 0); console.log(`\n${COLORS.cyan}Integration Tests Summary:${COLORS.reset}`); console.log(` Total: ${totalTests}`); console.log(` ${COLORS.green}Passed: ${passedTests}${COLORS.reset}`); console.log(` ${COLORS.red}Failed: ${failedTests}${COLORS.reset}`); console.log(` Success Rate: ${((passedTests / totalTests) * 100).toFixed(2)}%`); return failedTests === 0; } catch (error) { logError(`Integration tests failed: ${error.message}`); return false; } } function runAPIIntegrationTests() { try { const output = execSync('cd server && npm run test:integration', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}API Integration Tests:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('API integration tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runDatabaseIntegrationTests() { try { const output = execSync('cd server && npm run test:database', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}Database Integration Tests:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('Database integration tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runRedisIntegrationTests() { try { const output = execSync('cd server && npm run test:redis', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}Redis Integration Tests:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('Redis integration tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runWebSocketIntegrationTests() { try { const output = execSync('cd server && npm run test:websocket', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}WebSocket Integration Tests:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('WebSocket integration tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function parseTestOutput(output) { const lines = output.split('\n'); let total = 0, passed = 0, failed = 0; lines.forEach(line => { const totalMatch = line.match(/Tests:\s+(\d+)/); const passedMatch = line.match(/Passed:\s+(\d+)/); const failedMatch = line.match(/Failed:\s+(\d+)/); if (totalMatch) total = parseInt(totalMatch[1]); if (passedMatch) passed = parseInt(passedMatch[1]); if (failedMatch) failed = parseInt(failedMatch[1]); }); return { total, passed, failed }; } function runE2ETests() { logStep(3, 'Running End-to-End Tests'); try { const testResults = { userFlow: runUserFlowTests(), businessFlow: runBusinessFlowTests(), adminFlow: runAdminFlowTests() }; const totalTests = Object.values(testResults).reduce((sum, result) => sum + result.total, 0); const passedTests = Object.values(testResults).reduce((sum, result) => sum + result.passed, 0); const failedTests = Object.values(testResults).reduce((sum, result) => sum + result.failed, 0); console.log(`\n${COLORS.cyan}E2E Tests Summary:${COLORS.reset}`); console.log(` Total: ${totalTests}`); console.log(` ${COLORS.green}Passed: ${passedTests}${COLORS.reset}`); console.log(` ${COLORS.red}Failed: ${failedTests}${COLORS.reset}`); console.log(` Success Rate: ${((passedTests / totalTests) * 100).toFixed(2)}%`); return failedTests === 0; } catch (error) { logError(`E2E tests failed: ${error.message}`); return false; } } function runUserFlowTests() { try { const output = execSync('cd dashboard && npm run test:e2e:user', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}User Flow Tests:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('User flow tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runBusinessFlowTests() { try { const output = execSync('cd dashboard && npm run test:e2e:business', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}Business Flow Tests:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('Business flow tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runAdminFlowTests() { try { const output = execSync('cd dashboard && npm run test:e2e:admin', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}Admin Flow Tests:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('Admin flow tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runPerformanceTests() { logStep(4, 'Running Performance Tests'); try { const testResults = { load: runLoadTests(), stress: runStressTests(), endurance: runEnduranceTests() }; const totalTests = Object.values(testResults).reduce((sum, result) => sum + result.total, 0); const passedTests = Object.values(testResults).reduce((sum, result) => sum + result.passed, 0); const failedTests = Object.values(testResults).reduce((sum, result) => sum + result.failed, 0); console.log(`\n${COLORS.cyan}Performance Tests Summary:${COLORS.reset}`); console.log(` Total: ${totalTests}`); console.log(` ${COLORS.green}Passed: ${passedTests}${COLORS.reset}`); console.log(` ${COLORS.red}Failed: ${failedTests}${COLORS.reset}`); console.log(` Success Rate: ${((passedTests / totalTests) * 100).toFixed(2)}%`); return failedTests === 0; } catch (error) { logError(`Performance tests failed: ${error.message}`); return false; } } function runLoadTests() { try { const output = execSync('cd server && npm run test:load', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}Load Tests:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('Load tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runStressTests() { try { const output = execSync('cd server && npm run test:stress', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}Stress Tests:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('Stress tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runEnduranceTests() { try { const output = execSync('cd server && npm run test:endurance', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}Endurance Tests:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('Endurance tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runSecurityTests() { logStep(5, 'Running Security Tests'); try { const testResults = { vulnerability: runVulnerabilityTests(), penetration: runPenetrationTests(), compliance: runComplianceTests() }; const totalTests = Object.values(testResults).reduce((sum, result) => sum + result.total, 0); const passedTests = Object.values(testResults).reduce((sum, result) => sum + result.passed, 0); const failedTests = Object.values(testResults).reduce((sum, result) => sum + result.failed, 0); console.log(`\n${COLORS.cyan}Security Tests Summary:${COLORS.reset}`); console.log(` Total: ${totalTests}`); console.log(` ${COLORS.green}Passed: ${passedTests}${COLORS.reset}`); console.log(` ${COLORS.red}Failed: ${failedTests}${COLORS.reset}`); console.log(` Success Rate: ${((passedTests / totalTests) * 100).toFixed(2)}%`); return failedTests === 0; } catch (error) { logError(`Security tests failed: ${error.message}`); return false; } } function runVulnerabilityTests() { try { const output = execSync('npm audit --json', { encoding: 'utf8', stdio: 'pipe' }); const results = JSON.parse(output); const vulnerabilities = results.vulnerabilities || {}; const total = Object.values(vulnerabilities).reduce((sum, vulns) => sum + vulns.length, 0); const critical = vulnerabilities.critical ? vulnerabilities.critical.length : 0; const high = vulnerabilities.high ? vulnerabilities.high.length : 0; const moderate = vulnerabilities.moderate ? vulnerabilities.moderate.length : 0; const low = vulnerabilities.low ? vulnerabilities.low.length : 0; const passed = total - (critical + high); const failed = critical + high; console.log(`\n${COLORS.cyan}Vulnerability Tests:${COLORS.reset}`); console.log(` Critical: ${critical}, High: ${high}, Moderate: ${moderate}, Low: ${low}`); console.log(` Total: ${total}, Passed: ${passed}, Failed: ${failed}`); return { total, passed, failed }; } catch (error) { logError('Vulnerability tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runPenetrationTests() { try { const output = execSync('cd server && npm run test:security', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}Penetration Tests:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('Penetration tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runComplianceTests() { try { const output = execSync('cd server && npm run test:compliance', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}Compliance Tests:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('Compliance tests failed'); return { total: 0, passed: 0, failed: 1 }; } } function runCodeQualityChecks() { logStep(6, 'Running Code Quality Checks'); try { const checkResults = { linting: runLintingChecks(), formatting: runFormattingChecks(), complexity: runComplexityChecks(), duplication: runDuplicationChecks() }; const totalChecks = Object.values(checkResults).reduce((sum, result) => sum + result.total, 0); const passedChecks = Object.values(checkResults).reduce((sum, result) => sum + result.passed, 0); const failedChecks = Object.values(checkResults).reduce((sum, result) => sum + result.failed, 0); console.log(`\n${COLORS.cyan}Code Quality Checks Summary:${COLORS.reset}`); console.log(` Total: ${totalChecks}`); console.log(` ${COLORS.green}Passed: ${passedChecks}${COLORS.reset}`); console.log(` ${COLORS.red}Failed: ${failedChecks}${COLORS.reset}`); console.log(` Success Rate: ${((passedChecks / totalChecks) * 100).toFixed(2)}%`); return failedChecks === 0; } catch (error) { logError(`Code quality checks failed: ${error.message}`); return false; } } function runLintingChecks() { try { const output = execSync('npm run lint -- --format json', { encoding: 'utf8', stdio: 'pipe' }); const results = JSON.parse(output); const total = results.length; const passed = results.filter(r => r.errorCount === 0 && r.warningCount === 0).length; const failed = total - passed; console.log(`\n${COLORS.cyan}Linting Checks:${COLORS.reset}`); console.log(` Total: ${total}, Passed: ${passed}, Failed: ${failed}`); return { total, passed, failed }; } catch (error) { logError('Linting checks failed'); return { total: 0, passed: 0, failed: 1 }; } } function runFormattingChecks() { try { const output = execSync('npm run format:check', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}Formatting Checks:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('Formatting checks failed'); return { total: 0, passed: 0, failed: 1 }; } } function runComplexityChecks() { try { const output = execSync('npm run complexity:check', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}Complexity Checks:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('Complexity checks failed'); return { total: 0, passed: 0, failed: 1 }; } } function runDuplicationChecks() { try { const output = execSync('npm run duplication:check', { encoding: 'utf8', stdio: 'pipe' }); const results = parseTestOutput(output); console.log(`\n${COLORS.cyan}Duplication Checks:${COLORS.reset}`); console.log(` Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`); return results; } catch (error) { logError('Duplication checks failed'); return { total: 0, passed: 0, failed: 1 }; } } function generateTestReport() { logStep(7, 'Generating Test Report'); const report = { timestamp: new Date().toISOString(), project: { name: 'Crawlful Hub', version: '1.0.0' }, summary: { totalTests: 0, passedTests: 0, failedTests: 0, skippedTests: 0, successRate: 0, duration: 0 }, categories: { unitTests: { total: 0, passed: 0, failed: 0, coverage: 0 }, integrationTests: { total: 0, passed: 0, failed: 0 }, e2eTests: { total: 0, passed: 0, failed: 0 }, performanceTests: { total: 0, passed: 0, failed: 0 }, securityTests: { total: 0, passed: 0, failed: 0 }, codeQualityChecks: { total: 0, passed: 0, failed: 0 } }, recommendations: [ 'Fix failing tests before deployment', 'Improve test coverage for critical paths', 'Add more integration tests', 'Implement automated security scanning', 'Set up continuous testing pipeline' ], nextSteps: [ 'Review test failures', 'Fix critical issues', 'Re-run failed tests', 'Update documentation', 'Prepare for deployment' ] }; const reportPath = path.join(process.cwd(), 'test-report.json'); fs.writeFileSync(reportPath, JSON.stringify(report, null, 2)); logSuccess(`Test report generated: ${reportPath}`); return true; } function main() { console.log(`${COLORS.bright}${COLORS.blue} ╔══════════════════════════════════════════════════════════╗ ║ ║ ║ CRAWLFUL HUB - COMPREHENSIVE TEST SUITE ║ ║ ║ ║ Complete Quality Assurance & Testing ║ ║ ║ ╚══════════════════════════════════════════════════════════╝ ${COLORS.reset}`); logStep('START', 'Starting comprehensive testing...\n'); const results = { unitTests: runUnitTests(), integrationTests: runIntegrationTests(), e2eTests: runE2ETests(), performanceTests: runPerformanceTests(), securityTests: runSecurityTests(), codeQualityChecks: runCodeQualityChecks(), reportGeneration: generateTestReport() }; console.log(`\n${COLORS.bright}${COLORS.blue} ══════════════════════════════════════════════════════════ TESTING COMPLETE ══════════════════════════════════════════════════════════ ${COLORS.reset}`); const successCount = Object.values(results).filter(Boolean).length; const totalCount = Object.keys(results).length; console.log(`\n${COLORS.cyan}Summary:${COLORS.reset}`); console.log(` ${COLORS.green}✅${COLORS.reset} Successful: ${successCount}/${totalCount}`); console.log(` ${COLORS.red}❌${COLORS.reset} Failed: ${totalCount - successCount}/${totalCount}`); if (successCount === totalCount) { logSuccess('🚀 All tests completed successfully!'); console.log(`\n${COLORS.yellow}Next Steps:${COLORS.reset}`); console.log(' 1. Review test-report.json'); console.log(' 2. Check test coverage reports'); console.log(' 3. Review performance metrics'); console.log(' 4. Address any warnings'); console.log(' 5. Prepare for deployment'); } else { logWarning('Some tests failed. Please review the errors above.'); console.log(`\n${COLORS.yellow}Action Items:${COLORS.reset}`); console.log(' 1. Review test failures'); console.log(' 2. Fix critical issues'); console.log(' 3. Re-run failed tests'); console.log(' 4. Update documentation'); } process.exit(successCount === totalCount ? 0 : 1); } if (require.main === module) { main(); } module.exports = { runUnitTests, runIntegrationTests, runE2ETests, runPerformanceTests, runSecurityTests, runCodeQualityChecks, generateTestReport };