diff --git a/extensions/discord/src/monitor.gateway.test.ts b/extensions/discord/src/monitor.gateway.test.ts index 3e835d23c77..cb605b6f32b 100644 --- a/extensions/discord/src/monitor.gateway.test.ts +++ b/extensions/discord/src/monitor.gateway.test.ts @@ -108,9 +108,10 @@ describe("waitForDiscordGatewayStop", () => { }, }); - expect(forceStop).toBeDefined(); - - forceStop?.(new Error("reconnect watchdog timeout")); + if (!forceStop) { + throw new Error("registerForceStop did not expose a stopper callback"); + } + forceStop(new Error("reconnect watchdog timeout")); await expect(promise).rejects.toThrow("reconnect watchdog timeout"); expect(disconnect).toHaveBeenCalledTimes(1); diff --git a/extensions/discord/src/monitor/auto-presence.test.ts b/extensions/discord/src/monitor/auto-presence.test.ts index 3e81b523bc9..96fa7187fe5 100644 --- a/extensions/discord/src/monitor/auto-presence.test.ts +++ b/extensions/discord/src/monitor/auto-presence.test.ts @@ -43,10 +43,12 @@ function expectExhaustedDecision(params: { failureCounts: Record now, }); - expect(decision).toBeTruthy(); - expect(decision?.state).toBe("exhausted"); - expect(decision?.presence.status).toBe("dnd"); - expect(decision?.presence.activities[0]?.state).toBe("token exhausted"); + if (!decision) { + throw new Error("expected an exhausted auto-presence decision"); + } + expect(decision.state).toBe("exhausted"); + expect(decision.presence.status).toBe("dnd"); + expect(decision.presence.activities[0]?.state).toBe("token exhausted"); } describe("discord auto presence", () => { @@ -87,8 +89,10 @@ describe("discord auto presence", () => { controller.runNow(); expect(updatePresence).toHaveBeenCalledTimes(2); - expect(updatePresence.mock.calls[0]?.[0]?.status).toBe("dnd"); - expect(updatePresence.mock.calls[1]?.[0]?.status).toBe("online"); + expect(updatePresence.mock.calls).toEqual([ + [expect.objectContaining({ status: "dnd" })], + [expect.objectContaining({ status: "online" })], + ]); }); it("re-applies presence on refresh even when signature is unchanged", () => { @@ -119,8 +123,10 @@ describe("discord auto presence", () => { controller.refresh(); expect(updatePresence).toHaveBeenCalledTimes(2); - expect(updatePresence.mock.calls[0]?.[0]?.status).toBe("online"); - expect(updatePresence.mock.calls[1]?.[0]?.status).toBe("online"); + expect(updatePresence.mock.calls).toEqual([ + [expect.objectContaining({ status: "online" })], + [expect.objectContaining({ status: "online" })], + ]); }); it("does nothing when auto presence is disabled", () => { diff --git a/extensions/discord/src/monitor/monitor.test.ts b/extensions/discord/src/monitor/monitor.test.ts index a70fdfe63c5..55b4fc096a2 100644 --- a/extensions/discord/src/monitor/monitor.test.ts +++ b/extensions/discord/src/monitor/monitor.test.ts @@ -203,7 +203,9 @@ describe("agent components", () => { const pairingText = String(reply.mock.calls[0]?.[0]?.content ?? ""); expect(pairingText).toContain("Pairing code:"); const code = pairingText.match(/Pairing code:\s*([A-Z2-9]{8})/)?.[1]; - expect(code).toBeDefined(); + if (!code) { + throw new Error(`pairing reply did not include an 8-character pairing code: ${pairingText}`); + } expect(pairingText).toContain(`openclaw pairing approve discord ${code}`); expect(peekSystemEvents(dmSessionKey)).toEqual([]); expect(readAllowFromStoreMock).toHaveBeenCalledWith("discord", "default"); diff --git a/extensions/discord/src/monitor/reply-delivery.test.ts b/extensions/discord/src/monitor/reply-delivery.test.ts index bbfbe6eeae8..54f49129c3b 100644 --- a/extensions/discord/src/monitor/reply-delivery.test.ts +++ b/extensions/discord/src/monitor/reply-delivery.test.ts @@ -211,7 +211,11 @@ describe("deliverDiscordReply", () => { textLimit: 2000, }); - expect(sendMessageDiscordMock.mock.calls[0]?.[2]?.cfg).toBe(cfg); + expect(sendMessageDiscordMock).toHaveBeenCalledWith( + "channel:101", + "cfg path", + expect.objectContaining({ cfg }), + ); }); it("uses replyToId only for the first chunk when replyToMode is first", async () => { @@ -231,8 +235,18 @@ describe("deliverDiscordReply", () => { }); expect(sendMessageDiscordMock).toHaveBeenCalledTimes(2); - expect(sendMessageDiscordMock.mock.calls[0]?.[2]?.replyTo).toBe("reply-1"); - expect(sendMessageDiscordMock.mock.calls[1]?.[2]?.replyTo).toBeUndefined(); + expect(sendMessageDiscordMock.mock.calls).toEqual([ + expect.arrayContaining([ + "channel:789", + "12345", + expect.objectContaining({ replyTo: "reply-1" }), + ]), + expect.arrayContaining([ + "channel:789", + "67890", + expect.not.objectContaining({ replyTo: expect.anything() }), + ]), + ]); }); it("does not consume replyToId for replyToMode=first on whitespace-only payloads", async () => { diff --git a/extensions/discord/src/monitor/thread-bindings.lifecycle.test.ts b/extensions/discord/src/monitor/thread-bindings.lifecycle.test.ts index dc4649cbefd..0fa0721178f 100644 --- a/extensions/discord/src/monitor/thread-bindings.lifecycle.test.ts +++ b/extensions/discord/src/monitor/thread-bindings.lifecycle.test.ts @@ -339,7 +339,12 @@ describe("thread binding lifecycle", () => { await vi.advanceTimersByTimeAsync(120_000); await __testing.runThreadBindingSweepForAccount("default"); - expect(manager.getByThreadId("thread-1")).toBeDefined(); + expect(requireBinding(manager, "thread-1")).toMatchObject({ + threadId: "thread-1", + targetSessionKey: "agent:main:subagent:child", + webhookId: "wh-1", + webhookToken: "tok-1", + }); expect(hoisted.sendWebhookMessageDiscord).not.toHaveBeenCalled(); } finally { vi.useRealTimers(); diff --git a/extensions/discord/src/monitor/threading.starter.test.ts b/extensions/discord/src/monitor/threading.starter.test.ts index 65e556a55dc..1c80c6991f6 100644 --- a/extensions/discord/src/monitor/threading.starter.test.ts +++ b/extensions/discord/src/monitor/threading.starter.test.ts @@ -54,6 +54,9 @@ describe("resolveDiscordThreadStarter", () => { () => undefined, ); - expect(result?.text).toBe("starter content"); + if (!result) { + throw new Error("starter content should have produced a resolved starter payload"); + } + expect(result.text).toBe("starter content"); }); });