Files
clawdbot/src/auto-reply/reply.heartbeat-typing.test.ts
2026-01-06 18:33:37 +00:00

112 lines
3.0 KiB
TypeScript

import fs from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
const runEmbeddedPiAgentMock = vi.fn();
vi.mock("../agents/model-fallback.js", () => ({
runWithModelFallback: async ({
provider,
model,
run,
}: {
provider: string;
model: string;
run: (provider: string, model: string) => Promise<unknown>;
}) => ({
result: await run(provider, model),
provider,
model,
}),
}));
vi.mock("../agents/pi-embedded.js", () => ({
abortEmbeddedPiRun: vi.fn().mockReturnValue(false),
runEmbeddedPiAgent: (params: unknown) => runEmbeddedPiAgentMock(params),
queueEmbeddedPiMessage: vi.fn().mockReturnValue(false),
resolveEmbeddedSessionLane: (key: string) =>
`session:${key.trim() || "main"}`,
isEmbeddedPiRunActive: vi.fn().mockReturnValue(false),
isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false),
}));
const webMocks = vi.hoisted(() => ({
webAuthExists: vi.fn().mockResolvedValue(true),
getWebAuthAgeMs: vi.fn().mockReturnValue(120_000),
readWebSelfId: vi.fn().mockReturnValue({ e164: "+1999" }),
}));
vi.mock("../web/session.js", () => webMocks);
import { getReplyFromConfig } from "./reply.js";
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
const base = await fs.mkdtemp(join(tmpdir(), "clawdbot-typing-"));
const previousHome = process.env.HOME;
process.env.HOME = base;
try {
runEmbeddedPiAgentMock.mockClear();
return await fn(base);
} finally {
process.env.HOME = previousHome;
await fs.rm(base, { recursive: true, force: true });
}
}
function makeCfg(home: string) {
return {
agent: {
model: "anthropic/claude-opus-4-5",
workspace: join(home, "clawd"),
},
whatsapp: {
allowFrom: ["*"],
},
session: { store: join(home, "sessions.json") },
};
}
afterEach(() => {
vi.restoreAllMocks();
});
describe("getReplyFromConfig typing (heartbeat)", () => {
it("starts typing for normal runs", async () => {
await withTempHome(async (home) => {
runEmbeddedPiAgentMock.mockResolvedValueOnce({
payloads: [{ text: "ok" }],
meta: {},
});
const onReplyStart = vi.fn();
await getReplyFromConfig(
{ Body: "hi", From: "+1000", To: "+2000", Provider: "whatsapp" },
{ onReplyStart, isHeartbeat: false },
makeCfg(home),
);
expect(onReplyStart).toHaveBeenCalled();
});
});
it("does not start typing for heartbeat runs", async () => {
await withTempHome(async (home) => {
runEmbeddedPiAgentMock.mockResolvedValueOnce({
payloads: [{ text: "ok" }],
meta: {},
});
const onReplyStart = vi.fn();
await getReplyFromConfig(
{ Body: "hi", From: "+1000", To: "+2000", Provider: "whatsapp" },
{ onReplyStart, isHeartbeat: true },
makeCfg(home),
);
expect(onReplyStart).not.toHaveBeenCalled();
});
});
});