From 0e8ec837422d7d4b29fbd8760f8f20c9c84b8ca7 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 14 Feb 2026 20:33:46 +0000 Subject: [PATCH] refactor(test): dedupe web auto-reply group message setup --- ...asts-sequentially-configured-order.test.ts | 56 +++++------------- src/web/auto-reply.test-harness.ts | 59 +++++++++++++++++++ ...oup-chats-injects-history-replying.test.ts | 44 ++++---------- 3 files changed, 88 insertions(+), 71 deletions(-) diff --git a/src/web/auto-reply.broadcast-groups.broadcasts-sequentially-configured-order.test.ts b/src/web/auto-reply.broadcast-groups.broadcasts-sequentially-configured-order.test.ts index da2bc0f6d24..a2f7aa5a2a3 100644 --- a/src/web/auto-reply.broadcast-groups.broadcasts-sequentially-configured-order.test.ts +++ b/src/web/auto-reply.broadcast-groups.broadcasts-sequentially-configured-order.test.ts @@ -3,9 +3,12 @@ import { describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; import { monitorWebChannel } from "./auto-reply.js"; import { + createWebInboundDeliverySpies, + createWebListenerFactoryCapture, installWebAutoReplyTestHomeHooks, installWebAutoReplyUnitTestHooks, resetLoadConfigMock, + sendWebGroupInboundMessage, setLoadConfigMock, } from "./auto-reply.test-harness.js"; @@ -81,58 +84,37 @@ describe("broadcast groups", () => { }, } satisfies OpenClawConfig); - const sendMedia = vi.fn(); - const reply = vi.fn().mockResolvedValue(undefined); - const sendComposing = vi.fn(); + const spies = createWebInboundDeliverySpies(); const resolver = vi.fn().mockResolvedValue({ text: "ok" }); - let capturedOnMessage: - | ((msg: import("./inbound.js").WebInboundMessage) => Promise) - | undefined; - const listenerFactory = async (opts: { - onMessage: (msg: import("./inbound.js").WebInboundMessage) => Promise; - }) => { - capturedOnMessage = opts.onMessage; - return { close: vi.fn() }; - }; + const { listenerFactory, getOnMessage } = createWebListenerFactoryCapture(); await monitorWebChannel(false, listenerFactory, false, resolver); - expect(capturedOnMessage).toBeDefined(); + const onMessage = getOnMessage(); + expect(onMessage).toBeDefined(); - await capturedOnMessage?.({ + await sendWebGroupInboundMessage({ + onMessage: onMessage!, + spies, body: "hello group", - from: "123@g.us", - conversationId: "123@g.us", - chatId: "123@g.us", - chatType: "group", - to: "+2", id: "g1", senderE164: "+111", senderName: "Alice", selfE164: "+999", - sendComposing, - reply, - sendMedia, }); expect(resolver).not.toHaveBeenCalled(); - await capturedOnMessage?.({ + await sendWebGroupInboundMessage({ + onMessage: onMessage!, + spies, body: "@bot ping", - from: "123@g.us", - conversationId: "123@g.us", - chatId: "123@g.us", - chatType: "group", - to: "+2", id: "g2", senderE164: "+222", senderName: "Bob", mentionedJids: ["999@s.whatsapp.net"], selfE164: "+999", selfJid: "999@s.whatsapp.net", - sendComposing, - reply, - sendMedia, }); expect(resolver).toHaveBeenCalledTimes(2); @@ -153,22 +135,16 @@ describe("broadcast groups", () => { expect(payload.SenderId).toBe("+222"); } - await capturedOnMessage?.({ + await sendWebGroupInboundMessage({ + onMessage: onMessage!, + spies, body: "@bot ping 2", - from: "123@g.us", - conversationId: "123@g.us", - chatId: "123@g.us", - chatType: "group", - to: "+2", id: "g3", senderE164: "+333", senderName: "Clara", mentionedJids: ["999@s.whatsapp.net"], selfE164: "+999", selfJid: "999@s.whatsapp.net", - sendComposing, - reply, - sendMedia, }); expect(resolver).toHaveBeenCalledTimes(4); diff --git a/src/web/auto-reply.test-harness.ts b/src/web/auto-reply.test-harness.ts index e94e824ae30..36c785adba9 100644 --- a/src/web/auto-reply.test-harness.ts +++ b/src/web/auto-reply.test-harness.ts @@ -3,6 +3,7 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, beforeEach, vi } from "vitest"; +import type { WebInboundMessage } from "./inbound.js"; import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js"; import * as ssrf from "../infra/net/ssrf.js"; import { resetLogger, setLoggerOverride } from "../logging.js"; @@ -117,3 +118,61 @@ export function installWebAutoReplyUnitTestHooks(opts?: { pinDns?: boolean }) { vi.useRealTimers(); }); } + +export function createWebListenerFactoryCapture() { + let capturedOnMessage: ((msg: WebInboundMessage) => Promise) | undefined; + const listenerFactory = async (opts: { + onMessage: (msg: WebInboundMessage) => Promise; + }) => { + capturedOnMessage = opts.onMessage; + return { close: vi.fn() }; + }; + + return { + listenerFactory, + getOnMessage: () => capturedOnMessage, + }; +} + +export function createWebInboundDeliverySpies() { + return { + sendMedia: vi.fn(), + reply: vi.fn().mockResolvedValue(undefined), + sendComposing: vi.fn(), + }; +} + +export async function sendWebGroupInboundMessage(params: { + onMessage: (msg: WebInboundMessage) => Promise; + body: string; + id: string; + senderE164: string; + senderName: string; + mentionedJids?: string[]; + selfE164?: string; + selfJid?: string; + spies: ReturnType; + conversationId?: string; + accountId?: string; +}) { + const conversationId = params.conversationId ?? "123@g.us"; + const accountId = params.accountId ?? "default"; + await params.onMessage({ + body: params.body, + from: conversationId, + conversationId, + chatId: conversationId, + chatType: "group", + to: "+2", + accountId, + id: params.id, + senderE164: params.senderE164, + senderName: params.senderName, + mentionedJids: params.mentionedJids, + selfE164: params.selfE164, + selfJid: params.selfJid, + sendComposing: params.spies.sendComposing, + reply: params.spies.reply, + sendMedia: params.spies.sendMedia, + } as WebInboundMessage); +} diff --git a/src/web/auto-reply.web-auto-reply.requires-mention-group-chats-injects-history-replying.test.ts b/src/web/auto-reply.web-auto-reply.requires-mention-group-chats-injects-history-replying.test.ts index e4a072fba6c..8991dfec1ff 100644 --- a/src/web/auto-reply.web-auto-reply.requires-mention-group-chats-injects-history-replying.test.ts +++ b/src/web/auto-reply.web-auto-reply.requires-mention-group-chats-injects-history-replying.test.ts @@ -3,10 +3,13 @@ import os from "node:os"; import path from "node:path"; import { beforeAll, describe, expect, it, vi } from "vitest"; import { + createWebInboundDeliverySpies, + createWebListenerFactoryCapture, installWebAutoReplyTestHomeHooks, installWebAutoReplyUnitTestHooks, resetLoadConfigMock, rmDirWithRetries, + sendWebGroupInboundMessage, setLoadConfigMock, } from "./auto-reply.test-harness.js"; @@ -22,58 +25,37 @@ describe("web auto-reply", () => { installWebAutoReplyUnitTestHooks(); it("requires mention in group chats and injects history when replying", async () => { - const sendMedia = vi.fn(); - const reply = vi.fn().mockResolvedValue(undefined); - const sendComposing = vi.fn(); + const spies = createWebInboundDeliverySpies(); const resolver = vi.fn().mockResolvedValue({ text: "ok" }); - let capturedOnMessage: - | ((msg: import("./inbound.js").WebInboundMessage) => Promise) - | undefined; - const listenerFactory = async (opts: { - onMessage: (msg: import("./inbound.js").WebInboundMessage) => Promise; - }) => { - capturedOnMessage = opts.onMessage; - return { close: vi.fn() }; - }; + const { listenerFactory, getOnMessage } = createWebListenerFactoryCapture(); await monitorWebChannel(false, listenerFactory, false, resolver); - expect(capturedOnMessage).toBeDefined(); + const onMessage = getOnMessage(); + expect(onMessage).toBeDefined(); - await capturedOnMessage?.({ + await sendWebGroupInboundMessage({ + onMessage: onMessage!, + spies, body: "hello group", - from: "123@g.us", - conversationId: "123@g.us", - chatId: "123@g.us", - chatType: "group", - to: "+2", id: "g1", senderE164: "+111", senderName: "Alice", selfE164: "+999", - sendComposing, - reply, - sendMedia, }); expect(resolver).not.toHaveBeenCalled(); - await capturedOnMessage?.({ + await sendWebGroupInboundMessage({ + onMessage: onMessage!, + spies, body: "@bot ping", - from: "123@g.us", - conversationId: "123@g.us", - chatId: "123@g.us", - chatType: "group", - to: "+2", id: "g2", senderE164: "+222", senderName: "Bob", mentionedJids: ["999@s.whatsapp.net"], selfE164: "+999", selfJid: "999@s.whatsapp.net", - sendComposing, - reply, - sendMedia, }); expect(resolver).toHaveBeenCalledTimes(1);