test: temp dirs are removed even when a test fails; lint guards it (#646)

golden-capture-provenance accept() left a ~20 MB baselines sandbox in
TMPDIR on every call (433 copies, 8.5 GB, ENOSPC in the shared sandbox).
It now reads what it needs and removes the sandbox in finally; fixtures
are removed via t.after. Same fix for the three other leaking sites
(bundle-assets hp-tree-, docs-accept hp-identical-, rebase-generated
hp-runner- outside finally).

test/temp-dir-hygiene.test.mjs parses test/**/*.mjs with the TypeScript
AST: every mkdtemp/mkdtempSync must be bound to a name removed by
rm*/rmSync in a finally block or an after/afterEach/t.after hook of the
same function, or returned by a named helper whose every call site does
so; exception `// tmp-ok: <reason>`. Two mutants witness the lint.

Issue: #646
User-Visible: no
This commit is contained in:
Claude
2026-09-25 03:50:40 +03:00
parent 524908b23b
commit fa91f3a731
6 changed files with 357 additions and 60 deletions
+7 -6
View File
@@ -3,7 +3,7 @@ import test from 'node:test';
import { createHash } from 'node:crypto';
import { readFileSync } from 'node:fs';
import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs';
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { acceptIdentical, acceptedDocsManifest, identicalDecision, identicalDocsManifest, verifyDocsCandidate } from '../scripts/docs-accept.mjs';
@@ -213,8 +213,9 @@ test('#455 принятый манифест несёт среду приёмк
// ---------- #512: --identical ----------
const identicalRoot = (frames) => {
const identicalRoot = (t, frames) => {
const root = mkdtempSync(join(tmpdir(), 'hp-identical-'));
t.after(() => rmSync(root, { recursive: true, force: true }));
mkdirSync(join(root, 'docs', 'images'), { recursive: true });
const scenarios = {};
for (const scenario of DOC_SCREENSHOTS) {
@@ -241,8 +242,8 @@ const identicalRoot = (frames) => {
return { root, manifest, capture, compare };
};
test('#512 AC3: identical frames accept only the source fingerprint; bytes and provenance stay committed', async () => {
const { root, manifest, capture, compare } = identicalRoot({});
test('#512 AC3: identical frames accept only the source fingerprint; bytes and provenance stay committed', async (t) => {
const { root, manifest, capture, compare } = identicalRoot(t, {});
const log = [];
const code = await acceptIdentical({ root, capture, compare, log: (line) => log.push(line) });
assert.equal(code, 0);
@@ -259,8 +260,8 @@ test('#512 AC3: identical frames accept only the source fingerprint; bytes and p
assert.match(log[0], /попиксельно совпали/);
});
test('#512 AC3: one differing pixel refuses, names the frame and leaves everything committed as it was', async () => {
const { root, manifest, capture, compare } = identicalRoot({ 'view-desktop': { identical: false, differing: 3, sizeMismatch: false } });
test('#512 AC3: one differing pixel refuses, names the frame and leaves everything committed as it was', async (t) => {
const { root, manifest, capture, compare } = identicalRoot(t, { 'view-desktop': { identical: false, differing: 3, sizeMismatch: false } });
const log = [];
const code = await acceptIdentical({ root, capture, compare, log: (line) => log.push(line) });
assert.equal(code, 1);