#!/usr/bin/env node
/**
* Test Runner para CV MCP Tools
* Ejecuta todos los tests de manera ordenada y genera reportes
*/
const fs = require('fs');
const path = require('path');
// Colors para la consola
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 colorize(text, color) {
return `${colors[color]}${text}${colors.reset}`;
}
function printHeader() {
console.log(colorize('=' * 60, 'cyan'));
console.log(colorize('🧪 CV MCP TOOLS - BATERÍA DE TESTS', 'cyan'));
console.log(colorize(' Sistema de Reclutamiento para Brayan Smith Cordova Tasayco', 'blue'));
console.log(colorize('=' * 60, 'cyan'));
console.log();
}
function printSeparator(title) {
console.log(colorize(`\n${'─'.repeat(40)}`, 'yellow'));
console.log(colorize(`${title}`, 'yellow'));
console.log(colorize(`${'─'.repeat(40)}`, 'yellow'));
}
async function validateDataFiles() {
printSeparator('📁 VALIDANDO ARCHIVOS DE DATOS');
const requiredFiles = [
'src/candidate-data.json',
'src/index.ts'
];
let allFilesExist = true;
for (const file of requiredFiles) {
const filePath = path.join(process.cwd(), file);
if (fs.existsSync(filePath)) {
console.log(colorize(`✅ ${file}`, 'green'));
} else {
console.log(colorize(`❌ ${file} - ARCHIVO NO ENCONTRADO`, 'red'));
allFilesExist = false;
}
}
// Validar JSON
try {
const candidateDataPath = path.join(process.cwd(), 'src/candidate-data.json');
if (fs.existsSync(candidateDataPath)) {
const data = JSON.parse(fs.readFileSync(candidateDataPath, 'utf8'));
// Validar estructura básica
const requiredSections = ['personal', 'workExperience', 'education', 'certifications', 'skills'];
let validStructure = true;
for (const section of requiredSections) {
if (!data[section]) {
console.log(colorize(`❌ Sección faltante en JSON: ${section}`, 'red'));
validStructure = false;
}
}
if (validStructure) {
console.log(colorize('✅ Estructura JSON válida', 'green'));
} else {
allFilesExist = false;
}
}
} catch (error) {
console.log(colorize(`❌ Error validando JSON: ${error.message}`, 'red'));
allFilesExist = false;
}
return allFilesExist;
}
async function runMCPTests() {
printSeparator('🔧 EJECUTANDO TESTS MCP');
try {
// Importar y ejecutar los tests principales
const { runTests } = require('./mcp-tools.test.js');
await runTests();
return true;
} catch (error) {
console.log(colorize(`❌ Error ejecutando tests MCP: ${error.message}`, 'red'));
return false;
}
}
async function runCryptoTests() {
printSeparator('🔐 TESTS DE FIRMA DIGITAL');
console.log(colorize('🔑 Validando sistema de firmas digitales...', 'blue'));
try {
const { TestMCPAgent } = require('./mcp-tools.test.js');
const agent = new TestMCPAgent();
await agent.init();
console.log('\n📝 Verificando que todas las respuestas estén firmadas...');
// Lista de todas las herramientas que deben devolver respuestas firmadas
const tools = [
'get_candidate_profile',
'get_work_experience',
'get_education_background',
'get_certifications',
'get_technical_skills',
'get_soft_skills',
'get_languages_interests',
'get_portfolio_website',
'get_github_profile',
'get_social_networks'
];
let allToolsSigned = true;
for (const toolName of tools) {
try {
const response = await agent.server.callTool(toolName);
const responseText = response.content[0].text;
const parsedResponse = JSON.parse(responseText);
// Verificar que tenga todos los campos de firma digital
const requiredFields = ['data', 'hash', 'signature', 'timestamp', 'publicKey', 'serverId', 'version'];
const hasAllFields = requiredFields.every(field => Object.hasOwn(parsedResponse, field));
if (hasAllFields) {
console.log(` ✅ ${toolName}: Respuesta firmada correctamente`);
} else {
console.log(` ❌ ${toolName}: Faltan campos de firma digital`);
allToolsSigned = false;
}
} catch (error) {
console.log(` ❌ ${toolName}: Error - ${error.message}`);
allToolsSigned = false;
}
}
// Test de verificación de firma
console.log('\n🔍 Probando herramienta de verificación...');
const profileResponse = await agent.server.callTool('get_candidate_profile');
const verifyResponse = await agent.server.callTool('verify_response_signature', {
signedResponse: profileResponse.content[0].text
});
const verifyData = JSON.parse(verifyResponse.content[0].text);
if (verifyData.data.verificationStatus === 'VALID') {
console.log(' ✅ Herramienta de verificación funciona correctamente');
} else {
console.log(' ❌ Herramienta de verificación falló');
allToolsSigned = false;
}
if (allToolsSigned) {
console.log(colorize('\n🔐 Sistema de firma digital validado exitosamente', 'green'));
} else {
console.log(colorize('\n❌ Fallos en el sistema de firma digital', 'red'));
}
return allToolsSigned;
} catch (error) {
console.log(colorize(`❌ Error en tests de criptografía: ${error.message}`, 'red'));
return false;
}
}
async function runIntegrationTests() {
printSeparator('🌐 TESTS DE INTEGRACIÓN');
console.log(colorize('📋 Simulando escenarios reales de reclutamiento...', 'blue'));
try {
const { TestMCPAgent } = require('./mcp-tools.test.js');
const agent = new TestMCPAgent();
await agent.init();
// Escenario 1: Reclutador busca desarrollador React
console.log('\n🎯 Escenario 1: Evaluación para puesto Frontend React Developer');
const reactEval = await agent.server.callTool('match_job_requirements', {
jobTitle: 'React Frontend Developer',
requiredSkills: ['React', 'JavaScript', 'HTML', 'CSS'],
preferredSkills: ['TypeScript', 'Next.js', 'Tailwind CSS']
});
const reactData = JSON.parse(reactEval.content[0].text);
console.log(` 💯 Compatibilidad: ${reactData.matchAnalysis.requiredSkillsMatch}`);
console.log(` 🎨 Skills preferidos: ${reactData.matchAnalysis.preferredSkillsMatch}`);
console.log(` 📊 Fit general: ${reactData.matchAnalysis.overallFit}`);
// Escenario 2: Búsqueda de experiencia específica
console.log('\n🎯 Escenario 2: Verificación de experiencia en liderazgo');
const leadershipEval = await agent.server.callTool('assess_leadership_experience');
const leadershipData = JSON.parse(leadershipEval.content[0].text);
console.log(` 👥 Tiene experiencia de liderazgo: ${leadershipData.hasLeadershipExperience ? 'Sí' : 'No'}`);
console.log(` ⏱️ Duración: ${leadershipData.leadershipDuration}`);
// Escenario 3: Tech stack específico
console.log('\n🎯 Escenario 3: Evaluación tech stack para startup moderna');
const techEval = await agent.server.callTool('evaluate_tech_stack', {
requiredTechnologies: ['React', 'Node.js', 'MongoDB', 'Docker', 'AWS']
});
const techData = JSON.parse(techEval.content[0].text);
console.log(` 🔧 Score de compatibilidad: ${techData.compatibilityScore}`);
console.log(` ✅ Tecnologías que domina: ${techData.matchingTechnologies.join(', ')}`);
console.log(` ❌ Tecnologías por aprender: ${techData.missingTechnologies.join(', ')}`);
console.log(colorize('\n✨ Tests de integración completados exitosamente', 'green'));
return true;
} catch (error) {
console.log(colorize(`❌ Error en tests de integración: ${error.message}`, 'red'));
return false;
}
}
async function generateReport(results) {
printSeparator('📊 GENERANDO REPORTE');
const reportData = {
timestamp: new Date().toISOString(),
results: results,
summary: {
allPassed: results.validation && results.mcpTests && results.cryptoTests && results.integration,
totalSteps: 4,
passedSteps: Object.values(results).filter(Boolean).length
}
};
// Generar reporte en archivo
const reportPath = path.join(__dirname, 'test-report.json');
fs.writeFileSync(reportPath, JSON.stringify(reportData, null, 2));
console.log(colorize(`📄 Reporte guardado en: ${reportPath}`, 'blue'));
// Mostrar resumen final
console.log(colorize('\n🏁 RESUMEN FINAL', 'magenta'));
console.log(`📁 Validación de archivos: ${results.validation ? '✅' : '❌'}`);
console.log(`🔧 Tests MCP: ${results.mcpTests ? '✅' : '❌'}`);
console.log(`🔐 Tests firma digital: ${results.cryptoTests ? '✅' : '❌'}`);
console.log(`🌐 Tests integración: ${results.integration ? '✅' : '❌'}`);
if (reportData.summary.allPassed) {
console.log(colorize('\n🎉 ¡TODOS LOS TESTS PASARON!', 'green'));
console.log(colorize('✨ El sistema CV MCP está listo para producción', 'green'));
} else {
console.log(colorize(`\n⚠️ ${4 - reportData.summary.passedSteps} etapa(s) fallaron`, 'yellow'));
console.log(colorize('🔧 Revisa los errores anteriores', 'yellow'));
}
return reportData.summary.allPassed;
}
async function main() {
console.clear();
printHeader();
const startTime = Date.now();
const results = {};
try {
// Paso 1: Validar archivos
results.validation = await validateDataFiles();
if (!results.validation) {
console.log(colorize('\n❌ Validación de archivos falló. Abortando tests.', 'red'));
process.exit(1);
}
// Paso 2: Ejecutar tests MCP
results.mcpTests = await runMCPTests();
// Paso 3: Tests de firma digital
results.cryptoTests = await runCryptoTests();
// Paso 4: Tests de integración
results.integration = await runIntegrationTests();
// Generar reporte final
const success = await generateReport(results);
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
console.log(colorize(`\n⏱️ Duración total: ${duration}s`, 'cyan'));
process.exit(success ? 0 : 1);
} catch (error) {
console.error(colorize(`\n💥 Error inesperado: ${error.message}`, 'red'));
console.error(error.stack);
process.exit(1);
}
}
// Ejecutar si se llama directamente
if (require.main === module) {
main();
}
module.exports = { main };