UNPKG

estructura_automation

Version:

Paquete de estructura de automation

249 lines (214 loc) 7.04 kB
/** * ======================================================================================== * METADATA BUILDER - Generación de Metadata de Tests * ---------------------------------------------------------------------------------------- * Responsabilidades: * - Generar metadata JSON para sincronización con tests automatizados * - Calcular estadísticas de tests (manuales vs automáticos) * - Crear mapas de rutas y identificadores * - Estructurar datos para sistemas externos * ======================================================================================== */ /** * Genera metadata JSON para sincronización con tests automatizados * @param {Object} hierarchicalData - Estructura de datos jerárquica * @returns {Object} Metadata de tests */ const generateTestsMetadata = (hierarchicalData) => { const tests = []; /** * Procesa recursivamente un nodo para extraer todos los tests * @param {Object} node - Nodo actual * @param {Array} pathArray - Array con la ruta hasta este nodo */ const processNode = (node, pathArray = []) => { // Procesar test cases del nodo actual node.testCases.forEach(testCase => { tests.push({ id: testCase.id, name: testCase.name, path: pathArray.join('/'), automatable: !testCase.isManual, isManual: testCase.isManual, tags: testCase.tags, featureFile: testCase.featureFile, stepCount: testCase.steps.length, steps: testCase.steps.map(step => ({ id: step.id, text: step.text })) }); }); // Procesar recursivamente todos los hijos Object.values(node.children || {}).forEach(child => { processNode(child, [...pathArray, child.name]); }); }; // Procesar todas las aplicaciones Object.values(hierarchicalData.apps).forEach(app => { processNode(app, [app.name]); }); // Calcular estadísticas const manualTests = tests.filter(t => t.isManual); const automatableTests = tests.filter(t => !t.isManual); return { generatedAt: new Date().toISOString(), totalTests: tests.length, manualTests: manualTests.length, automatableTests: automatableTests.length, manualPercentage: Math.round((manualTests.length / tests.length) * 100), automatablePercentage: Math.round((automatableTests.length / tests.length) * 100), tests: tests, // Estadísticas adicionales statistics: { totalSteps: tests.reduce((sum, test) => sum + test.stepCount, 0), averageStepsPerTest: Math.round(tests.reduce((sum, test) => sum + test.stepCount, 0) / tests.length), testsByApp: getTestsByApp(hierarchicalData), tagStatistics: getTagStatistics(tests) } }; }; /** * Calcula estadísticas de tests por aplicación * @param {Object} hierarchicalData - Datos jerárquicos * @returns {Object} Estadísticas por app */ const getTestsByApp = (hierarchicalData) => { const appStats = {}; Object.entries(hierarchicalData.apps).forEach(([appId, app]) => { const appTests = []; const collectTests = (node) => { appTests.push(...node.testCases); Object.values(node.children || {}).forEach(child => { collectTests(child); }); }; collectTests(app); appStats[appId] = { name: app.name, totalTests: appTests.length, manualTests: appTests.filter(t => t.isManual).length, automatableTests: appTests.filter(t => !t.isManual).length }; }); return appStats; }; /** * Calcula estadísticas de tags utilizados * @param {Array} tests - Array de tests * @returns {Object} Estadísticas de tags */ const getTagStatistics = (tests) => { const tagCounts = {}; tests.forEach(test => { test.tags.forEach(tag => { tagCounts[tag] = (tagCounts[tag] || 0) + 1; }); }); return { totalUniqueTags: Object.keys(tagCounts).length, tagCounts: tagCounts, mostCommonTags: Object.entries(tagCounts) .sort(([,a], [,b]) => b - a) .slice(0, 5) .map(([tag, count]) => ({ tag, count })) }; }; /** * Genera un mapa de rutas para navegación rápida * @param {Object} hierarchicalData - Datos jerárquicos * @returns {Object} Mapa de rutas */ const generatePathMap = (hierarchicalData) => { const pathMap = {}; const processNode = (node, pathArray = []) => { const currentPath = [...pathArray, node.name]; pathMap[node.id] = { path: currentPath, breadcrumb: currentPath.join(' / '), hasSubfolders: node.hasSubfolders, hasFeatures: node.hasFeatures, testCount: node.testCases.length }; // Procesar hijos recursivamente Object.values(node.children || {}).forEach(child => { processNode(child, currentPath); }); }; Object.values(hierarchicalData.apps).forEach(app => { processNode(app, []); }); return pathMap; }; /** * Valida la integridad de los datos jerárquicos * @param {Object} hierarchicalData - Datos a validar * @returns {Object} Reporte de validación */ const validateHierarchicalData = (hierarchicalData) => { const errors = []; const warnings = []; const stats = { totalNodes: 0, totalTests: 0, duplicateIds: [] }; const seenIds = new Set(); const validateNode = (node, path = []) => { stats.totalNodes++; // Verificar ID único if (seenIds.has(node.id)) { errors.push(`ID duplicado encontrado: ${node.id} en ${path.join('/')}`); stats.duplicateIds.push(node.id); } else { seenIds.add(node.id); } // Verificar estructura del nodo if (!node.name || typeof node.name !== 'string') { errors.push(`Nodo sin nombre válido: ${node.id}`); } if (!Array.isArray(node.testCases)) { errors.push(`TestCases no es array en nodo: ${node.id}`); } else { stats.totalTests += node.testCases.length; // Validar test cases node.testCases.forEach(testCase => { if (!testCase.id || !testCase.name) { errors.push(`Test case inválido en ${node.id}: falta ID o nombre`); } if (!Array.isArray(testCase.steps)) { errors.push(`Steps no es array en test: ${testCase.id}`); } }); } // Validar flags de consistencia const actualHasSubfolders = Object.keys(node.children || {}).length > 0; const actualHasFeatures = node.testCases.length > 0; if (node.hasSubfolders !== actualHasSubfolders) { warnings.push(`Flag hasSubfolders inconsistente en ${node.id}`); } if (node.hasFeatures !== actualHasFeatures) { warnings.push(`Flag hasFeatures inconsistente en ${node.id}`); } // Validar hijos recursivamente Object.values(node.children || {}).forEach(child => { validateNode(child, [...path, node.name]); }); }; Object.values(hierarchicalData.apps || {}).forEach(app => { validateNode(app, []); }); return { isValid: errors.length === 0, errors, warnings, stats }; }; module.exports = { generateTestsMetadata, generatePathMap, validateHierarchicalData, getTestsByApp, getTagStatistics };