diff --git a/src/commands/agents.add.test.ts b/src/commands/agents.add.test.ts index 2ae5d61ec0fc..d8d3d2e1b92b 100644 --- a/src/commands/agents.add.test.ts +++ b/src/commands/agents.add.test.ts @@ -1,14 +1,14 @@ // Agents add tests cover agent creation, workspace setup, channel binding, and onboarding integration. import fs from "node:fs/promises"; -import os from "node:os"; import path from "node:path"; -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { AUTH_STORE_VERSION } from "../agents/auth-profiles/constants.js"; import { loadPersistedAuthProfileStore } from "../agents/auth-profiles/persisted.js"; import { saveAuthProfileStore } from "../agents/auth-profiles/store.js"; import { formatCliCommand } from "../cli/command-format.js"; import { closeOpenClawAgentDatabasesForTest } from "../state/openclaw-agent-db.js"; import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js"; +import { createSuiteTempRootTracker } from "../test-helpers/temp-dir.js"; import { withEnvAsync } from "../test-utils/env.js"; import { baseConfigSnapshot, createTestRuntime } from "./test-runtime-config-helpers.js"; @@ -116,6 +116,18 @@ import { agentsAddCommand, testing } from "./agents.commands.add.js"; const runtime = createTestRuntime(); describe("agents add command", () => { + const suiteTempDirs = createSuiteTempRootTracker({ prefix: "openclaw-agents-add-" }); + + beforeAll(async () => { + await suiteTempDirs.setup(); + }); + + afterAll(async () => { + closeOpenClawAgentDatabasesForTest(); + closeOpenClawStateDatabaseForTest(); + await suiteTempDirs.cleanup(); + }); + beforeEach(() => { readConfigFileSnapshotMock.mockClear(); writeConfigFileMock.mockClear(); @@ -136,14 +148,8 @@ describe("agents add command", () => { prefix: string, run: (root: string) => Promise, ): Promise { - const root = await fs.mkdtemp(path.join(os.tmpdir(), prefix)); - try { - await withEnvAsync({ OPENCLAW_STATE_DIR: root }, async () => await run(root)); - } finally { - closeOpenClawAgentDatabasesForTest(); - closeOpenClawStateDatabaseForTest(); - await fs.rm(root, { recursive: true, force: true }); - } + const root = await suiteTempDirs.make(prefix); + await withEnvAsync({ OPENCLAW_STATE_DIR: root }, async () => await run(root)); } it("requires --workspace when flags are present", async () => { diff --git a/src/commands/doctor-plugin-manifests.test.ts b/src/commands/doctor-plugin-manifests.test.ts index 2cefe9354284..bfa3de4dea4e 100644 --- a/src/commands/doctor-plugin-manifests.test.ts +++ b/src/commands/doctor-plugin-manifests.test.ts @@ -1,25 +1,21 @@ // Doctor plugin manifest tests cover manifest validation, missing installs, and repair guidance. import fs from "node:fs"; import path from "node:path"; -import { afterEach, describe, expect, it, vi } from "vitest"; +import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { cleanupTrackedTempDirs } from "../plugins/test-helpers/fs-fixtures.js"; import type { RuntimeEnv } from "../runtime.js"; +import { createSuiteTempRootTracker } from "../test-helpers/temp-dir.js"; import { collectLegacyPluginManifestContractMigrations, maybeRepairLegacyPluginManifestContracts, } from "./doctor-plugin-manifests.js"; import type { DoctorPrompter } from "./doctor-prompter.js"; -const tempDirs: string[] = []; - -function makeTrustedBundledPluginsDir() { - const fixturesRoot = path.join(process.cwd(), "dist", "extensions"); - fs.mkdirSync(fixturesRoot, { recursive: true }); - const dir = fs.mkdtempSync(path.join(fixturesRoot, "openclaw-doctor-plugin-manifests-")); - tempDirs.push(dir); - return dir; -} +const fixturesRoot = path.join(process.cwd(), "dist", "extensions"); +const suiteTempDirs = createSuiteTempRootTracker({ + prefix: "openclaw-doctor-plugin-manifests-", + parentDir: fixturesRoot, +}); function configWithPluginLoadPath(pluginRoot: string): OpenClawConfig { return { @@ -86,13 +82,21 @@ function createPrompter(overrides: Partial = {}): DoctorPrompter } describe("doctor plugin manifest legacy contract repair", () => { + beforeAll(async () => { + fs.mkdirSync(fixturesRoot, { recursive: true }); + await suiteTempDirs.setup(); + }); + + afterAll(async () => { + await suiteTempDirs.cleanup(); + }); + afterEach(() => { - cleanupTrackedTempDirs(tempDirs); vi.restoreAllMocks(); }); - it("collects legacy top-level capability keys for migration", () => { - const pluginsRoot = makeTrustedBundledPluginsDir(); + it("collects legacy top-level capability keys for migration", async () => { + const pluginsRoot = await suiteTempDirs.make("legacy-capability"); const root = path.join(pluginsRoot, "openai"); fs.mkdirSync(root, { recursive: true }); writePackageJson(root); @@ -129,8 +133,8 @@ describe("doctor plugin manifest legacy contract repair", () => { ]); }); - it("collects legacy top-level plugin tool keys for migration", () => { - const pluginsRoot = makeTrustedBundledPluginsDir(); + it("collects legacy top-level plugin tool keys for migration", async () => { + const pluginsRoot = await suiteTempDirs.make("legacy-tool"); const root = path.join(pluginsRoot, "cortex"); fs.mkdirSync(root, { recursive: true }); writePackageJson(root); @@ -166,7 +170,7 @@ describe("doctor plugin manifest legacy contract repair", () => { }); it("rewrites legacy top-level capability keys into contracts", async () => { - const pluginsRoot = makeTrustedBundledPluginsDir(); + const pluginsRoot = await suiteTempDirs.make("rewrite-capability"); const root = path.join(pluginsRoot, "openai"); fs.mkdirSync(root, { recursive: true }); writePackageJson(root); @@ -207,7 +211,7 @@ describe("doctor plugin manifest legacy contract repair", () => { }); it("removes duplicate legacy top-level plugin tools while keeping contracts.tools", async () => { - const pluginsRoot = makeTrustedBundledPluginsDir(); + const pluginsRoot = await suiteTempDirs.make("dedupe-tool"); const root = path.join(pluginsRoot, "cortex"); fs.mkdirSync(root, { recursive: true }); writePackageJson(root); @@ -241,8 +245,8 @@ describe("doctor plugin manifest legacy contract repair", () => { }); }); - it("ignores non-object contracts payloads when collecting migrations", () => { - const pluginsRoot = makeTrustedBundledPluginsDir(); + it("ignores non-object contracts payloads when collecting migrations", async () => { + const pluginsRoot = await suiteTempDirs.make("non-object-contracts"); const root = path.join(pluginsRoot, "openai"); fs.mkdirSync(root, { recursive: true }); writePackageJson(root); diff --git a/src/commands/doctor-security.test.ts b/src/commands/doctor-security.test.ts index 4cf437013ee8..5b141707d66a 100644 --- a/src/commands/doctor-security.test.ts +++ b/src/commands/doctor-security.test.ts @@ -1,9 +1,9 @@ // Doctor security tests cover security audit checks, config findings, and repair output. import fs from "node:fs/promises"; -import os from "node:os"; import path from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; +import { withTempDir } from "../test-helpers/temp-dir.js"; const note = vi.hoisted(() => vi.fn()); const pluginRegistry = vi.hoisted(() => ({ list: [] as unknown[] })); @@ -72,14 +72,15 @@ describe("noteSecurityWarnings gateway exposure", () => { file: Record, run: () => Promise, ): Promise { - const home = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-doctor-security-")); - process.env.HOME = home; - await fs.mkdir(path.join(home, ".openclaw"), { recursive: true }); - await fs.writeFile( - path.join(home, ".openclaw", "exec-approvals.json"), - JSON.stringify(file, null, 2), - ); - await run(); + await withTempDir({ prefix: "openclaw-doctor-security-" }, async (home) => { + process.env.HOME = home; + await fs.mkdir(path.join(home, ".openclaw"), { recursive: true }); + await fs.writeFile( + path.join(home, ".openclaw", "exec-approvals.json"), + JSON.stringify(file, null, 2), + ); + await run(); + }); } async function expectAgentExecHostPolicyWarning(agentKey: "*" | "runner") { diff --git a/src/commands/migrate/apply.test.ts b/src/commands/migrate/apply.test.ts index 2572e39d909c..122b6bc7ac9b 100644 --- a/src/commands/migrate/apply.test.ts +++ b/src/commands/migrate/apply.test.ts @@ -1,13 +1,12 @@ // Migration apply tests cover backups, filtering, provider apply calls, and report output. -import { mkdtempSync } from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { describe, expect, it, vi } from "vitest"; +import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import type { MigrationPlan, MigrationProviderPlugin } from "../../plugins/types.js"; import { createNonExitingRuntime } from "../../runtime.js"; +import { createSuiteTempRootTracker } from "../../test-helpers/temp-dir.js"; import { runMigrationApply } from "./apply.js"; -const stateDir = mkdtempSync(path.join(tmpdir(), "openclaw-migrate-apply-")); +let stateDir = ""; +const suiteTempDirs = createSuiteTempRootTracker({ prefix: "openclaw-migrate-apply-" }); vi.mock("../../config/paths.js", async (importActual) => { const actual = await importActual(); @@ -36,6 +35,14 @@ function buildEmptyPlan(): MigrationPlan { } describe("runMigrationApply", () => { + beforeAll(async () => { + stateDir = await suiteTempDirs.setup(); + }); + + afterAll(async () => { + await suiteTempDirs.cleanup(); + }); + it("uses the resolved provider id when forwarding Codex options", async () => { const plan = vi.fn(async () => buildEmptyPlan()); const apply = vi.fn(async () => buildEmptyPlan());