test(plugins): share suite temp root helper in install path tests

This commit is contained in:
Vincent Koc
2026-04-06 05:53:53 +01:00
parent 17d7483404
commit c75cdf6b0b
3 changed files with 60 additions and 70 deletions

View File

@@ -8,6 +8,7 @@ import {
mockNpmPackMetadataResult,
} from "../test-utils/npm-spec-install-test-helpers.js";
import { installPluginFromNpmSpec, PLUGIN_INSTALL_ERROR_CODE } from "./install.js";
import { createSuiteTempRootTracker } from "./test-helpers/fs-fixtures.js";
const runCommandWithTimeoutMock = vi.fn();
@@ -15,27 +16,9 @@ vi.mock("../process/exec.js", () => ({
runCommandWithTimeout: (...args: unknown[]) => runCommandWithTimeoutMock(...args),
}));
let suiteTempRoot = "";
let tempDirCounter = 0;
const dynamicArchiveTemplatePathCache = new Map<string, string>();
const pluginFixturesDir = path.resolve(process.cwd(), "test", "fixtures", "plugins-install");
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-npm-spec-"));
return suiteTempRoot;
}
function makeTempDir() {
const dir = path.join(ensureSuiteTempRoot(), `case-${String(tempDirCounter)}`);
tempDirCounter += 1;
fs.mkdirSync(dir);
return dir;
}
const suiteTempRootTracker = createSuiteTempRootTracker("openclaw-plugin-install-npm-spec");
function readVoiceCallArchiveBuffer(version: string): Buffer {
return fs.readFileSync(path.join(pluginFixturesDir, `voice-call-${version}.tgz`));
@@ -92,7 +75,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) {
@@ -106,7 +89,7 @@ async function ensureDynamicArchiveTemplate(params: {
fs.writeFileSync(path.join(pkgDir, "package.json"), JSON.stringify(params.packageJson), "utf-8");
const archivePath = await packToArchive({
pkgDir,
outDir: ensureSuiteTempRoot(),
outDir: suiteTempRootTracker.ensureSuiteTempRoot(),
outName: params.outName,
flatRoot: params.flatRoot,
});
@@ -115,16 +98,8 @@ async function ensureDynamicArchiveTemplate(params: {
}
afterAll(() => {
if (!suiteTempRoot) {
return;
}
try {
fs.rmSync(suiteTempRoot, { recursive: true, force: true });
} finally {
suiteTempRoot = "";
tempDirCounter = 0;
dynamicArchiveTemplatePathCache.clear();
}
suiteTempRootTracker.cleanup();
dynamicArchiveTemplatePathCache.clear();
});
beforeEach(() => {
@@ -134,7 +109,7 @@ beforeEach(() => {
describe("installPluginFromNpmSpec", () => {
it("uses --ignore-scripts for npm pack and cleans up temp dir", async () => {
const stateDir = makeTempDir();
const stateDir = suiteTempRootTracker.makeTempDir();
const extensionsDir = path.join(stateDir, "extensions");
fs.mkdirSync(extensionsDir, { recursive: true });
@@ -190,7 +165,7 @@ describe("installPluginFromNpmSpec", () => {
});
it("allows npm-spec 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 });
@@ -364,7 +339,7 @@ describe("installPluginFromNpmSpec", () => {
throw new Error(`unexpected command: ${argv.join(" ")}`);
});
const stateDir = makeTempDir();
const stateDir = suiteTempRootTracker.makeTempDir();
const extensionsDir = path.join(stateDir, "extensions");
fs.mkdirSync(extensionsDir, { recursive: true });
const result = await installPluginFromNpmSpec({

View File

@@ -11,30 +11,13 @@ import {
installPluginFromPath,
PLUGIN_INSTALL_ERROR_CODE,
} from "./install.js";
import { createSuiteTempRootTracker } from "./test-helpers/fs-fixtures.js";
vi.mock("../process/exec.js", () => ({
runCommandWithTimeout: vi.fn(),
}));
let suiteTempRoot = "";
let tempDirCounter = 0;
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-path-"));
return suiteTempRoot;
}
function makeTempDir() {
const dir = path.join(ensureSuiteTempRoot(), `case-${String(tempDirCounter)}`);
tempDirCounter += 1;
fs.mkdirSync(dir);
return dir;
}
const suiteTempRootTracker = createSuiteTempRootTracker("openclaw-plugin-install-path");
async function packToArchive(params: {
pkgDir: string;
@@ -60,7 +43,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 });
@@ -100,7 +83,7 @@ function setupBundleInstallFixture(params: {
}
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 });
@@ -161,15 +144,7 @@ async function installFromFileWithWarnings(params: {
}
afterAll(() => {
if (!suiteTempRoot) {
return;
}
try {
fs.rmSync(suiteTempRoot, { recursive: true, force: true });
} finally {
suiteTempRoot = "";
tempDirCounter = 0;
}
suiteTempRootTracker.cleanup();
});
beforeEach(() => {
@@ -193,7 +168,7 @@ describe("installPluginFromPath", () => {
});
initializeGlobalHookRunner(createMockPluginRegistry([{ hookName: "before_install", handler }]));
const baseDir = makeTempDir();
const baseDir = suiteTempRootTracker.makeTempDir();
const extensionsDir = path.join(baseDir, "extensions");
fs.mkdirSync(extensionsDir, { recursive: true });
@@ -235,7 +210,7 @@ describe("installPluginFromPath", () => {
});
it("blocks plain file installs when the scanner finds dangerous code patterns", async () => {
const baseDir = makeTempDir();
const baseDir = suiteTempRootTracker.makeTempDir();
const extensionsDir = path.join(baseDir, "extensions");
fs.mkdirSync(extensionsDir, { recursive: true });
@@ -256,7 +231,7 @@ describe("installPluginFromPath", () => {
});
it("allows plain file installs with dangerous code patterns when forced unsafe install is set", async () => {
const baseDir = makeTempDir();
const baseDir = suiteTempRootTracker.makeTempDir();
const extensionsDir = path.join(baseDir, "extensions");
fs.mkdirSync(extensionsDir, { recursive: true });
@@ -280,7 +255,7 @@ describe("installPluginFromPath", () => {
});
it("blocks hardlink alias overwrites when installing a plain file plugin", async () => {
const baseDir = makeTempDir();
const baseDir = suiteTempRootTracker.makeTempDir();
const extensionsDir = path.join(baseDir, "extensions");
const outsideDir = path.join(baseDir, "outside");
fs.mkdirSync(extensionsDir, { recursive: true });
@@ -313,7 +288,7 @@ describe("installPluginFromPath", () => {
bundleFormat: "claude",
name: "Claude Sample",
});
const archivePath = path.join(makeTempDir(), "claude-bundle.tgz");
const archivePath = path.join(suiteTempRootTracker.makeTempDir(), "claude-bundle.tgz");
await packToArchive({
pkgDir: pluginDir,
@@ -337,7 +312,7 @@ describe("installPluginFromPath", () => {
const { pluginDir, extensionsDir } = setupDualFormatInstallFixture({
bundleFormat: "claude",
});
const archivePath = path.join(makeTempDir(), "dual-format.tgz");
const archivePath = path.join(suiteTempRootTracker.makeTempDir(), "dual-format.tgz");
await packToArchive({
pkgDir: pluginDir,

View File

@@ -50,3 +50,43 @@ export async function cleanupTrackedTempDirsAsync(trackedDirs: string[]) {
}),
);
}
export function createSuiteTempRootTracker(prefix: string) {
let suiteTempRoot = "";
let tempDirCounter = 0;
function ensureSuiteTempRoot() {
if (suiteTempRoot) {
return suiteTempRoot;
}
const bundleTempRoot = path.join(process.cwd(), ".tmp");
fs.mkdirSync(bundleTempRoot, { recursive: true });
suiteTempRoot = fs.mkdtempSync(path.join(bundleTempRoot, String(prefix) + "-"));
return suiteTempRoot;
}
function makeTempDir() {
const dir = path.join(ensureSuiteTempRoot(), `case-${String(tempDirCounter)}`);
tempDirCounter += 1;
fs.mkdirSync(dir);
return dir;
}
function cleanup() {
if (!suiteTempRoot) {
return;
}
try {
fs.rmSync(suiteTempRoot, { recursive: true, force: true });
} finally {
suiteTempRoot = "";
tempDirCounter = 0;
}
}
return {
cleanup,
ensureSuiteTempRoot,
makeTempDir,
};
}