openclaw/src/infra/heartbeat-events.test.ts
2026-03-13 20:06:14 +00:00

60 lines
1.7 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
emitHeartbeatEvent,
getLastHeartbeatEvent,
onHeartbeatEvent,
resolveIndicatorType,
} from "./heartbeat-events.js";
describe("resolveIndicatorType", () => {
it("maps heartbeat statuses to indicator types", () => {
expect(resolveIndicatorType("ok-empty")).toBe("ok");
expect(resolveIndicatorType("ok-token")).toBe("ok");
expect(resolveIndicatorType("sent")).toBe("alert");
expect(resolveIndicatorType("failed")).toBe("error");
expect(resolveIndicatorType("skipped")).toBeUndefined();
});
});
describe("heartbeat events", () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-01-09T12:00:00Z"));
});
afterEach(() => {
vi.useRealTimers();
});
it("stores the last event and timestamps emitted payloads", () => {
emitHeartbeatEvent({ status: "sent", to: "+123", preview: "ping" });
expect(getLastHeartbeatEvent()).toEqual({
ts: 1767960000000,
status: "sent",
to: "+123",
preview: "ping",
});
});
it("delivers events to listeners, isolates listener failures, and supports unsubscribe", () => {
const seen: string[] = [];
const unsubscribeFirst = onHeartbeatEvent((evt) => {
seen.push(`first:${evt.status}`);
});
onHeartbeatEvent(() => {
throw new Error("boom");
});
const unsubscribeThird = onHeartbeatEvent((evt) => {
seen.push(`third:${evt.status}`);
});
emitHeartbeatEvent({ status: "ok-empty" });
unsubscribeFirst();
unsubscribeThird();
emitHeartbeatEvent({ status: "failed" });
expect(seen).toEqual(["first:ok-empty", "third:ok-empty"]);
});
});