Files
bitvid/test-audit/run-flaky-check.mjs
T
google-labs-jules[bot]andPR0M3TH3AN 82dc581145 docs: add daily test audit report and artifacts
- Run unit tests with coverage (c8)
- Generate test audit report (test-audit-report-2026-02-15.md)
- Add static analysis of suspicious tests
- Add flakiness check script and results (timed out)
- Create daily completion log

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-15 22:24:28 +00:00

98 lines
3.2 KiB
JavaScript

import { spawn } from "node:child_process";
import fs from "node:fs/promises";
import path from "node:path";
const RUNS = 3;
const RESULTS_FILE = "test-audit/flakiness-matrix.json";
async function runTests(runIndex) {
console.log(`Starting Run ${runIndex + 1}/${RUNS}...`);
return new Promise((resolve) => {
const child = spawn("npm", ["run", "test:unit"], {
stdio: ["ignore", "pipe", "pipe"],
shell: true
});
let output = "";
child.stdout.on("data", (d) => output += d.toString());
child.stderr.on("data", (d) => output += d.toString());
child.on("close", (code) => {
resolve({ code, output });
});
});
}
function parseFailedFiles(output) {
const failedFiles = [];
const lines = output.split("\n");
for (const line of lines) {
// Look for "failed with exit code" or similar from run-unit-tests.mjs
// The script logs: "Error: <relativePath> failed with exit code <code>"
// or "Error: <relativePath> timed out..."
const match = line.match(/Error: (.+) (failed with exit code|timed out)/);
if (match) {
failedFiles.push(match[1]);
}
}
return failedFiles;
}
async function main() {
const matrix = {
runs: [],
flakyFiles: []
};
const fileStatus = {}; // { filename: { pass: 0, fail: 0 } }
for (let i = 0; i < RUNS; i++) {
const { code, output } = await runTests(i);
const failedFiles = parseFailedFiles(output);
const passed = code === 0;
matrix.runs.push({
run: i + 1,
passed,
failedFiles
});
// We assume all files ran if the suite finished, or at least the ones that didn't fail passed.
// But since run-unit-tests.mjs aborts on first failure?
// Wait, let's check run-unit-tests.mjs logic.
// It loops through `selectedTests` and awaits each spawn.
// If a test fails, `finalize` is called with error.
// `child.on("close", ...)` calls finalize.
// The `run()` function in `run-unit-tests.mjs`:
// `try { await run(); } catch ...`
// Inside `run()`, it loops. If `spawn` promise rejects, the loop breaks?
// `await new Promise(...)`. If reject is called, `run()` throws and exits?
// Yes: `try { await run() } catch (e) { ... process.exit(1) }`.
// So if one file fails, the whole suite stops.
// This makes flakiness detection harder because subsequent files aren't run.
// However, if the suite passes, all files passed.
// If it fails, one file failed.
// We can just track which file failed if any.
if (failedFiles.length > 0) {
for (const file of failedFiles) {
if (!fileStatus[file]) fileStatus[file] = { failures: 0 };
fileStatus[file].failures++;
}
}
}
// Identify flaky files: files that failed in some runs but not all?
// Or just list files that failed at all.
// If a file fails every time, it's broken, not flaky (unless we fixed it and it broke again).
// If it fails sometimes, it's flaky.
// Since we stop on first failure, we can't know if subsequent files would have failed.
// We'll just record the matrix.
await fs.writeFile(RESULTS_FILE, JSON.stringify(matrix, null, 2));
console.log(`Flakiness check complete. Saved to ${RESULTS_FILE}`);
}
main().catch(console.error);