@debugmcp/mcp-debugger
Version:
Run-time step-through debugging for LLM agents.
132 lines (109 loc) • 4.11 kB
JavaScript
import { spawn } from 'child_process';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
/**
* Runs tests with coverage and displays a minimal summary
*/
async function testCoverageSummary() {
const jsonFile = path.join(process.cwd(), 'test-results.json');
const coverageSummaryFile = path.join(process.cwd(), 'coverage', 'coverage-summary.json');
console.log('Running tests with coverage...\n');
// Run tests with coverage and JSON reporter
// Use separate arguments to avoid path issues with spaces
const vitestArgs = ['vitest', 'run', '--coverage', '--reporter=dot', '--outputFile', jsonFile];
const testProcess = spawn('npx', vitestArgs, {
stdio: ['inherit', 'pipe', 'pipe'],
shell: true,
cwd: process.cwd()
});
// Capture output but don't display verbose logs
let dots = '';
testProcess.stdout.on('data', (data) => {
const output = data.toString();
// Extract only the dots/progress indicators
const progressMatch = output.match(/[·.xX!*]+/g);
if (progressMatch) {
dots += progressMatch.join('');
process.stdout.write(progressMatch.join(''));
}
});
testProcess.stderr.on('data', () => {});
const startTime = Date.now();
await new Promise((resolve) => {
testProcess.on('close', resolve);
});
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
// Read and parse results
try {
// Parse test results
let testSummary = {
totalTests: 0,
passed: 0,
failed: 0,
skipped: 0
};
if (fs.existsSync(jsonFile)) {
const results = JSON.parse(fs.readFileSync(jsonFile, 'utf8'));
testSummary = {
totalTests: results.numTotalTests || 0,
passed: results.numPassedTests || 0,
failed: results.numFailedTests || 0,
skipped: results.numPendingTests || 0
};
}
// Parse coverage results
let coverageSummary = {
statements: 0,
branches: 0,
functions: 0,
lines: 0
};
if (fs.existsSync(coverageSummaryFile)) {
const coverage = JSON.parse(fs.readFileSync(coverageSummaryFile, 'utf8'));
if (coverage.total) {
coverageSummary = {
statements: coverage.total.statements.pct || 0,
branches: coverage.total.branches.pct || 0,
functions: coverage.total.functions.pct || 0,
lines: coverage.total.lines.pct || 0
};
}
}
// Display minimal summary
console.log('\n');
console.log('─'.repeat(70));
console.log(`Test Files ${testSummary.failed > 0 ? testSummary.failed + ' failed |' : ''} ${testSummary.passed} passed`);
console.log(` Tests ${testSummary.failed > 0 ? testSummary.failed + ' failed |' : ''} ${testSummary.passed} passed${testSummary.skipped > 0 ? ' | ' + testSummary.skipped + ' skipped' : ''}`);
console.log(` Duration ${duration}s`);
console.log(` Coverage ${coverageSummary.statements.toFixed(2)}% stmts | ${coverageSummary.branches.toFixed(1)}% branch | ${coverageSummary.functions.toFixed(2)}% funcs | ${coverageSummary.lines.toFixed(1)}% lines`);
console.log('─'.repeat(70));
// Exit code based on test results
const exitCode = testSummary.failed > 0 ? 1 : 0;
// Clean up
if (fs.existsSync(jsonFile)) {
fs.unlinkSync(jsonFile);
}
process.exit(exitCode);
} catch (error) {
console.error('Error reading results:', error.message);
// Try to provide basic info even on error
console.log('\n');
console.log('─'.repeat(70));
console.log('Test run completed with errors. Check logs for details.');
console.log(`Duration: ${duration}s`);
console.log('─'.repeat(70));
// Clean up
if (fs.existsSync(jsonFile)) {
fs.unlinkSync(jsonFile);
}
process.exit(1);
}
}
// Run the script
testCoverageSummary().catch(error => {
console.error('Unexpected error:', error);
process.exit(1);
});