#!/usr/bin/env node
/**
* Extract test and coverage metrics for README badge updates
*/
const fs = require('fs');
const { execSync } = require('child_process');
async function extractMetrics() {
console.log('🔍 Extracting current test and coverage metrics...\n');
let testResults = {};
let coverageResults = {};
try {
// Extract test count by running test suite
console.log('📊 Running test suite to count tests...');
const testOutput = execSync('npm test 2>&1', { encoding: 'utf8', timeout: 60000 });
// Parse test results from output
const testMatch = testOutput.match(/Tests:\s+(\d+)\s+failed,\s+(\d+)\s+passed,\s+(\d+)\s+total/);
if (testMatch) {
testResults = {
failed: parseInt(testMatch[1]),
passed: parseInt(testMatch[2]),
total: parseInt(testMatch[3])
};
}
} catch (error) {
console.warn('⚠️ Could not extract test metrics from test run');
// Use fallback from the issue description
testResults = {
failed: 5,
passed: 399,
total: 404
};
}
try {
// Try to get coverage from existing coverage-final.json if it exists
if (fs.existsSync('coverage/coverage-final.json')) {
const coverageData = JSON.parse(fs.readFileSync('coverage/coverage-final.json', 'utf8'));
// Extract global coverage summary if available
if (Object.keys(coverageData).length > 0) {
const files = Object.values(coverageData);
let totalStatements = { covered: 0, total: 0 };
let totalBranches = { covered: 0, total: 0 };
let totalFunctions = { covered: 0, total: 0 };
let totalLines = { covered: 0, total: 0 };
files.forEach(file => {
if (file.s) {
totalStatements.total += Object.keys(file.s).length;
totalStatements.covered += Object.values(file.s).filter(count => count > 0).length;
}
if (file.b) {
Object.values(file.b).forEach(branch => {
totalBranches.total += branch.length;
totalBranches.covered += branch.filter(count => count > 0).length;
});
}
if (file.f) {
totalFunctions.total += Object.keys(file.f).length;
totalFunctions.covered += Object.values(file.f).filter(count => count > 0).length;
}
if (file.l) {
totalLines.total += Object.keys(file.l).length;
totalLines.covered += Object.values(file.l).filter(count => count > 0).length;
}
});
coverageResults = {
statements: totalStatements.total > 0 ? (totalStatements.covered / totalStatements.total * 100).toFixed(2) : '0.00',
branches: totalBranches.total > 0 ? (totalBranches.covered / totalBranches.total * 100).toFixed(2) : '0.00',
functions: totalFunctions.total > 0 ? (totalFunctions.covered / totalFunctions.total * 100).toFixed(2) : '0.00',
lines: totalLines.total > 0 ? (totalLines.covered / totalLines.total * 100).toFixed(2) : '0.00'
};
}
}
} catch (error) {
console.warn('⚠️ Could not extract coverage metrics from coverage report');
}
// Use fallback coverage data from existing README if we can't generate it
if (!coverageResults.statements) {
console.log('📋 Using existing coverage metrics from README...');
coverageResults = {
statements: '29.76',
branches: '23.84',
functions: '27.69',
lines: '30.97'
};
}
// Display results
console.log('\n📊 Current Metrics:');
console.log('==================');
console.log(`Tests: ${testResults.passed}/${testResults.total} passing (${testResults.failed} failed)`);
console.log(`Lines Coverage: ${coverageResults.lines}%`);
console.log(`Branch Coverage: ${coverageResults.branches}%`);
console.log(`Function Coverage: ${coverageResults.functions}%`);
console.log(`Statement Coverage: ${coverageResults.statements}%`);
// Generate badge URLs
const badges = {
tests: `https://img.shields.io/badge/tests-${testResults.passed}%2F${testResults.total}%20passing-${testResults.failed === 0 ? 'brightgreen' : 'yellow'}?logo=checkmarx&logoColor=white`,
lines: `https://img.shields.io/badge/lines%20coverage-${coverageResults.lines}%25-${getCoverageColor(parseFloat(coverageResults.lines))}?logo=jest&logoColor=white`,
branches: `https://img.shields.io/badge/branch%20coverage-${coverageResults.branches}%25-${getCoverageColor(parseFloat(coverageResults.branches))}?logo=jest&logoColor=white`,
functions: `https://img.shields.io/badge/function%20coverage-${coverageResults.functions}%25-${getCoverageColor(parseFloat(coverageResults.functions))}?logo=jest&logoColor=white`
};
console.log('\n🔗 Updated Badge URLs:');
console.log('======================');
Object.entries(badges).forEach(([key, url]) => {
console.log(`${key}: ${url}`);
});
return { testResults, coverageResults, badges };
}
function getCoverageColor(percentage) {
if (percentage >= 70) return 'brightgreen';
if (percentage >= 50) return 'green';
if (percentage >= 30) return 'yellow';
if (percentage >= 20) return 'orange';
return 'red';
}
// Run if called directly
if (require.main === module) {
extractMetrics().catch(console.error);
}
module.exports = { extractMetrics };