From ef2d8a0bf41734156aaed2e7199b05cdcff9a722 Mon Sep 17 00:00:00 2001 From: masonxhuang Date: Wed, 27 May 2026 18:02:06 +0800 Subject: [PATCH] test: tie script tmp dirs to cleanup hooks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...led-plugin-install-uninstall-probe.test.ts | 15 ++++--- test/scripts/ci-docker-pull-retry.test.ts | 18 ++++++--- test/scripts/committer.test.ts | 7 +++- test/scripts/crabbox-wrapper.test.ts | 30 ++++++++------ .../dependency-vulnerability-gate.test.ts | 11 ++++- ...nerate-dependency-release-evidence.test.ts | 11 ++++- test/scripts/live-docker-auth.test.ts | 21 +++++----- ...ld-telegram-desktop-proof-evidence.test.ts | 14 ++++--- test/scripts/package-mac-app.test.ts | 40 ++++++++++++++----- test/scripts/plugin-gateway-gauntlet.test.ts | 12 +++--- test/scripts/rtt-harness.test.ts | 16 ++++---- test/scripts/source-file-scan-cache.test.ts | 6 +-- .../test-built-status-message-runtime.test.ts | 10 +++-- test/scripts/vitest-shard-timings.test.ts | 10 +++-- 14 files changed, 143 insertions(+), 78 deletions(-) diff --git a/test/scripts/bundled-plugin-install-uninstall-probe.test.ts b/test/scripts/bundled-plugin-install-uninstall-probe.test.ts index a15bec47a6b..a56f61d6a85 100644 --- a/test/scripts/bundled-plugin-install-uninstall-probe.test.ts +++ b/test/scripts/bundled-plugin-install-uninstall-probe.test.ts @@ -7,7 +7,7 @@ import path from "node:path"; import { pathToFileURL } from "node:url"; import { afterEach, describe, expect, it } from "vitest"; -const tempDirs: string[] = []; +const tempDirCleanups: Array<() => void> = []; const probePath = path.resolve("scripts/e2e/lib/bundled-plugin-install-uninstall/probe.mjs"); const runtimeSmokePath = path.resolve( "scripts/e2e/lib/bundled-plugin-install-uninstall/runtime-smoke.mjs", @@ -22,7 +22,9 @@ type PluginListEntry = { function makePackageRoot(): string { const root = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-bundled-probe-")); - tempDirs.push(root); + tempDirCleanups.push(() => { + fs.rmSync(root, { force: true, recursive: true }); + }); fs.writeFileSync(path.join(root, "package.json"), '{"type":"module"}\n', "utf8"); fs.mkdirSync(path.join(root, "dist"), { recursive: true }); return root; @@ -127,8 +129,8 @@ async function closeServer(server: HttpServer | NetServer): Promise { } afterEach(() => { - for (const dir of tempDirs.splice(0)) { - fs.rmSync(dir, { force: true, recursive: true }); + for (const cleanup of tempDirCleanups.splice(0)) { + cleanup(); } }); @@ -212,7 +214,10 @@ describe("bundled plugin install/uninstall probe", () => { it("creates runtime smoke state with OPENCLAW_HOME at the test home", async () => { const runtimeSmoke = await import(pathToFileURL(runtimeSmokePath).href); const env = runtimeSmoke.createIsolatedStateEnv("runtime-env"); - tempDirs.push(path.dirname(env.HOME)); + const homeRoot = path.dirname(env.HOME); + tempDirCleanups.push(() => { + fs.rmSync(homeRoot, { force: true, recursive: true }); + }); expect(env.USERPROFILE).toBe(env.HOME); expect(env.OPENCLAW_HOME).toBe(env.HOME); diff --git a/test/scripts/ci-docker-pull-retry.test.ts b/test/scripts/ci-docker-pull-retry.test.ts index e56fa393df7..4e3907b1942 100644 --- a/test/scripts/ci-docker-pull-retry.test.ts +++ b/test/scripts/ci-docker-pull-retry.test.ts @@ -5,11 +5,13 @@ import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; const SCRIPT_PATH = path.resolve("scripts/ci-docker-pull-retry.sh"); -const tempDirs: string[] = []; +const tempDirCleanups: Array<() => void> = []; function makeTempBin(prefix: string) { const dir = mkdtempSync(path.join(tmpdir(), prefix)); - tempDirs.push(dir); + tempDirCleanups.push(() => { + rmSync(dir, { force: true, recursive: true }); + }); return dir; } @@ -38,8 +40,8 @@ function runPullHelperWithEnv(binDir: string, env: Record) { } afterEach(() => { - while (tempDirs.length > 0) { - rmSync(tempDirs.pop()!, { force: true, recursive: true }); + while (tempDirCleanups.length > 0) { + tempDirCleanups.pop()!(); } }); @@ -128,7 +130,9 @@ describe("scripts/ci-docker-pull-retry.sh", () => { const result = runPullHelper(binDir); expect(result.status).toBe(127); - expect(result.stderr).toContain("timeout command not found; cannot bound Docker pull after 42s"); + expect(result.stderr).toContain( + "timeout command not found; cannot bound Docker pull after 42s", + ); expect(existsSync(dockerArgsPath)).toBe(false); }); @@ -162,6 +166,8 @@ describe("scripts/ci-docker-pull-retry.sh", () => { expect(result.status).toBe(42); expect(result.stderr).toContain("Docker pull failed or timed out after 42s: status=42"); - expect(execFileSync("wc", ["-l", dockerArgsPath], { encoding: "utf8" }).trim()).toMatch(/^2\b/u); + expect(execFileSync("wc", ["-l", dockerArgsPath], { encoding: "utf8" }).trim()).toMatch( + /^2\b/u, + ); }); }); diff --git a/test/scripts/committer.test.ts b/test/scripts/committer.test.ts index a5b39efb168..3c0f7a86023 100644 --- a/test/scripts/committer.test.ts +++ b/test/scripts/committer.test.ts @@ -8,6 +8,7 @@ import { createScriptTestHarness } from "./test-helpers.js"; const scriptPath = path.join(process.cwd(), "scripts", "committer"); const { createTempDir } = createScriptTestHarness(); let templateRepo: string; +let templateRepoCleanup: (() => void) | null = null; function run(cwd: string, command: string, args: string[]) { return execFileSync(command, args, { @@ -28,6 +29,9 @@ function createRepo() { function createTemplateRepo() { const repo = mkdtempSync(path.join(tmpdir(), "committer-template-")); + templateRepoCleanup = () => { + rmSync(repo, { recursive: true, force: true }); + }; git(repo, "init", "-q"); git(repo, "config", "user.email", "test@example.com"); git(repo, "config", "user.name", "Test User"); @@ -83,7 +87,8 @@ describe("scripts/committer", () => { }); afterAll(() => { - rmSync(templateRepo, { recursive: true, force: true }); + templateRepoCleanup?.(); + templateRepoCleanup = null; }); it("accepts supported path argument shapes", () => { diff --git a/test/scripts/crabbox-wrapper.test.ts b/test/scripts/crabbox-wrapper.test.ts index 0c75d02fa11..0d4dbba0821 100644 --- a/test/scripts/crabbox-wrapper.test.ts +++ b/test/scripts/crabbox-wrapper.test.ts @@ -4,7 +4,7 @@ import { tmpdir } from "node:os"; import path from "node:path"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; -const tempDirs: string[] = []; +const tempDirCleanups: Array<() => void> = []; const repoRoot = process.cwd(); const fakeCrabboxBinDirs = new Map(); @@ -14,7 +14,9 @@ function makeFakeCrabbox(helpText: string): string { return cached; } const binDir = mkdtempSync(path.join(tmpdir(), "openclaw-fake-crabbox-")); - tempDirs.push(binDir); + tempDirCleanups.push(() => { + rmSync(binDir, { recursive: true, force: true }); + }); writeFakeCrabbox(binDir, helpText); fakeCrabboxBinDirs.set(helpText, binDir); return binDir; @@ -126,7 +128,9 @@ function makeFakeGit( responses: Record, ): string { const binDir = mkdtempSync(path.join(tmpdir(), "openclaw-fake-git-")); - tempDirs.push(binDir); + tempDirCleanups.push(() => { + rmSync(binDir, { recursive: true, force: true }); + }); const gitPath = path.join(binDir, "git"); if (process.platform !== "win32") { const script = [ @@ -272,8 +276,8 @@ function expectGroupedShellCommand(remoteCommand: string, command: string): void } afterAll(() => { - for (const dir of tempDirs.splice(0)) { - rmSync(dir, { recursive: true, force: true }); + for (const cleanup of tempDirCleanups.splice(0)) { + cleanup(); } }); @@ -386,11 +390,9 @@ describe.concurrent("scripts/crabbox-wrapper", () => { }); it("keeps explicit provider env overrides for Windows runs", () => { - const result = runWrapper( - azureProviderHelp, - ["run", "--target", "windows", "--", "echo ok"], - { env: { CRABBOX_PROVIDER: "aws" } }, - ); + const result = runWrapper(azureProviderHelp, ["run", "--target", "windows", "--", "echo ok"], { + env: { CRABBOX_PROVIDER: "aws" }, + }); expect(result.status).toBe(0); expect(parseFakeCrabboxOutput(result).args).toEqual([ @@ -1400,7 +1402,9 @@ describe.concurrent("scripts/crabbox-wrapper", () => { "finds a Crabbox checkout next to the Git common dir in linked worktrees", () => { const fakeWorkspaceParent = mkdtempSync(path.join(tmpdir(), "openclaw-linked-worktree-")); - tempDirs.push(fakeWorkspaceParent); + tempDirCleanups.push(() => { + rmSync(fakeWorkspaceParent, { recursive: true, force: true }); + }); const gitCommonDir = path.join(fakeWorkspaceParent, "openclaw", ".git"); const crabboxBinDir = path.join(fakeWorkspaceParent, "crabbox", "bin"); mkdirSync(gitCommonDir, { recursive: true }); @@ -1460,7 +1464,9 @@ describe.concurrent("scripts/crabbox-wrapper", () => { if (process.platform !== "win32") { it("keeps POSIX PATH lookup semantics for non-executable entries", () => { const staleBinDir = mkdtempSync(path.join(tmpdir(), "openclaw-stale-crabbox-")); - tempDirs.push(staleBinDir); + tempDirCleanups.push(() => { + rmSync(staleBinDir, { recursive: true, force: true }); + }); writeFileSync(path.join(staleBinDir, "crabbox"), "not executable\n", "utf8"); const result = runWrapper("provider: aws\n", ["run", "--provider", "aws", "--", "echo ok"], { extraPathEntries: [staleBinDir], diff --git a/test/scripts/dependency-vulnerability-gate.test.ts b/test/scripts/dependency-vulnerability-gate.test.ts index e49181d2338..0db999664ee 100644 --- a/test/scripts/dependency-vulnerability-gate.test.ts +++ b/test/scripts/dependency-vulnerability-gate.test.ts @@ -1,13 +1,19 @@ -import { mkdtemp, writeFile } from "node:fs/promises"; +import { mkdtemp, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; -import { describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it } from "vitest"; import { classifyVulnerabilityFindings, renderDependencyVulnerabilityGateMarkdownReport, runDependencyVulnerabilityGate, } from "../../scripts/dependency-vulnerability-gate.mjs"; +const tempDirCleanups: Array<() => Promise> = []; + +afterEach(async () => { + await Promise.all(tempDirCleanups.splice(0).map((cleanup) => cleanup())); +}); + function advisory({ id, severity, @@ -97,6 +103,7 @@ describe("dependency-vulnerability-gate", () => { it("queries full and production lockfile graphs separately", async () => { const rootDir = await mkdtemp(path.join(tmpdir(), "openclaw-vuln-gate-")); + tempDirCleanups.push(() => rm(rootDir, { recursive: true, force: true })); await writeLockfile(rootDir); const payloads: Record[] = []; diff --git a/test/scripts/generate-dependency-release-evidence.test.ts b/test/scripts/generate-dependency-release-evidence.test.ts index 85a4266b6f1..ab303722c7b 100644 --- a/test/scripts/generate-dependency-release-evidence.test.ts +++ b/test/scripts/generate-dependency-release-evidence.test.ts @@ -1,7 +1,7 @@ -import { mkdtemp, readFile, writeFile } from "node:fs/promises"; +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; -import { describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it } from "vitest"; import { DEPENDENCY_EVIDENCE_REPORTS, collectDependencyEvidenceSummaryCounts, @@ -12,6 +12,12 @@ import { resolveReleaseTag, } from "../../scripts/generate-dependency-release-evidence.mjs"; +const tempDirCleanups: Array<() => Promise> = []; + +afterEach(async () => { + await Promise.all(tempDirCleanups.splice(0).map((cleanup) => cleanup())); +}); + async function writeJson(dir: string, fileName: string, value: unknown) { await writeFile(path.join(dir, fileName), `${JSON.stringify(value, null, 2)}\n`, "utf8"); } @@ -105,6 +111,7 @@ describe("generate-dependency-release-evidence", () => { it("collects report counts and renders human summaries", async () => { const dir = await mkdtemp(path.join(tmpdir(), "openclaw-release-dependency-evidence-test-")); + tempDirCleanups.push(() => rm(dir, { recursive: true, force: true })); await writeJson(dir, "dependency-vulnerability-gate.json", { blockers: [{ id: "GHSA-blocker" }], findings: [{ id: "GHSA-blocker" }, { id: "GHSA-report" }], diff --git a/test/scripts/live-docker-auth.test.ts b/test/scripts/live-docker-auth.test.ts index 7db40bce185..bf403d68486 100644 --- a/test/scripts/live-docker-auth.test.ts +++ b/test/scripts/live-docker-auth.test.ts @@ -4,11 +4,13 @@ import { tmpdir } from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -const tempDirs: string[] = []; +const tempDirCleanups: Array<() => void> = []; function makeTempBin(prefix: string) { const dir = mkdtempSync(path.join(tmpdir(), prefix)); - tempDirs.push(dir); + tempDirCleanups.push(() => { + rmSync(dir, { force: true, recursive: true }); + }); return dir; } @@ -60,8 +62,8 @@ function failDockerRunArgs(pathPrefix: string) { } afterEach(() => { - while (tempDirs.length > 0) { - rmSync(tempDirs.pop()!, { force: true, recursive: true }); + while (tempDirCleanups.length > 0) { + tempDirCleanups.pop()!(); } }); @@ -93,14 +95,9 @@ describe("scripts/lib/live-docker-auth.sh", () => { const binDir = makeTempBin("openclaw-live-docker-auth-plain-"); writeExecutable( path.join(binDir, "timeout"), - [ - "#!/bin/sh", - 'if [ "$1" = "--kill-after=1s" ]; then', - " exit 1", - "fi", - "exit 0", - "", - ].join("\n"), + ["#!/bin/sh", 'if [ "$1" = "--kill-after=1s" ]; then', " exit 1", "fi", "exit 0", ""].join( + "\n", + ), ); expect(resolveDockerRunArgs(binDir)).toEqual(["timeout", "42s", "docker", "run"]); diff --git a/test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts b/test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts index 64de2a61a03..92b5e8859c6 100644 --- a/test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts +++ b/test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts @@ -8,17 +8,19 @@ import { renderEvidenceComment, } from "../../scripts/mantis/publish-pr-evidence.mjs"; -const tempDirs: string[] = []; +const tempDirCleanups: Array<() => void> = []; afterEach(() => { - for (const dir of tempDirs.splice(0)) { - rmSync(dir, { recursive: true, force: true }); + for (const cleanup of tempDirCleanups.splice(0)) { + cleanup(); } }); function makeLane(name: string) { const repo = mkdtempSync(path.join(tmpdir(), `mantis-telegram-${name}-repo-`)); - tempDirs.push(repo); + tempDirCleanups.push(() => { + rmSync(repo, { recursive: true, force: true }); + }); const outputDir = path.join(repo, ".artifacts", "qa-e2e", name); mkdirSync(outputDir, { recursive: true }); const gif = path.join(outputDir, "telegram-user-crabbox-session-motion-telegram-window.gif"); @@ -49,7 +51,9 @@ describe("scripts/mantis/build-telegram-desktop-proof-evidence", () => { const baseline = makeLane("baseline"); const candidate = makeLane("candidate"); const outputDir = mkdtempSync(path.join(tmpdir(), "mantis-telegram-proof-")); - tempDirs.push(outputDir); + tempDirCleanups.push(() => { + rmSync(outputDir, { recursive: true, force: true }); + }); const result = writeTelegramDesktopProofEvidence([ "--output-dir", diff --git a/test/scripts/package-mac-app.test.ts b/test/scripts/package-mac-app.test.ts index 035454e379a..74587274c7a 100644 --- a/test/scripts/package-mac-app.test.ts +++ b/test/scripts/package-mac-app.test.ts @@ -4,12 +4,14 @@ import { tmpdir } from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -const tempDirs: string[] = []; +const tempDirCleanups: Array<() => void> = []; const scriptPath = "scripts/package-mac-app.sh"; function makePlist(): string { const dir = mkdtempSync(path.join(tmpdir(), "openclaw-plistbuddy-")); - tempDirs.push(dir); + tempDirCleanups.push(() => { + rmSync(dir, { recursive: true, force: true }); + }); const plist = path.join(dir, "Info.plist"); writeFileSync( plist, @@ -48,8 +50,8 @@ function getPackageManagerHelperBlock(): string { } afterEach(() => { - for (const dir of tempDirs.splice(0)) { - rmSync(dir, { recursive: true, force: true }); + for (const cleanup of tempDirCleanups.splice(0)) { + cleanup(); } }); @@ -71,7 +73,14 @@ describe("package-mac-app plist stamping", () => { const tempRoot = mkdtempSync(path.join(tmpdir(), "openclaw-package-pnpm-root-")); const toolsDir = mkdtempSync(path.join(tmpdir(), "openclaw-package-pnpm-tools-")); const logPath = path.join(tempRoot, "corepack.log"); - tempDirs.push(tempRoot, toolsDir); + tempDirCleanups.push( + () => { + rmSync(tempRoot, { recursive: true, force: true }); + }, + () => { + rmSync(toolsDir, { recursive: true, force: true }); + }, + ); const corepackPath = path.join(toolsDir, "corepack"); writeFileSync( @@ -79,8 +88,8 @@ describe("package-mac-app plist stamping", () => { [ "#!/usr/bin/env bash", "set -euo pipefail", - "printf '%s|%s\\n' \"$PWD\" \"$*\" >> \"$OPENCLAW_TEST_LOG\"", - "if [[ \"${1:-}\" == \"pnpm\" && \"${2:-}\" == \"--version\" ]]; then", + 'printf \'%s|%s\\n\' "$PWD" "$*" >> "$OPENCLAW_TEST_LOG"', + 'if [[ "${1:-}" == "pnpm" && "${2:-}" == "--version" ]]; then', " echo '11.2.2'", "fi", "", @@ -112,7 +121,14 @@ describe("package-mac-app plist stamping", () => { const helperBlock = getPackageManagerHelperBlock(); const tempRoot = mkdtempSync(path.join(tmpdir(), "openclaw-package-pnpm-root-")); const toolsDir = mkdtempSync(path.join(tmpdir(), "openclaw-package-pnpm-tools-")); - tempDirs.push(tempRoot, toolsDir); + tempDirCleanups.push( + () => { + rmSync(tempRoot, { recursive: true, force: true }); + }, + () => { + rmSync(toolsDir, { recursive: true, force: true }); + }, + ); const result = runHelper(` set -euo pipefail @@ -156,11 +172,15 @@ describe("package-mac-app plist stamping", () => { it("fails closed when required bundled resources are missing", () => { const script = readFileSync(scriptPath, "utf8"); const modelCatalogBlock = script.slice( - script.indexOf('MODEL_CATALOG_SRC="$ROOT_DIR/node_modules/@earendil-works/pi-ai/dist/models.generated.js"'), + script.indexOf( + 'MODEL_CATALOG_SRC="$ROOT_DIR/node_modules/@earendil-works/pi-ai/dist/models.generated.js"', + ), script.indexOf('echo "📦 Copying Control UI assets"'), ); const openClawKitBlock = script.slice( - script.indexOf('OPENCLAWKIT_BUNDLE="$(build_path_for_arch "$PRIMARY_ARCH")/$BUILD_CONFIG/OpenClawKit_OpenClawKit.bundle"'), + script.indexOf( + 'OPENCLAWKIT_BUNDLE="$(build_path_for_arch "$PRIMARY_ARCH")/$BUILD_CONFIG/OpenClawKit_OpenClawKit.bundle"', + ), script.indexOf('echo "📦 Copying Textual resources"'), ); diff --git a/test/scripts/plugin-gateway-gauntlet.test.ts b/test/scripts/plugin-gateway-gauntlet.test.ts index 93a752d6c34..32f02f1ebfd 100644 --- a/test/scripts/plugin-gateway-gauntlet.test.ts +++ b/test/scripts/plugin-gateway-gauntlet.test.ts @@ -23,14 +23,18 @@ import { describe("plugin gateway gauntlet helpers", () => { let repoRoot: string; + let repoRootCleanup: (() => Promise) | null = null; beforeEach(async () => { - repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), "plugin-gauntlet-")); + const tempRepoRoot = await fs.mkdtemp(path.join(os.tmpdir(), "plugin-gauntlet-")); + repoRoot = tempRepoRoot; + repoRootCleanup = () => fs.rm(tempRepoRoot, { recursive: true, force: true }); await fs.mkdir(path.join(repoRoot, "extensions"), { recursive: true }); }); afterEach(async () => { - await fs.rm(repoRoot, { recursive: true, force: true }); + await repoRootCleanup?.(); + repoRootCleanup = null; }); async function writeManifest(pluginDir: string, fileName: string, source: string) { @@ -332,9 +336,7 @@ describe("plugin gateway gauntlet helpers", () => { it("does not count prebuild setup as gauntlet work", () => { expect(hasGauntletWorkRows([])).toBe(false); expect(hasGauntletWorkRows([{ phase: "prebuild" }])).toBe(false); - expect(hasGauntletWorkRows([{ phase: "prebuild" }, { phase: "lifecycle:install" }])).toBe( - true, - ); + expect(hasGauntletWorkRows([{ phase: "prebuild" }, { phase: "lifecycle:install" }])).toBe(true); expect(hasGauntletWorkRows([{ phase: "slash:help" }])).toBe(true); expect(hasGauntletWorkRows([{ phase: "qa:rpc" }])).toBe(true); }); diff --git a/test/scripts/rtt-harness.test.ts b/test/scripts/rtt-harness.test.ts index 06ce5b90a5e..6c564c7e60f 100644 --- a/test/scripts/rtt-harness.test.ts +++ b/test/scripts/rtt-harness.test.ts @@ -27,10 +27,10 @@ const CREDENTIAL_SCRIPT_PATH = path.resolve( ); const CONFIG_SCRIPT_PATH = path.resolve(TEST_DIR, "../../scripts/e2e/npm-telegram-rtt-config.mjs"); const execFileAsync = promisify(execFile); -const tempDirs: string[] = []; +const tempDirCleanups: Array<() => Promise> = []; afterEach(async () => { - await Promise.all(tempDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true }))); + await Promise.all(tempDirCleanups.splice(0).map((cleanup) => cleanup())); }); describe("RTT harness", () => { @@ -149,8 +149,8 @@ describe("RTT harness", () => { expect(script).toContain( '"$timeout_bin" --kill-after=30s "$npm_install_timeout" npm install -g "$install_source" --no-fund --no-audit', ); - expect(script).toContain('elif command -v gtimeout >/dev/null 2>&1; then'); - expect(script).toContain("timeout_bin=\"gtimeout\""); + expect(script).toContain("elif command -v gtimeout >/dev/null 2>&1; then"); + expect(script).toContain('timeout_bin="gtimeout"'); expect(script).toContain( 'echo "timeout or gtimeout is required for OPENCLAW_E2E_NPM_INSTALL_TIMEOUT=$npm_install_timeout" >&2', ); @@ -158,7 +158,9 @@ describe("RTT harness", () => { expect(script).toContain( '"$timeout_bin" "$npm_install_timeout" npm install -g "$install_source" --no-fund --no-audit', ); - expect(script).not.toContain("running package install without OPENCLAW_E2E_NPM_INSTALL_TIMEOUT"); + expect(script).not.toContain( + "running package install without OPENCLAW_E2E_NPM_INSTALL_TIMEOUT", + ); expect(script).toContain("run_logged docker_e2e_docker_run_cmd run --rm"); expect(script).not.toContain("run_logged docker run --rm"); expect(heartbeatStartIndex).toBeGreaterThan(sourceIndex); @@ -180,7 +182,7 @@ describe("RTT harness", () => { it("generates final-only Telegram RTT delivery config for release packages", async () => { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-rtt-config-test-")); - tempDirs.push(tempDir); + tempDirCleanups.push(() => fs.rm(tempDir, { recursive: true, force: true })); const configPath = path.join(tempDir, "config.json"); await execFileAsync(process.execPath, [ @@ -292,7 +294,7 @@ describe("RTT harness", () => { it("appends JSONL rows", async () => { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-rtt-test-")); - tempDirs.push(tempDir); + tempDirCleanups.push(() => fs.rm(tempDir, { recursive: true, force: true })); const jsonlPath = path.join(tempDir, "data/rtt.jsonl"); await appendJsonl(jsonlPath, { run: 1 }); await appendJsonl(jsonlPath, { run: 2 }); diff --git a/test/scripts/source-file-scan-cache.test.ts b/test/scripts/source-file-scan-cache.test.ts index 25f70a59934..9dc1b447aa0 100644 --- a/test/scripts/source-file-scan-cache.test.ts +++ b/test/scripts/source-file-scan-cache.test.ts @@ -4,17 +4,17 @@ import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { collectSourceFileContents } from "../../scripts/lib/source-file-scan-cache.mjs"; -const tempDirs: string[] = []; +const tempDirCleanups: Array<() => Promise> = []; async function makeTempRepo() { const repoRoot = await mkdtemp(path.join(os.tmpdir(), "openclaw-source-scan-")); - tempDirs.push(repoRoot); + tempDirCleanups.push(() => rm(repoRoot, { recursive: true, force: true })); return repoRoot; } describe("source file scan cache", () => { afterEach(async () => { - await Promise.all(tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true }))); + await Promise.all(tempDirCleanups.splice(0).map((cleanup) => cleanup())); }); it("bounds concurrent source file reads while preserving sorted output", async () => { diff --git a/test/scripts/test-built-status-message-runtime.test.ts b/test/scripts/test-built-status-message-runtime.test.ts index 558732e1bf5..2080dcf36ba 100644 --- a/test/scripts/test-built-status-message-runtime.test.ts +++ b/test/scripts/test-built-status-message-runtime.test.ts @@ -5,17 +5,19 @@ import { afterEach, describe, expect, it } from "vitest"; import { findBuiltStatusMessageRuntimePath } from "../../scripts/test-built-status-message-runtime.mjs"; import { expectNoReaddirSyncDuring } from "../../src/test-utils/fs-scan-assertions.js"; -const tempDirs: string[] = []; +const tempDirCleanups: Array<() => void> = []; afterEach(() => { - for (const dir of tempDirs.splice(0)) { - fs.rmSync(dir, { recursive: true, force: true }); + for (const cleanup of tempDirCleanups.splice(0)) { + cleanup(); } }); function makeDistDir(): string { const root = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-status-runtime-")); - tempDirs.push(root); + tempDirCleanups.push(() => { + fs.rmSync(root, { recursive: true, force: true }); + }); const distDir = path.join(root, "dist"); fs.mkdirSync(distDir, { recursive: true }); return distDir; diff --git a/test/scripts/vitest-shard-timings.test.ts b/test/scripts/vitest-shard-timings.test.ts index ed82d77c08f..caa75080c9d 100644 --- a/test/scripts/vitest-shard-timings.test.ts +++ b/test/scripts/vitest-shard-timings.test.ts @@ -9,11 +9,11 @@ import { writeShardTimings, } from "../../scripts/lib/vitest-shard-timings.mjs"; -const tempDirs: string[] = []; +const tempDirCleanups: Array<() => void> = []; afterEach(() => { - for (const dir of tempDirs.splice(0)) { - fs.rmSync(dir, { recursive: true, force: true }); + for (const cleanup of tempDirCleanups.splice(0)) { + cleanup(); } }); @@ -56,7 +56,9 @@ describe("scripts/lib/vitest-shard-timings.mjs", () => { it("persists include-pattern timing metadata", () => { const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-shard-timings-")); - tempDirs.push(tempDir); + tempDirCleanups.push(() => { + fs.rmSync(tempDir, { recursive: true, force: true }); + }); const env = { OPENCLAW_TEST_PROJECTS_TIMINGS_PATH: path.join(tempDir, "timings.json"), OPENCLAW_VITEST_SHARD_NAME: "auto-reply-reply-agent-runner",