From c9bc0dbe055bd2d6f46da672c533f06bc6f9236d Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 6 Apr 2026 05:54:29 +0100 Subject: [PATCH] test(plugins): reuse suite temp root helper in install fixture tests --- src/plugins/install.test.ts | 58 +++++++++++-------------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/src/plugins/install.test.ts b/src/plugins/install.test.ts index 1b9df3fce79..04232c202ef 100644 --- a/src/plugins/install.test.ts +++ b/src/plugins/install.test.ts @@ -15,6 +15,7 @@ import { PLUGIN_INSTALL_ERROR_CODE, resolvePluginInstallDir, } from "./install.js"; +import { createSuiteTempRootTracker } from "./test-helpers/fs-fixtures.js"; vi.mock("../process/exec.js", () => ({ runCommandWithTimeout: vi.fn(), @@ -41,14 +42,13 @@ vi.mock("./install.runtime.js", async () => { }; }); -let suiteTempRoot = ""; let suiteFixtureRoot = ""; -let tempDirCounter = 0; const pluginFixturesDir = path.resolve(process.cwd(), "test", "fixtures", "plugins-install"); const archiveFixturePathCache = new Map(); const dynamicArchiveTemplatePathCache = new Map(); let installPluginFromDirTemplateDir = ""; let manifestInstallTemplateDir = ""; +const suiteTempRootTracker = createSuiteTempRootTracker("openclaw-plugin-install"); const DYNAMIC_ARCHIVE_TEMPLATE_PRESETS = [ { outName: "traversal.tgz", @@ -78,28 +78,11 @@ const DYNAMIC_ARCHIVE_TEMPLATE_PRESETS = [ }, ]; -function ensureSuiteTempRoot() { - if (suiteTempRoot) { - return suiteTempRoot; - } - const bundleTempRoot = path.join(process.cwd(), ".tmp"); - fs.mkdirSync(bundleTempRoot, { recursive: true }); - suiteTempRoot = fs.mkdtempSync(path.join(bundleTempRoot, "openclaw-plugin-install-")); - return suiteTempRoot; -} - -function makeTempDir() { - const dir = path.join(ensureSuiteTempRoot(), `case-${String(tempDirCounter)}`); - tempDirCounter += 1; - fs.mkdirSync(dir); - return dir; -} - function ensureSuiteFixtureRoot() { if (suiteFixtureRoot) { return suiteFixtureRoot; } - suiteFixtureRoot = path.join(ensureSuiteTempRoot(), "_fixtures"); + suiteFixtureRoot = path.join(suiteTempRootTracker.ensureSuiteTempRoot(), "_fixtures"); fs.mkdirSync(suiteFixtureRoot, { recursive: true }); return suiteFixtureRoot; } @@ -178,7 +161,7 @@ function expectSuccessfulArchiveInstall(params: { } function setupPluginInstallDirs() { - const tmpDir = makeTempDir(); + const tmpDir = suiteTempRootTracker.makeTempDir(); const pluginDir = path.join(tmpDir, "plugin-src"); const extensionsDir = path.join(tmpDir, "extensions"); fs.mkdirSync(pluginDir, { recursive: true }); @@ -187,7 +170,7 @@ function setupPluginInstallDirs() { } function setupInstallPluginFromDirFixture(params?: { devDependencies?: Record }) { - const caseDir = makeTempDir(); + const caseDir = suiteTempRootTracker.makeTempDir(); const stateDir = path.join(caseDir, "state"); const pluginDir = path.join(caseDir, "plugin"); fs.mkdirSync(stateDir, { recursive: true }); @@ -242,7 +225,7 @@ async function installFromArchiveWithWarnings(params: { } function setupManifestInstallFixture(params: { manifestId: string; packageName?: string }) { - const caseDir = makeTempDir(); + const caseDir = suiteTempRootTracker.makeTempDir(); const stateDir = path.join(caseDir, "state"); const pluginDir = path.join(caseDir, "plugin-src"); fs.mkdirSync(stateDir, { recursive: true }); @@ -319,7 +302,7 @@ function setupBundleInstallFixture(params: { bundleFormat: "codex" | "claude" | "cursor"; name: string; }) { - const caseDir = makeTempDir(); + const caseDir = suiteTempRootTracker.makeTempDir(); const stateDir = path.join(caseDir, "state"); const pluginDir = path.join(caseDir, "plugin-src"); fs.mkdirSync(stateDir, { recursive: true }); @@ -359,7 +342,7 @@ function setupBundleInstallFixture(params: { } function setupManifestlessClaudeInstallFixture() { - const caseDir = makeTempDir(); + const caseDir = suiteTempRootTracker.makeTempDir(); const stateDir = path.join(caseDir, "state"); const pluginDir = path.join(caseDir, "claude-manifestless"); fs.mkdirSync(stateDir, { recursive: true }); @@ -374,7 +357,7 @@ function setupManifestlessClaudeInstallFixture() { } function setupDualFormatInstallFixture(params: { bundleFormat: "codex" | "claude" }) { - const caseDir = makeTempDir(); + const caseDir = suiteTempRootTracker.makeTempDir(); const stateDir = path.join(caseDir, "state"); const pluginDir = path.join(caseDir, "plugin-src"); fs.mkdirSync(path.join(pluginDir, "dist"), { recursive: true }); @@ -443,7 +426,7 @@ async function installArchivePackageAndReturnResult(params: { withDistIndex?: boolean; flatRoot?: boolean; }) { - const stateDir = makeTempDir(); + const stateDir = suiteTempRootTracker.makeTempDir(); const archivePath = await ensureDynamicArchiveTemplate({ outName: params.outName, packageJson: params.packageJson, @@ -490,7 +473,7 @@ async function ensureDynamicArchiveTemplate(params: { if (cachedPath) { return cachedPath; } - const templateDir = makeTempDir(); + const templateDir = suiteTempRootTracker.makeTempDir(); const pkgDir = params.flatRoot ? templateDir : path.join(templateDir, "package"); fs.mkdirSync(pkgDir, { recursive: true }); if (params.withDistIndex) { @@ -514,15 +497,8 @@ async function ensureDynamicArchiveTemplate(params: { afterAll(() => { resetGlobalHookRunner(); - if (!suiteTempRoot) { - return; - } - try { - fs.rmSync(suiteTempRoot, { recursive: true, force: true }); - } finally { - suiteTempRoot = ""; - tempDirCounter = 0; - } + suiteTempRootTracker.cleanup(); + suiteFixtureRoot = ""; }); beforeAll(async () => { @@ -593,7 +569,7 @@ beforeEach(() => { describe("installPluginFromArchive", () => { it("installs scoped archives, rejects duplicate installs, and allows updates", async () => { - const stateDir = makeTempDir(); + const stateDir = suiteTempRootTracker.makeTempDir(); const archiveV1 = getArchiveFixturePath({ cacheKey: "voice-call:0.0.1", outName: "voice-call-0.0.1.tgz", @@ -637,7 +613,7 @@ describe("installPluginFromArchive", () => { }); it("installs from a zip archive", async () => { - const stateDir = makeTempDir(); + const stateDir = suiteTempRootTracker.makeTempDir(); const archivePath = getArchiveFixturePath({ cacheKey: "zipper:0.0.1", outName: "zipper-0.0.1.zip", @@ -653,7 +629,7 @@ describe("installPluginFromArchive", () => { }); it("allows archive installs with dangerous code patterns when forced unsafe install is set", async () => { - const stateDir = makeTempDir(); + const stateDir = suiteTempRootTracker.makeTempDir(); const extensionsDir = path.join(stateDir, "extensions"); fs.mkdirSync(extensionsDir, { recursive: true }); @@ -1323,7 +1299,7 @@ describe("installPluginFromDir", () => { ); it("keeps scoped install-dir validation aligned for real scoped ids", () => { - const extensionsDir = path.join(makeTempDir(), "extensions"); + const extensionsDir = path.join(suiteTempRootTracker.makeTempDir(), "extensions"); const scopedTarget = resolvePluginInstallDir("@scope/name", extensionsDir); const hashedFlatId = safePathSegmentHashed("@scope/name"); const flatTarget = resolvePluginInstallDir(hashedFlatId, extensionsDir);