refactor(test): centralize temporary state-dir env setup

This commit is contained in:
Peter Steinberger
2026-02-21 12:59:14 +00:00
parent 50a8942c07
commit c2874aead7
4 changed files with 88 additions and 61 deletions

View File

@@ -1,45 +1,28 @@
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path"; import path from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { defaultRuntime } from "../runtime.js"; import { defaultRuntime } from "../runtime.js";
import { import { withStateDirEnv } from "../test-helpers/state-dir-env.js";
restoreStateDirEnv,
setStateDirEnv,
snapshotStateDirEnv,
} from "../test-helpers/state-dir-env.js";
import { createCanvasHostHandler } from "./server.js"; import { createCanvasHostHandler } from "./server.js";
describe("canvas host state dir defaults", () => { describe("canvas host state dir defaults", () => {
let envSnapshot: ReturnType<typeof snapshotStateDirEnv>;
beforeEach(() => {
envSnapshot = snapshotStateDirEnv();
});
afterEach(() => {
restoreStateDirEnv(envSnapshot);
});
it("uses OPENCLAW_STATE_DIR for the default canvas root", async () => { it("uses OPENCLAW_STATE_DIR for the default canvas root", async () => {
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-canvas-state-")); await withStateDirEnv("openclaw-canvas-state-", async ({ stateDir }) => {
const stateDir = path.join(tempRoot, "state"); const handler = await createCanvasHostHandler({
setStateDirEnv(stateDir); runtime: defaultRuntime,
const handler = await createCanvasHostHandler({ allowInTests: true,
runtime: defaultRuntime, });
allowInTests: true,
});
try { try {
const expectedRoot = await fs.realpath(path.join(stateDir, "canvas")); const expectedRoot = await fs.realpath(path.join(stateDir, "canvas"));
const actualRoot = await fs.realpath(handler.rootDir); const actualRoot = await fs.realpath(handler.rootDir);
expect(actualRoot).toBe(expectedRoot); expect(actualRoot).toBe(expectedRoot);
const indexPath = path.join(expectedRoot, "index.html"); const indexPath = path.join(expectedRoot, "index.html");
const indexContents = await fs.readFile(indexPath, "utf8"); const indexContents = await fs.readFile(indexPath, "utf8");
expect(indexContents).toContain("OpenClaw Canvas"); expect(indexContents).toContain("OpenClaw Canvas");
} finally { } finally {
await handler.close(); await handler.close();
await fs.rm(tempRoot, { recursive: true, force: true }); }
} });
}); });
}); });

View File

@@ -1,37 +1,16 @@
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path"; import path from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { import { withStateDirEnv } from "../test-helpers/state-dir-env.js";
restoreStateDirEnv,
setStateDirEnv,
snapshotStateDirEnv,
} from "../test-helpers/state-dir-env.js";
import { loadOrCreateDeviceIdentity } from "./device-identity.js"; import { loadOrCreateDeviceIdentity } from "./device-identity.js";
describe("device identity state dir defaults", () => { describe("device identity state dir defaults", () => {
let envSnapshot: ReturnType<typeof snapshotStateDirEnv>;
beforeEach(() => {
envSnapshot = snapshotStateDirEnv();
});
afterEach(() => {
restoreStateDirEnv(envSnapshot);
});
it("writes the default identity file under OPENCLAW_STATE_DIR", async () => { it("writes the default identity file under OPENCLAW_STATE_DIR", async () => {
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-identity-state-")); await withStateDirEnv("openclaw-identity-state-", async ({ stateDir }) => {
const stateDir = path.join(tempRoot, "state"); const identity = loadOrCreateDeviceIdentity();
setStateDirEnv(stateDir);
const identity = loadOrCreateDeviceIdentity();
try {
const identityPath = path.join(stateDir, "identity", "device.json"); const identityPath = path.join(stateDir, "identity", "device.json");
const raw = JSON.parse(await fs.readFile(identityPath, "utf8")) as { deviceId?: string }; const raw = JSON.parse(await fs.readFile(identityPath, "utf8")) as { deviceId?: string };
expect(raw.deviceId).toBe(identity.deviceId); expect(raw.deviceId).toBe(identity.deviceId);
} finally { });
await fs.rm(tempRoot, { recursive: true, force: true });
}
}); });
}); });

View File

@@ -0,0 +1,45 @@
import fs from "node:fs/promises";
import path from "node:path";
import { describe, expect, it } from "vitest";
import {
restoreStateDirEnv,
setStateDirEnv,
snapshotStateDirEnv,
withStateDirEnv,
} from "./state-dir-env.js";
describe("state-dir-env helpers", () => {
it("set/snapshot/restore round-trips OPENCLAW_STATE_DIR", () => {
const prevOpenClaw = process.env.OPENCLAW_STATE_DIR;
const prevLegacy = process.env.CLAWDBOT_STATE_DIR;
const snapshot = snapshotStateDirEnv();
setStateDirEnv("/tmp/openclaw-state-dir-test");
expect(process.env.OPENCLAW_STATE_DIR).toBe("/tmp/openclaw-state-dir-test");
expect(process.env.CLAWDBOT_STATE_DIR).toBeUndefined();
restoreStateDirEnv(snapshot);
expect(process.env.OPENCLAW_STATE_DIR).toBe(prevOpenClaw);
expect(process.env.CLAWDBOT_STATE_DIR).toBe(prevLegacy);
});
it("withStateDirEnv sets env for callback and cleans up temp root", async () => {
const prevOpenClaw = process.env.OPENCLAW_STATE_DIR;
const prevLegacy = process.env.CLAWDBOT_STATE_DIR;
let capturedTempRoot = "";
let capturedStateDir = "";
await withStateDirEnv("openclaw-state-dir-env-", async ({ tempRoot, stateDir }) => {
capturedTempRoot = tempRoot;
capturedStateDir = stateDir;
expect(process.env.OPENCLAW_STATE_DIR).toBe(stateDir);
expect(process.env.CLAWDBOT_STATE_DIR).toBeUndefined();
await fs.writeFile(path.join(stateDir, "probe.txt"), "ok", "utf8");
});
expect(process.env.OPENCLAW_STATE_DIR).toBe(prevOpenClaw);
expect(process.env.CLAWDBOT_STATE_DIR).toBe(prevLegacy);
await expect(fs.stat(capturedStateDir)).rejects.toThrow();
await expect(fs.stat(capturedTempRoot)).rejects.toThrow();
});
});

View File

@@ -1,3 +1,6 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { captureEnv } from "../test-utils/env.js"; import { captureEnv } from "../test-utils/env.js";
export function snapshotStateDirEnv() { export function snapshotStateDirEnv() {
@@ -12,3 +15,20 @@ export function setStateDirEnv(stateDir: string): void {
process.env.OPENCLAW_STATE_DIR = stateDir; process.env.OPENCLAW_STATE_DIR = stateDir;
delete process.env.CLAWDBOT_STATE_DIR; delete process.env.CLAWDBOT_STATE_DIR;
} }
export async function withStateDirEnv<T>(
prefix: string,
fn: (ctx: { tempRoot: string; stateDir: string }) => Promise<T>,
): Promise<T> {
const snapshot = snapshotStateDirEnv();
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
const stateDir = path.join(tempRoot, "state");
await fs.mkdir(stateDir, { recursive: true });
setStateDirEnv(stateDir);
try {
return await fn({ tempRoot, stateDir });
} finally {
restoreStateDirEnv(snapshot);
await fs.rm(tempRoot, { recursive: true, force: true });
}
}