UNPKG

reldens

Version:
210 lines (198 loc) 8.16 kB
/** * * Reldens - Admin Integration Test Runner * */ const { FileHandler } = require('@reldens/server-utils'); const { Logger, sc } = require('@reldens/utils'); const { DatabaseResetUtility } = require('./database-reset-utility'); const readline = require('readline'); Logger.activeLogLevels = [100]; Logger.setLogLevel(100); Logger.addTimeStamp = false; Logger.context().RELDENS_ENABLE_TRACE_FOR = 'none'; async function runTests() { try { await confirmTestExecution(); Logger.log(100, '', '='.repeat(60)); Logger.log(100, '', 'TESTING RELDENS ADMIN INTEGRATION'); Logger.log(100, '', '='.repeat(60)+'\n'); Logger.log(100, '', 'Test execution started: '+sc.formatDate(new Date())); let config = JSON.parse(process.argv[2] || '{}'); Logger.log(100, '', 'Resetting database before tests...'); let databaseResetUtility = new DatabaseResetUtility(config); let resetResult = await databaseResetUtility.resetDatabase(); if(!resetResult){ Logger.log(100, '', 'Database reset failed - aborting test execution'); process.exit(1); } Logger.log(100, '', 'Database reset completed successfully\n'); let testFiles = await getTestFilesFromDirectory(__dirname); let filter = null; let methodFilter = null; let breakOnError = false; for(let arg of process.argv){ if(arg.startsWith('--filter=')){ let filterValue = arg.split('=')[1]; if(filterValue.includes('::')){ let filterParts = filterValue.split('::'); filter = filterParts[0]; methodFilter = filterParts[1]; } if(!filterValue.includes('::')){ filter = filterValue; } } if(arg === '--break-on-error'){ breakOnError = true; } } testFiles = applyFilter(testFiles, filter); if(0 === testFiles.length){ let filterMsg = filter ? ' matching filter: '+filter : ''; Logger.log(100, '', 'No test files found in directory: '+__dirname+filterMsg); process.exit(1); } let totalTests = 0; let totalPassed = 0; for(let testFile of testFiles){ let testDisplayName = getTestDisplayName(testFile); Logger.log(100, '', 'Running '+testDisplayName+' ('+testFile+')'); let testModule = require(FileHandler.joinPaths(__dirname, testFile)); let TestClassName = Object.keys(testModule)[0]; if(!TestClassName){ Logger.log(100, '', 'No test class found in: '+testFile); continue; } let TestClass = testModule[TestClassName]; let testInstance = new TestClass(config); testInstance.breakOnError = breakOnError; let testMethods = getTestMethods(testInstance); if(methodFilter){ testMethods = testMethods.filter(methodName => methodName.includes(methodFilter)); } if(0 === testMethods.length){ let methodFilterMsg = methodFilter ? ' matching method filter: '+methodFilter : ''; Logger.log(100, '', 'No test methods found in: '+testFile+methodFilterMsg); continue; } for(let methodName of testMethods){ if('function' === typeof testInstance[methodName]){ let testFailed = false; try { await testInstance[methodName](); } catch(error){ testFailed = true; Logger.log(100, '', 'Test method failed: '+methodName+' - '+error.message); if(breakOnError){ Logger.log(100, '', 'Breaking on error as requested'); process.exit(1); } } if(breakOnError && testFailed){ break; } } } totalTests += testInstance.testCount; totalPassed += testInstance.passedCount; if(breakOnError && testInstance.testCount !== testInstance.passedCount){ Logger.log(100, '', 'Breaking execution due to test failure'); break; } } Logger.log(100, '', '='.repeat(60)); if(totalTests === totalPassed){ Logger.log(100, '', 'ALL TESTS PASSED: '+totalPassed+'/'+totalTests+' succeed.'); Logger.log(100, '', '='.repeat(60)); process.exit(0); } Logger.log(100, '', 'TESTS FAILED: '+totalPassed+'/'+totalTests+' succeed.'); Logger.log(100, '', '='.repeat(60)); process.exit(1); } catch(error){ Logger.log(100, '', 'Test execution failed: '+error.message); Logger.log(100, '', error.stack); process.exit(1); } } async function confirmTestExecution() { let rl = readline.createInterface({ input: process.stdin, output: process.stdout }); console.log('\n⚠️ WARNING: Integration Tests'); console.log('══════════════════════════════'); console.log('Running integration tests may modify or corrupt your test database.'); console.log('Make sure you are using a dedicated test environment.'); console.log('══════════════════════════════\n'); return new Promise((resolve) => { rl.question('Do you want to continue? (y/N): ', (answer) => { rl.close(); let shouldContinue = answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes'; if(!shouldContinue){ console.log('Tests cancelled by user.'); process.exit(0); } resolve(); }); }); } function getTestMethods(testInstance) { let methods = []; for(let prototype = Object.getPrototypeOf(testInstance); prototype !== null && prototype.constructor.name !== 'BaseTest'; prototype = Object.getPrototypeOf(prototype)){ let propertyNames = Object.getOwnPropertyNames(prototype); for(let propertyName of propertyNames){ if( propertyName.startsWith('test') && sc.isFunction(testInstance[propertyName]) && 'constructor' !== propertyName ){ if(!methods.includes(propertyName)){ methods.push(propertyName); } } } } return methods.sort(); } function getTestDisplayName(fileName) { return fileName .replace(/^test-/, '') .replace(/\.js$/, '') .split('-') .map(word => word.charAt(0).toUpperCase() + word.slice(1)) .join(' ') + ' Tests'; } function applyFilter(testFiles, filter) { if(!filter){ return testFiles; } return testFiles.filter(file => file.includes(filter)); } async function getTestFilesFromDirectory(directoryPath) { if(!FileHandler.exists(directoryPath)){ return []; } let files = FileHandler.readFolder(directoryPath); let excludeFiles = ['manager.js', 'utils.js', 'run.js', 'base-test.js']; return files.filter(file => file.startsWith('test-') && file.endsWith('.js') && !excludeFiles.includes(file)); } process.on('unhandledRejection', (reason, promise) => { Logger.log(100, '', 'Unhandled Rejection at:', promise, 'reason:', reason); process.exit(1); }); process.on('uncaughtException', (error) => { Logger.log(100, '', 'Uncaught Exception:', error); process.exit(1); }); runTests();