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 { createServer } from "node:net";
import os from "node:os";
import path from "node:path";
import { afterAll, beforeAll, describe, expect, test } from "vitest";
import { WebSocket } from "ws";
@@ -11,6 +10,7 @@ import { GatewayLockError } from "../infra/gateway-lock.js";
import { getActivePluginRegistry, setActivePluginRegistry } from "../plugins/runtime.js";
import { createOutboundTestPlugin } from "../test-utils/channel-plugins.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 { createRegistry } from "./server.e2e-registry-helpers.js";
import {
@@ -81,140 +81,99 @@ const whatsappRegistry = createRegistry([
const emptyRegistry = createRegistry([]);
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(
"voicewake.get returns defaults and voicewake.set broadcasts",
{ timeout: 60_000 },
async () => {
const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-home-"));
const restoreHome = setTempHome(homeDir);
const tempHome = await createTempHomeEnv("openclaw-home-");
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");
expect(initial.ok).toBe(true);
expect(initial.payload?.triggers).toEqual(["openclaw", "claude", "computer"]);
const changedP = onceMessage(
ws,
(o) => o.type === "event" && o.event === "voicewake.changed",
);
const changedP = onceMessage(
ws,
(o) => o.type === "event" && o.event === "voicewake.changed",
);
const setRes = await rpcReq<{ triggers: string[] }>(ws, "voicewake.set", {
triggers: [" hi ", "", "there"],
});
expect(setRes.ok).toBe(true);
expect(setRes.payload?.triggers).toEqual(["hi", "there"]);
const setRes = await rpcReq<{ triggers: string[] }>(ws, "voicewake.set", {
triggers: [" hi ", "", "there"],
});
expect(setRes.ok).toBe(true);
expect(setRes.payload?.triggers).toEqual(["hi", "there"]);
const changed = (await changedP) as { event?: string; payload?: unknown };
expect(changed.event).toBe("voicewake.changed");
expect((changed.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([
"hi",
"there",
]);
const changed = (await changedP) as { event?: string; payload?: unknown };
expect(changed.event).toBe("voicewake.changed");
expect((changed.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([
"hi",
"there",
]);
const after = await rpcReq<{ triggers: string[] }>(ws, "voicewake.get");
expect(after.ok).toBe(true);
expect(after.payload?.triggers).toEqual(["hi", "there"]);
const after = await rpcReq<{ triggers: string[] }>(ws, "voicewake.get");
expect(after.ok).toBe(true);
expect(after.payload?.triggers).toEqual(["hi", "there"]);
const onDisk = JSON.parse(
await fs.readFile(path.join(homeDir, ".openclaw", "settings", "voicewake.json"), "utf8"),
) as { triggers?: unknown; updatedAtMs?: unknown };
expect(onDisk.triggers).toEqual(["hi", "there"]);
expect(typeof onDisk.updatedAtMs).toBe("number");
restoreHome();
const onDisk = JSON.parse(
await fs.readFile(
path.join(tempHome.home, ".openclaw", "settings", "voicewake.json"),
"utf8",
),
) as { triggers?: unknown; updatedAtMs?: unknown };
expect(onDisk.triggers).toEqual(["hi", "there"]);
expect(typeof onDisk.updatedAtMs).toBe("number");
} finally {
await tempHome.restore();
}
},
);
test("pushes voicewake.changed to nodes on connect and on updates", async () => {
const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-home-"));
const restoreHome = setTempHome(homeDir);
const tempHome = await createTempHomeEnv("openclaw-home-");
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}`);
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 first = (await firstEventP) as { event?: string; payload?: unknown };
expect(first.event).toBe("voicewake.changed");
expect((first.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([
"openclaw",
"claude",
"computer",
]);
const first = (await firstEventP) as { event?: string; payload?: unknown };
expect(first.event).toBe("voicewake.changed");
expect((first.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([
"openclaw",
"claude",
"computer",
]);
const broadcastP = onceMessage(
nodeWs,
(o) => o.type === "event" && o.event === "voicewake.changed",
);
const setRes = await rpcReq<{ triggers: string[] }>(ws, "voicewake.set", {
triggers: ["openclaw", "computer"],
});
expect(setRes.ok).toBe(true);
const broadcastP = onceMessage(
nodeWs,
(o) => o.type === "event" && o.event === "voicewake.changed",
);
const setRes = await rpcReq<{ triggers: string[] }>(ws, "voicewake.set", {
triggers: ["openclaw", "computer"],
});
expect(setRes.ok).toBe(true);
const broadcast = (await broadcastP) as { event?: string; payload?: unknown };
expect(broadcast.event).toBe("voicewake.changed");
expect((broadcast.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([
"openclaw",
"computer",
]);
const broadcast = (await broadcastP) as { event?: string; payload?: unknown };
expect(broadcast.event).toBe("voicewake.changed");
expect((broadcast.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([
"openclaw",
"computer",
]);
nodeWs.close();
restoreHome();
nodeWs.close();
} finally {
await tempHome.restore();
}
});
test("models.list returns model catalog", async () => {