From 0213a0921139fea93630e9f87f88485ddee655e0 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 19 Feb 2026 14:39:01 +0000 Subject: [PATCH] test: share temp home env harness --- src/config/home-env.test-harness.ts | 32 +++------------------ src/media/store.test.ts | 29 ++++--------------- src/test-utils/temp-home.test.ts | 26 +++++++++++++++++ src/test-utils/temp-home.ts | 43 +++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 52 deletions(-) create mode 100644 src/test-utils/temp-home.test.ts create mode 100644 src/test-utils/temp-home.ts diff --git a/src/config/home-env.test-harness.ts b/src/config/home-env.test-harness.ts index 78abde370d..095f8c9ed5 100644 --- a/src/config/home-env.test-harness.ts +++ b/src/config/home-env.test-harness.ts @@ -1,38 +1,14 @@ -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; -import { captureEnv } from "../test-utils/env.js"; +import { createTempHomeEnv } from "../test-utils/temp-home.js"; export async function withTempHome( prefix: string, fn: (home: string) => Promise, ): Promise { - const home = await fs.mkdtemp(path.join(os.tmpdir(), prefix)); - await fs.mkdir(path.join(home, ".openclaw"), { recursive: true }); - - const snapshot = captureEnv([ - "HOME", - "USERPROFILE", - "HOMEDRIVE", - "HOMEPATH", - "OPENCLAW_STATE_DIR", - ]); - process.env.HOME = home; - process.env.USERPROFILE = home; - process.env.OPENCLAW_STATE_DIR = path.join(home, ".openclaw"); - - if (process.platform === "win32") { - const match = home.match(/^([A-Za-z]:)(.*)$/); - if (match) { - process.env.HOMEDRIVE = match[1]; - process.env.HOMEPATH = match[2] || "\\"; - } - } + const tempHome = await createTempHomeEnv(prefix); try { - return await fn(home); + return await fn(tempHome.home); } finally { - snapshot.restore(); - await fs.rm(home, { recursive: true, force: true }); + await tempHome.restore(); } } diff --git a/src/media/store.test.ts b/src/media/store.test.ts index 59cffb7ff8..2941bf8d06 100644 --- a/src/media/store.test.ts +++ b/src/media/store.test.ts @@ -1,44 +1,25 @@ import fs from "node:fs/promises"; -import os from "node:os"; import path from "node:path"; import JSZip from "jszip"; import sharp from "sharp"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import { isPathWithinBase } from "../../test/helpers/paths.js"; -import { captureEnv } from "../test-utils/env.js"; +import { createTempHomeEnv, type TempHomeEnv } from "../test-utils/temp-home.js"; describe("media store", () => { let store: typeof import("./store.js"); let home = ""; - let envSnapshot: ReturnType; + let tempHome: TempHomeEnv; beforeAll(async () => { - envSnapshot = captureEnv([ - "HOME", - "USERPROFILE", - "HOMEDRIVE", - "HOMEPATH", - "OPENCLAW_STATE_DIR", - ]); - home = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-test-home-")); - process.env.HOME = home; - process.env.USERPROFILE = home; - process.env.OPENCLAW_STATE_DIR = path.join(home, ".openclaw"); - if (process.platform === "win32") { - const match = home.match(/^([A-Za-z]:)(.*)$/); - if (match) { - process.env.HOMEDRIVE = match[1]; - process.env.HOMEPATH = match[2] || "\\"; - } - } - await fs.mkdir(path.join(home, ".openclaw"), { recursive: true }); + tempHome = await createTempHomeEnv("openclaw-test-home-"); + home = tempHome.home; store = await import("./store.js"); }); afterAll(async () => { - envSnapshot.restore(); try { - await fs.rm(home, { recursive: true, force: true }); + await tempHome.restore(); } catch { // ignore cleanup failures in tests } diff --git a/src/test-utils/temp-home.test.ts b/src/test-utils/temp-home.test.ts new file mode 100644 index 0000000000..4b87e9b702 --- /dev/null +++ b/src/test-utils/temp-home.test.ts @@ -0,0 +1,26 @@ +import fs from "node:fs/promises"; +import { describe, expect, it } from "vitest"; +import { createTempHomeEnv } from "./temp-home.js"; + +describe("createTempHomeEnv", () => { + it("sets home env vars and restores them on cleanup", async () => { + const previousHome = process.env.HOME; + const previousUserProfile = process.env.USERPROFILE; + const previousStateDir = process.env.OPENCLAW_STATE_DIR; + + const tempHome = await createTempHomeEnv("openclaw-temp-home-"); + expect(process.env.HOME).toBe(tempHome.home); + expect(process.env.USERPROFILE).toBe(tempHome.home); + expect(process.env.OPENCLAW_STATE_DIR).toBe(`${tempHome.home}/.openclaw`); + await expect(fs.stat(tempHome.home)).resolves.toMatchObject({ + isDirectory: expect.any(Function), + }); + + await tempHome.restore(); + + expect(process.env.HOME).toBe(previousHome); + expect(process.env.USERPROFILE).toBe(previousUserProfile); + expect(process.env.OPENCLAW_STATE_DIR).toBe(previousStateDir); + await expect(fs.stat(tempHome.home)).rejects.toThrow(); + }); +}); diff --git a/src/test-utils/temp-home.ts b/src/test-utils/temp-home.ts new file mode 100644 index 0000000000..10886cc9aa --- /dev/null +++ b/src/test-utils/temp-home.ts @@ -0,0 +1,43 @@ +import fs from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { captureEnv } from "./env.js"; + +const HOME_ENV_KEYS = [ + "HOME", + "USERPROFILE", + "HOMEDRIVE", + "HOMEPATH", + "OPENCLAW_STATE_DIR", +] as const; + +export type TempHomeEnv = { + home: string; + restore: () => Promise; +}; + +export async function createTempHomeEnv(prefix: string): Promise { + const home = await fs.mkdtemp(path.join(os.tmpdir(), prefix)); + await fs.mkdir(path.join(home, ".openclaw"), { recursive: true }); + + const snapshot = captureEnv([...HOME_ENV_KEYS]); + process.env.HOME = home; + process.env.USERPROFILE = home; + process.env.OPENCLAW_STATE_DIR = path.join(home, ".openclaw"); + + if (process.platform === "win32") { + const match = home.match(/^([A-Za-z]:)(.*)$/); + if (match) { + process.env.HOMEDRIVE = match[1]; + process.env.HOMEPATH = match[2] || "\\"; + } + } + + return { + home, + restore: async () => { + snapshot.restore(); + await fs.rm(home, { recursive: true, force: true }); + }, + }; +}