From 2042a692110945506bc1a9862376a7fbbec94a40 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 21 Feb 2026 19:34:23 +0000 Subject: [PATCH] test(infra): dedupe dotenv fixture setup and cover fallback-only load --- src/infra/dotenv.test.ts | 71 ++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/src/infra/dotenv.test.ts b/src/infra/dotenv.test.ts index e03e8487659..0b77866a23b 100644 --- a/src/infra/dotenv.test.ts +++ b/src/infra/dotenv.test.ts @@ -31,46 +31,69 @@ async function withIsolatedEnvAndCwd(run: () => Promise) { } } +type DotEnvFixture = { + base: string; + cwdDir: string; + stateDir: string; +}; + +async function withDotEnvFixture(run: (fixture: DotEnvFixture) => Promise) { + const base = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-dotenv-test-")); + const cwdDir = path.join(base, "cwd"); + const stateDir = path.join(base, "state"); + process.env.OPENCLAW_STATE_DIR = stateDir; + await fs.mkdir(cwdDir, { recursive: true }); + await fs.mkdir(stateDir, { recursive: true }); + await run({ base, cwdDir, stateDir }); +} + describe("loadDotEnv", () => { it("loads ~/.openclaw/.env as fallback without overriding CWD .env", async () => { await withIsolatedEnvAndCwd(async () => { - const base = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-dotenv-test-")); - const cwdDir = path.join(base, "cwd"); - const stateDir = path.join(base, "state"); + await withDotEnvFixture(async ({ cwdDir, stateDir }) => { + await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\nBAR=1\n"); + await writeEnvFile(path.join(cwdDir, ".env"), "FOO=from-cwd\n"); - process.env.OPENCLAW_STATE_DIR = stateDir; + process.chdir(cwdDir); + delete process.env.FOO; + delete process.env.BAR; - await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\nBAR=1\n"); - await writeEnvFile(path.join(cwdDir, ".env"), "FOO=from-cwd\n"); + loadDotEnv({ quiet: true }); - process.chdir(cwdDir); - delete process.env.FOO; - delete process.env.BAR; - - loadDotEnv({ quiet: true }); - - expect(process.env.FOO).toBe("from-cwd"); - expect(process.env.BAR).toBe("1"); + expect(process.env.FOO).toBe("from-cwd"); + expect(process.env.BAR).toBe("1"); + }); }); }); it("does not override an already-set env var from the shell", async () => { await withIsolatedEnvAndCwd(async () => { - const base = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-dotenv-test-")); - const cwdDir = path.join(base, "cwd"); - const stateDir = path.join(base, "state"); + await withDotEnvFixture(async ({ cwdDir, stateDir }) => { + process.env.FOO = "from-shell"; - process.env.OPENCLAW_STATE_DIR = stateDir; - process.env.FOO = "from-shell"; + await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\n"); + await writeEnvFile(path.join(cwdDir, ".env"), "FOO=from-cwd\n"); - await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\n"); - await writeEnvFile(path.join(cwdDir, ".env"), "FOO=from-cwd\n"); + process.chdir(cwdDir); - process.chdir(cwdDir); + loadDotEnv({ quiet: true }); - loadDotEnv({ quiet: true }); + expect(process.env.FOO).toBe("from-shell"); + }); + }); + }); - expect(process.env.FOO).toBe("from-shell"); + it("loads fallback state .env when CWD .env is missing", async () => { + await withIsolatedEnvAndCwd(async () => { + await withDotEnvFixture(async ({ cwdDir, stateDir }) => { + await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\n"); + process.chdir(cwdDir); + delete process.env.FOO; + + loadDotEnv({ quiet: true }); + + expect(process.env.FOO).toBe("from-global"); + }); }); }); });