mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-08 13:52:58 +00:00
feat(test-audit): Add daily test integrity and coverage audit workflow
- 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]>
This commit is contained in:
1 parent
98d7cbe607
commit
661a51084e
14 files changed
+2576
-125
No files matched your search
@@ -0,0 +1,78 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const rootDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
||||
const testsDir = path.join(rootDir, 'tests');
|
||||
const outputFile = path.join(rootDir, 'test-audit', 'suspicious-tests.json');
|
||||
|
||||
const checks = {
|
||||
zeroAssertions: {
|
||||
pattern: /(expect\(|assert\.|t\.is|chai\.expect|should\.)/g,
|
||||
inverse: true,
|
||||
message: 'No assertions found'
|
||||
},
|
||||
focusedOrSkipped: {
|
||||
pattern: /\.(only|skip)\(/g,
|
||||
message: 'Focused or skipped test'
|
||||
},
|
||||
timeDependence: {
|
||||
pattern: /(setTimeout|setInterval|sleep|delay)\(/g,
|
||||
message: 'Time dependence (sleep/timeout)'
|
||||
},
|
||||
networkDependence: {
|
||||
pattern: /(fetch|axios\.|new WebSocket|WebSocket\()/g,
|
||||
message: 'Network dependence (fetch/WebSocket)'
|
||||
},
|
||||
consoleUsage: {
|
||||
pattern: /console\.(log|warn|error)/g,
|
||||
message: 'Console usage'
|
||||
}
|
||||
};
|
||||
|
||||
async function scanFile(filePath) {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
const fileIssues = [];
|
||||
|
||||
for (const [key, check] of Object.entries(checks)) {
|
||||
const matches = content.match(check.pattern);
|
||||
if (check.inverse) {
|
||||
if (!matches) {
|
||||
fileIssues.push(check.message);
|
||||
}
|
||||
} else {
|
||||
if (matches) {
|
||||
fileIssues.push(`${check.message} (${matches.length} occurrences)`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return fileIssues;
|
||||
}
|
||||
|
||||
async function walk(dir) {
|
||||
let results = {};
|
||||
const list = fs.readdirSync(dir);
|
||||
for (const file of list) {
|
||||
if (file === 'node_modules' || file === 'visual' || file === 'e2e') continue;
|
||||
const filePath = path.join(dir, file);
|
||||
const stat = fs.statSync(filePath);
|
||||
if (stat && stat.isDirectory()) {
|
||||
Object.assign(results, await walk(filePath));
|
||||
} else if (file.endsWith('.test.mjs') || file.endsWith('.test.js')) {
|
||||
const issues = await scanFile(filePath);
|
||||
if (issues.length > 0) {
|
||||
results[path.relative(rootDir, filePath)] = issues;
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('Scanning tests for suspicious patterns...');
|
||||
const suspiciousTests = await walk(testsDir);
|
||||
fs.writeFileSync(outputFile, JSON.stringify(suspiciousTests, null, 2));
|
||||
console.log(`Wrote suspicious tests to ${outputFile}`);
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in new issue
Block a user