mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
- Adds `scripts/run-test-audit.sh` to automate unit test execution with coverage. - Adds `scripts/analyze-flakiness.mjs` to detect test flakiness. - Adds `scripts/static-test-analysis.mjs` to find suspicious test patterns. - Adds `scripts/coverage-gap-analysis.mjs` to identify critical coverage gaps. - Adds `scripts/generate-audit-report.mjs` to produce markdown reports. - Generates initial audit report `test-audit-report-2025-02-18.md` and `issues/ISSUE_test_audit_findings.md`. - Documents findings in `decisions/DECISIONS_2025-02-18.md`. Co-authored-by: PR0M3TH3AN <[email protected]>
127 lines
4.4 KiB
JavaScript
127 lines
4.4 KiB
JavaScript
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { execSync } from 'node:child_process';
|
|
|
|
const rootDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
const flakinessFile = path.join(rootDir, 'test-audit', 'flakiness-matrix.json');
|
|
const suspiciousFile = path.join(rootDir, 'test-audit', 'suspicious-tests.json');
|
|
const coverageFile = path.join(rootDir, 'test-audit', 'coverage-gaps.json');
|
|
const outputFile = path.join(rootDir, 'test-audit-report-' + new Date().toISOString().split('T')[0] + '.md');
|
|
|
|
function readJson(file) {
|
|
if (fs.existsSync(file)) {
|
|
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function main() {
|
|
const flakiness = readJson(flakinessFile);
|
|
const suspicious = readJson(suspiciousFile);
|
|
const coverage = readJson(coverageFile);
|
|
|
|
const nodeVersion = process.version;
|
|
let npmVersion = 'unknown';
|
|
try {
|
|
npmVersion = execSync('npm --version').toString().trim();
|
|
} catch (e) {}
|
|
|
|
let report = `# Test Audit Report - ${new Date().toISOString().split('T')[0]}\n\n`;
|
|
|
|
report += `## Run Metadata\n`;
|
|
report += `- **Date**: ${new Date().toISOString()}\n`;
|
|
report += `- **Node Version**: ${nodeVersion}\n`;
|
|
report += `- **NPM Version**: ${npmVersion}\n`;
|
|
report += `- **Test Command**: \`npm run test:unit\` (with c8 coverage)\n\n`;
|
|
|
|
// Summary
|
|
report += `## Summary\n`;
|
|
report += `- **Flaky Tests**: ${flakiness ? Object.keys(flakiness).filter(k => flakiness[k].verdict === 'FLAKY').length : 'N/A'}\n`;
|
|
report += `- **Suspicious Files**: ${suspicious ? Object.keys(suspicious).length : 'N/A'}\n`;
|
|
report += `- **Critical Coverage Gaps**: ${coverage ? Object.keys(coverage).filter(k => coverage[k].status === 'LOW_COVERAGE').length : 'N/A'}\n\n`;
|
|
|
|
// Flakiness
|
|
report += `## Flakiness Detection\n`;
|
|
if (flakiness) {
|
|
const flakyTests = Object.keys(flakiness).filter(k => flakiness[k].verdict === 'FLAKY');
|
|
if (flakyTests.length > 0) {
|
|
report += `Found ${flakyTests.length} flaky tests:\n`;
|
|
for (const test of flakyTests) {
|
|
report += `- **${test}**: ${flakiness[test].statuses.join(', ')}\n`;
|
|
}
|
|
} else {
|
|
report += `No flaky tests detected (based on run matrix).\n`;
|
|
}
|
|
} else {
|
|
report += `Flakiness matrix not found.\n`;
|
|
}
|
|
report += `\n`;
|
|
|
|
// Suspicious Tests
|
|
report += `## Suspicious Patterns\n`;
|
|
if (suspicious) {
|
|
const files = Object.keys(suspicious);
|
|
if (files.length > 0) {
|
|
report += `Found suspicious patterns in ${files.length} files:\n`;
|
|
for (const file of files) {
|
|
report += `### ${file}\n`;
|
|
for (const issue of suspicious[file]) {
|
|
report += `- ${issue}\n`;
|
|
}
|
|
}
|
|
} else {
|
|
report += `No suspicious patterns found.\n`;
|
|
}
|
|
} else {
|
|
report += `Suspicious tests file not found.\n`;
|
|
}
|
|
report += `\n`;
|
|
|
|
// Coverage Gaps
|
|
report += `## Critical Coverage Gaps\n`;
|
|
if (coverage) {
|
|
const gaps = Object.keys(coverage).filter(k => coverage[k].status !== 'OK');
|
|
if (gaps.length > 0) {
|
|
report += `Critical modules with low coverage (< 70%):\n`;
|
|
for (const file of gaps) {
|
|
const stats = coverage[file];
|
|
if (stats.status === 'MISSING') {
|
|
report += `- **${file}**: No coverage data found.\n`;
|
|
} else {
|
|
report += `- **${file}**: Lines: ${stats.lines}%, Statements: ${stats.statements}%, Functions: ${stats.functions}%, Branches: ${stats.branches}%\n`;
|
|
}
|
|
}
|
|
} else {
|
|
report += `All critical modules have acceptable coverage.\n`;
|
|
}
|
|
} else {
|
|
report += `Coverage gaps file not found.\n`;
|
|
}
|
|
report += `\n`;
|
|
|
|
// Remediation
|
|
report += `## Prioritized Remediation\n`;
|
|
report += `### High Priority (P0)\n`;
|
|
if (coverage) {
|
|
const gaps = Object.keys(coverage).filter(k => coverage[k].status !== 'OK');
|
|
for (const file of gaps) {
|
|
report += `- [ ] Increase coverage for \`${file}\` (currently < 70%).\n`;
|
|
}
|
|
}
|
|
if (flakiness) {
|
|
const flakyTests = Object.keys(flakiness).filter(k => flakiness[k].verdict === 'FLAKY');
|
|
for (const test of flakyTests) {
|
|
report += `- [ ] Fix flakiness in \`${test}\`.\n`;
|
|
}
|
|
}
|
|
|
|
report += `\n### Medium Priority (P1)\n`;
|
|
report += `- [ ] Review suspicious tests (time dependence, network usage) and replace with deterministic patterns.\n`;
|
|
|
|
fs.writeFileSync(outputFile, report);
|
|
console.log(`Generated report: ${outputFile}`);
|
|
}
|
|
|
|
main();
|