refactor(test): reuse temp-home helper in voicewake e2e

This commit is contained in:
Peter Steinberger
2026-02-21 12:54:54 +00:00
parent 577e5cc74b
commit c529bafdc3

View File

@@ -1,6 +1,5 @@
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import { createServer } from "node:net"; import { createServer } from "node:net";
import os from "node:os";
import path from "node:path"; import path from "node:path";
import { afterAll, beforeAll, describe, expect, test } from "vitest"; import { afterAll, beforeAll, describe, expect, test } from "vitest";
import { WebSocket } from "ws"; import { WebSocket } from "ws";
@@ -11,6 +10,7 @@ import { GatewayLockError } from "../infra/gateway-lock.js";
import { getActivePluginRegistry, setActivePluginRegistry } from "../plugins/runtime.js"; import { getActivePluginRegistry, setActivePluginRegistry } from "../plugins/runtime.js";
import { createOutboundTestPlugin } from "../test-utils/channel-plugins.js"; import { createOutboundTestPlugin } from "../test-utils/channel-plugins.js";
import { captureEnv } from "../test-utils/env.js"; import { captureEnv } from "../test-utils/env.js";
import { createTempHomeEnv } from "../test-utils/temp-home.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js"; import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
import { createRegistry } from "./server.e2e-registry-helpers.js"; import { createRegistry } from "./server.e2e-registry-helpers.js";
import { import {
@@ -81,140 +81,99 @@ const whatsappRegistry = createRegistry([
const emptyRegistry = createRegistry([]); const emptyRegistry = createRegistry([]);
describe("gateway server models + voicewake", () => { describe("gateway server models + voicewake", () => {
const setTempHome = (homeDir: string) => {
const prevHome = process.env.HOME;
const prevStateDir = process.env.OPENCLAW_STATE_DIR;
const prevUserProfile = process.env.USERPROFILE;
const prevHomeDrive = process.env.HOMEDRIVE;
const prevHomePath = process.env.HOMEPATH;
process.env.HOME = homeDir;
process.env.OPENCLAW_STATE_DIR = path.join(homeDir, ".openclaw");
process.env.USERPROFILE = homeDir;
if (process.platform === "win32") {
const parsed = path.parse(homeDir);
process.env.HOMEDRIVE = parsed.root.replace(/\\$/, "");
process.env.HOMEPATH = homeDir.slice(Math.max(parsed.root.length - 1, 0));
}
return () => {
if (prevHome === undefined) {
delete process.env.HOME;
} else {
process.env.HOME = prevHome;
}
if (prevStateDir === undefined) {
delete process.env.OPENCLAW_STATE_DIR;
} else {
process.env.OPENCLAW_STATE_DIR = prevStateDir;
}
if (prevUserProfile === undefined) {
delete process.env.USERPROFILE;
} else {
process.env.USERPROFILE = prevUserProfile;
}
if (process.platform === "win32") {
if (prevHomeDrive === undefined) {
delete process.env.HOMEDRIVE;
} else {
process.env.HOMEDRIVE = prevHomeDrive;
}
if (prevHomePath === undefined) {
delete process.env.HOMEPATH;
} else {
process.env.HOMEPATH = prevHomePath;
}
}
};
};
test( test(
"voicewake.get returns defaults and voicewake.set broadcasts", "voicewake.get returns defaults and voicewake.set broadcasts",
{ timeout: 60_000 }, { timeout: 60_000 },
async () => { async () => {
const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-home-")); const tempHome = await createTempHomeEnv("openclaw-home-");
const restoreHome = setTempHome(homeDir); try {
const initial = await rpcReq<{ triggers: string[] }>(ws, "voicewake.get");
expect(initial.ok).toBe(true);
expect(initial.payload?.triggers).toEqual(["openclaw", "claude", "computer"]);
const initial = await rpcReq<{ triggers: string[] }>(ws, "voicewake.get"); const changedP = onceMessage(
expect(initial.ok).toBe(true); ws,
expect(initial.payload?.triggers).toEqual(["openclaw", "claude", "computer"]); (o) => o.type === "event" && o.event === "voicewake.changed",
);
const changedP = onceMessage( const setRes = await rpcReq<{ triggers: string[] }>(ws, "voicewake.set", {
ws, triggers: [" hi ", "", "there"],
(o) => o.type === "event" && o.event === "voicewake.changed", });
); expect(setRes.ok).toBe(true);
expect(setRes.payload?.triggers).toEqual(["hi", "there"]);
const setRes = await rpcReq<{ triggers: string[] }>(ws, "voicewake.set", { const changed = (await changedP) as { event?: string; payload?: unknown };
triggers: [" hi ", "", "there"], expect(changed.event).toBe("voicewake.changed");
}); expect((changed.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([
expect(setRes.ok).toBe(true); "hi",
expect(setRes.payload?.triggers).toEqual(["hi", "there"]); "there",
]);
const changed = (await changedP) as { event?: string; payload?: unknown }; const after = await rpcReq<{ triggers: string[] }>(ws, "voicewake.get");
expect(changed.event).toBe("voicewake.changed"); expect(after.ok).toBe(true);
expect((changed.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([ expect(after.payload?.triggers).toEqual(["hi", "there"]);
"hi",
"there",
]);
const after = await rpcReq<{ triggers: string[] }>(ws, "voicewake.get"); const onDisk = JSON.parse(
expect(after.ok).toBe(true); await fs.readFile(
expect(after.payload?.triggers).toEqual(["hi", "there"]); path.join(tempHome.home, ".openclaw", "settings", "voicewake.json"),
"utf8",
const onDisk = JSON.parse( ),
await fs.readFile(path.join(homeDir, ".openclaw", "settings", "voicewake.json"), "utf8"), ) as { triggers?: unknown; updatedAtMs?: unknown };
) as { triggers?: unknown; updatedAtMs?: unknown }; expect(onDisk.triggers).toEqual(["hi", "there"]);
expect(onDisk.triggers).toEqual(["hi", "there"]); expect(typeof onDisk.updatedAtMs).toBe("number");
expect(typeof onDisk.updatedAtMs).toBe("number"); } finally {
await tempHome.restore();
restoreHome(); }
}, },
); );
test("pushes voicewake.changed to nodes on connect and on updates", async () => { test("pushes voicewake.changed to nodes on connect and on updates", async () => {
const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-home-")); const tempHome = await createTempHomeEnv("openclaw-home-");
const restoreHome = setTempHome(homeDir); try {
const nodeWs = new WebSocket(`ws://127.0.0.1:${port}`);
await new Promise<void>((resolve) => nodeWs.once("open", resolve));
const firstEventP = onceMessage(
nodeWs,
(o) => o.type === "event" && o.event === "voicewake.changed",
);
await connectOk(nodeWs, {
role: "node",
client: {
id: GATEWAY_CLIENT_NAMES.NODE_HOST,
version: "1.0.0",
platform: "ios",
mode: GATEWAY_CLIENT_MODES.NODE,
},
});
const nodeWs = new WebSocket(`ws://127.0.0.1:${port}`); const first = (await firstEventP) as { event?: string; payload?: unknown };
await new Promise<void>((resolve) => nodeWs.once("open", resolve)); expect(first.event).toBe("voicewake.changed");
const firstEventP = onceMessage( expect((first.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([
nodeWs, "openclaw",
(o) => o.type === "event" && o.event === "voicewake.changed", "claude",
); "computer",
await connectOk(nodeWs, { ]);
role: "node",
client: {
id: GATEWAY_CLIENT_NAMES.NODE_HOST,
version: "1.0.0",
platform: "ios",
mode: GATEWAY_CLIENT_MODES.NODE,
},
});
const first = (await firstEventP) as { event?: string; payload?: unknown }; const broadcastP = onceMessage(
expect(first.event).toBe("voicewake.changed"); nodeWs,
expect((first.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([ (o) => o.type === "event" && o.event === "voicewake.changed",
"openclaw", );
"claude", const setRes = await rpcReq<{ triggers: string[] }>(ws, "voicewake.set", {
"computer", triggers: ["openclaw", "computer"],
]); });
expect(setRes.ok).toBe(true);
const broadcastP = onceMessage( const broadcast = (await broadcastP) as { event?: string; payload?: unknown };
nodeWs, expect(broadcast.event).toBe("voicewake.changed");
(o) => o.type === "event" && o.event === "voicewake.changed", expect((broadcast.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([
); "openclaw",
const setRes = await rpcReq<{ triggers: string[] }>(ws, "voicewake.set", { "computer",
triggers: ["openclaw", "computer"], ]);
});
expect(setRes.ok).toBe(true);
const broadcast = (await broadcastP) as { event?: string; payload?: unknown }; nodeWs.close();
expect(broadcast.event).toBe("voicewake.changed"); } finally {
expect((broadcast.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([ await tempHome.restore();
"openclaw", }
"computer",
]);
nodeWs.close();
restoreHome();
}); });
test("models.list returns model catalog", async () => { test("models.list returns model catalog", async () => {