mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-22 07:01:44 +03:00
refactor(test): dedupe web auto-reply group message setup
This commit is contained in:
+16
-40
@@ -3,9 +3,12 @@ import { describe, expect, it, vi } from "vitest";
|
|||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
import { monitorWebChannel } from "./auto-reply.js";
|
import { monitorWebChannel } from "./auto-reply.js";
|
||||||
import {
|
import {
|
||||||
|
createWebInboundDeliverySpies,
|
||||||
|
createWebListenerFactoryCapture,
|
||||||
installWebAutoReplyTestHomeHooks,
|
installWebAutoReplyTestHomeHooks,
|
||||||
installWebAutoReplyUnitTestHooks,
|
installWebAutoReplyUnitTestHooks,
|
||||||
resetLoadConfigMock,
|
resetLoadConfigMock,
|
||||||
|
sendWebGroupInboundMessage,
|
||||||
setLoadConfigMock,
|
setLoadConfigMock,
|
||||||
} from "./auto-reply.test-harness.js";
|
} from "./auto-reply.test-harness.js";
|
||||||
|
|
||||||
@@ -81,58 +84,37 @@ describe("broadcast groups", () => {
|
|||||||
},
|
},
|
||||||
} satisfies OpenClawConfig);
|
} satisfies OpenClawConfig);
|
||||||
|
|
||||||
const sendMedia = vi.fn();
|
const spies = createWebInboundDeliverySpies();
|
||||||
const reply = vi.fn().mockResolvedValue(undefined);
|
|
||||||
const sendComposing = vi.fn();
|
|
||||||
const resolver = vi.fn().mockResolvedValue({ text: "ok" });
|
const resolver = vi.fn().mockResolvedValue({ text: "ok" });
|
||||||
|
|
||||||
let capturedOnMessage:
|
const { listenerFactory, getOnMessage } = createWebListenerFactoryCapture();
|
||||||
| ((msg: import("./inbound.js").WebInboundMessage) => Promise<void>)
|
|
||||||
| undefined;
|
|
||||||
const listenerFactory = async (opts: {
|
|
||||||
onMessage: (msg: import("./inbound.js").WebInboundMessage) => Promise<void>;
|
|
||||||
}) => {
|
|
||||||
capturedOnMessage = opts.onMessage;
|
|
||||||
return { close: vi.fn() };
|
|
||||||
};
|
|
||||||
|
|
||||||
await monitorWebChannel(false, listenerFactory, false, resolver);
|
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",
|
body: "hello group",
|
||||||
from: "123@g.us",
|
|
||||||
conversationId: "123@g.us",
|
|
||||||
chatId: "123@g.us",
|
|
||||||
chatType: "group",
|
|
||||||
to: "+2",
|
|
||||||
id: "g1",
|
id: "g1",
|
||||||
senderE164: "+111",
|
senderE164: "+111",
|
||||||
senderName: "Alice",
|
senderName: "Alice",
|
||||||
selfE164: "+999",
|
selfE164: "+999",
|
||||||
sendComposing,
|
|
||||||
reply,
|
|
||||||
sendMedia,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(resolver).not.toHaveBeenCalled();
|
expect(resolver).not.toHaveBeenCalled();
|
||||||
|
|
||||||
await capturedOnMessage?.({
|
await sendWebGroupInboundMessage({
|
||||||
|
onMessage: onMessage!,
|
||||||
|
spies,
|
||||||
body: "@bot ping",
|
body: "@bot ping",
|
||||||
from: "123@g.us",
|
|
||||||
conversationId: "123@g.us",
|
|
||||||
chatId: "123@g.us",
|
|
||||||
chatType: "group",
|
|
||||||
to: "+2",
|
|
||||||
id: "g2",
|
id: "g2",
|
||||||
senderE164: "+222",
|
senderE164: "+222",
|
||||||
senderName: "Bob",
|
senderName: "Bob",
|
||||||
mentionedJids: ["999@s.whatsapp.net"],
|
mentionedJids: ["999@s.whatsapp.net"],
|
||||||
selfE164: "+999",
|
selfE164: "+999",
|
||||||
selfJid: "999@s.whatsapp.net",
|
selfJid: "999@s.whatsapp.net",
|
||||||
sendComposing,
|
|
||||||
reply,
|
|
||||||
sendMedia,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(resolver).toHaveBeenCalledTimes(2);
|
expect(resolver).toHaveBeenCalledTimes(2);
|
||||||
@@ -153,22 +135,16 @@ describe("broadcast groups", () => {
|
|||||||
expect(payload.SenderId).toBe("+222");
|
expect(payload.SenderId).toBe("+222");
|
||||||
}
|
}
|
||||||
|
|
||||||
await capturedOnMessage?.({
|
await sendWebGroupInboundMessage({
|
||||||
|
onMessage: onMessage!,
|
||||||
|
spies,
|
||||||
body: "@bot ping 2",
|
body: "@bot ping 2",
|
||||||
from: "123@g.us",
|
|
||||||
conversationId: "123@g.us",
|
|
||||||
chatId: "123@g.us",
|
|
||||||
chatType: "group",
|
|
||||||
to: "+2",
|
|
||||||
id: "g3",
|
id: "g3",
|
||||||
senderE164: "+333",
|
senderE164: "+333",
|
||||||
senderName: "Clara",
|
senderName: "Clara",
|
||||||
mentionedJids: ["999@s.whatsapp.net"],
|
mentionedJids: ["999@s.whatsapp.net"],
|
||||||
selfE164: "+999",
|
selfE164: "+999",
|
||||||
selfJid: "999@s.whatsapp.net",
|
selfJid: "999@s.whatsapp.net",
|
||||||
sendComposing,
|
|
||||||
reply,
|
|
||||||
sendMedia,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(resolver).toHaveBeenCalledTimes(4);
|
expect(resolver).toHaveBeenCalledTimes(4);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import fs from "node:fs/promises";
|
|||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { afterEach, beforeEach, vi } from "vitest";
|
import { afterEach, beforeEach, vi } from "vitest";
|
||||||
|
import type { WebInboundMessage } from "./inbound.js";
|
||||||
import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js";
|
import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js";
|
||||||
import * as ssrf from "../infra/net/ssrf.js";
|
import * as ssrf from "../infra/net/ssrf.js";
|
||||||
import { resetLogger, setLoggerOverride } from "../logging.js";
|
import { resetLogger, setLoggerOverride } from "../logging.js";
|
||||||
@@ -117,3 +118,61 @@ export function installWebAutoReplyUnitTestHooks(opts?: { pinDns?: boolean }) {
|
|||||||
vi.useRealTimers();
|
vi.useRealTimers();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createWebListenerFactoryCapture() {
|
||||||
|
let capturedOnMessage: ((msg: WebInboundMessage) => Promise<void>) | undefined;
|
||||||
|
const listenerFactory = async (opts: {
|
||||||
|
onMessage: (msg: WebInboundMessage) => Promise<void>;
|
||||||
|
}) => {
|
||||||
|
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<void>;
|
||||||
|
body: string;
|
||||||
|
id: string;
|
||||||
|
senderE164: string;
|
||||||
|
senderName: string;
|
||||||
|
mentionedJids?: string[];
|
||||||
|
selfE164?: string;
|
||||||
|
selfJid?: string;
|
||||||
|
spies: ReturnType<typeof createWebInboundDeliverySpies>;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|||||||
+13
-31
@@ -3,10 +3,13 @@ import os from "node:os";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { beforeAll, describe, expect, it, vi } from "vitest";
|
import { beforeAll, describe, expect, it, vi } from "vitest";
|
||||||
import {
|
import {
|
||||||
|
createWebInboundDeliverySpies,
|
||||||
|
createWebListenerFactoryCapture,
|
||||||
installWebAutoReplyTestHomeHooks,
|
installWebAutoReplyTestHomeHooks,
|
||||||
installWebAutoReplyUnitTestHooks,
|
installWebAutoReplyUnitTestHooks,
|
||||||
resetLoadConfigMock,
|
resetLoadConfigMock,
|
||||||
rmDirWithRetries,
|
rmDirWithRetries,
|
||||||
|
sendWebGroupInboundMessage,
|
||||||
setLoadConfigMock,
|
setLoadConfigMock,
|
||||||
} from "./auto-reply.test-harness.js";
|
} from "./auto-reply.test-harness.js";
|
||||||
|
|
||||||
@@ -22,58 +25,37 @@ describe("web auto-reply", () => {
|
|||||||
installWebAutoReplyUnitTestHooks();
|
installWebAutoReplyUnitTestHooks();
|
||||||
|
|
||||||
it("requires mention in group chats and injects history when replying", async () => {
|
it("requires mention in group chats and injects history when replying", async () => {
|
||||||
const sendMedia = vi.fn();
|
const spies = createWebInboundDeliverySpies();
|
||||||
const reply = vi.fn().mockResolvedValue(undefined);
|
|
||||||
const sendComposing = vi.fn();
|
|
||||||
const resolver = vi.fn().mockResolvedValue({ text: "ok" });
|
const resolver = vi.fn().mockResolvedValue({ text: "ok" });
|
||||||
|
|
||||||
let capturedOnMessage:
|
const { listenerFactory, getOnMessage } = createWebListenerFactoryCapture();
|
||||||
| ((msg: import("./inbound.js").WebInboundMessage) => Promise<void>)
|
|
||||||
| undefined;
|
|
||||||
const listenerFactory = async (opts: {
|
|
||||||
onMessage: (msg: import("./inbound.js").WebInboundMessage) => Promise<void>;
|
|
||||||
}) => {
|
|
||||||
capturedOnMessage = opts.onMessage;
|
|
||||||
return { close: vi.fn() };
|
|
||||||
};
|
|
||||||
|
|
||||||
await monitorWebChannel(false, listenerFactory, false, resolver);
|
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",
|
body: "hello group",
|
||||||
from: "123@g.us",
|
|
||||||
conversationId: "123@g.us",
|
|
||||||
chatId: "123@g.us",
|
|
||||||
chatType: "group",
|
|
||||||
to: "+2",
|
|
||||||
id: "g1",
|
id: "g1",
|
||||||
senderE164: "+111",
|
senderE164: "+111",
|
||||||
senderName: "Alice",
|
senderName: "Alice",
|
||||||
selfE164: "+999",
|
selfE164: "+999",
|
||||||
sendComposing,
|
|
||||||
reply,
|
|
||||||
sendMedia,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(resolver).not.toHaveBeenCalled();
|
expect(resolver).not.toHaveBeenCalled();
|
||||||
|
|
||||||
await capturedOnMessage?.({
|
await sendWebGroupInboundMessage({
|
||||||
|
onMessage: onMessage!,
|
||||||
|
spies,
|
||||||
body: "@bot ping",
|
body: "@bot ping",
|
||||||
from: "123@g.us",
|
|
||||||
conversationId: "123@g.us",
|
|
||||||
chatId: "123@g.us",
|
|
||||||
chatType: "group",
|
|
||||||
to: "+2",
|
|
||||||
id: "g2",
|
id: "g2",
|
||||||
senderE164: "+222",
|
senderE164: "+222",
|
||||||
senderName: "Bob",
|
senderName: "Bob",
|
||||||
mentionedJids: ["999@s.whatsapp.net"],
|
mentionedJids: ["999@s.whatsapp.net"],
|
||||||
selfE164: "+999",
|
selfE164: "+999",
|
||||||
selfJid: "999@s.whatsapp.net",
|
selfJid: "999@s.whatsapp.net",
|
||||||
sendComposing,
|
|
||||||
reply,
|
|
||||||
sendMedia,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(resolver).toHaveBeenCalledTimes(1);
|
expect(resolver).toHaveBeenCalledTimes(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user