fix(qa): avoid vitest report path collisions

This commit is contained in:
Vincent Koc 2026-06-23 12:40:25 +02:00
parent 44d77de0c5
commit cb6b15f782
No known key found for this signature in database
2 changed files with 42 additions and 1 deletions

View file

@ -1,5 +1,6 @@
// Shared helpers for running Vitest JSON reports and reading duration data.
import { spawnSync } from "node:child_process";
import { randomUUID } from "node:crypto";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
@ -59,6 +60,10 @@ function validateVitestJsonReport(reportPath) {
return null;
}
function defaultVitestJsonReportPath(prefix) {
return path.join(os.tmpdir(), `${prefix}-${process.pid}-${Date.now()}-${randomUUID()}.json`);
}
/**
* Runs Vitest with the JSON reporter unless an existing report was supplied.
*/
@ -67,7 +72,7 @@ export function runVitestJsonReport({
reportPath = "",
prefix = "openclaw-vitest-report",
}) {
const resolvedReportPath = reportPath || path.join(os.tmpdir(), `${prefix}-${Date.now()}.json`);
const resolvedReportPath = reportPath || defaultVitestJsonReportPath(prefix);
if (!(reportPath && fs.existsSync(resolvedReportPath))) {
const run = spawnSync(

View file

@ -153,6 +153,42 @@ describe("scripts/test-report-utils runVitestJsonReport", () => {
);
});
it("uses distinct default report paths when invocations share a clock tick", async () => {
const { runVitestJsonReport } = await import("../../scripts/test-report-utils.mjs");
const reportPaths: string[] = [];
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(1234567890);
spawnSyncMock.mockImplementation((_command: string, args: string[]) => {
const outputFileIndex = args.indexOf("--outputFile") + 1;
const outputFile = args[outputFileIndex];
reportPaths.push(outputFile);
fs.writeFileSync(outputFile, `${JSON.stringify({ testResults: [] })}\n`, "utf8");
return { status: 0 };
});
try {
runVitestJsonReport({
config: "test/vitest/vitest.unit.config.ts",
});
runVitestJsonReport({
config: "test/vitest/vitest.unit.config.ts",
});
expect(reportPaths).toHaveLength(2);
expect(reportPaths[0]).not.toBe(reportPaths[1]);
for (const reportPath of reportPaths) {
expect(path.dirname(reportPath)).toBe(os.tmpdir());
expect(path.basename(reportPath)).toMatch(
/^openclaw-vitest-report-\d+-1234567890-[0-9a-f-]+\.json$/u,
);
}
} finally {
nowSpy.mockRestore();
for (const reportPath of reportPaths) {
fs.rmSync(reportPath, { force: true });
}
}
});
it("fails when Vitest exits successfully without writing a JSON report", async () => {
const { runVitestJsonReport } = await import("../../scripts/test-report-utils.mjs");
spawnSyncMock.mockReturnValue({ status: 0 });