mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 17:34:45 +00:00
test: tighten whatsapp outbound assertions
This commit is contained in:
@@ -3,6 +3,31 @@ import { createWhatsAppOutboundBase } from "./outbound-base.js";
|
||||
import { createWhatsAppPollFixture } from "./outbound-test-support.js";
|
||||
import { cacheInboundMessageMeta } from "./quoted-message.js";
|
||||
|
||||
type MockWithCalls = {
|
||||
mock: { calls: unknown[][] };
|
||||
};
|
||||
|
||||
function sendMessageOptionsAt(
|
||||
mock: MockWithCalls,
|
||||
index: number,
|
||||
expectedTo: string,
|
||||
expectedText: string,
|
||||
): Record<string, unknown> {
|
||||
const call = mock.mock.calls[index];
|
||||
expect(call?.[0]).toBe(expectedTo);
|
||||
expect(call?.[1]).toBe(expectedText);
|
||||
const options = call?.[2];
|
||||
if (
|
||||
options === undefined ||
|
||||
options === null ||
|
||||
typeof options !== "object" ||
|
||||
Array.isArray(options)
|
||||
) {
|
||||
throw new Error(`expected send call ${index} to include options`);
|
||||
}
|
||||
return options as Record<string, unknown>;
|
||||
}
|
||||
|
||||
describe("createWhatsAppOutboundBase", () => {
|
||||
it("exposes the provided chunker", () => {
|
||||
const outbound = createWhatsAppOutboundBase({
|
||||
@@ -41,18 +66,14 @@ describe("createWhatsAppOutboundBase", () => {
|
||||
gifPlayback: false,
|
||||
});
|
||||
|
||||
expect(sendMessageWhatsApp).toHaveBeenCalledWith(
|
||||
"whatsapp:+15551234567",
|
||||
"photo",
|
||||
expect.objectContaining({
|
||||
verbose: false,
|
||||
mediaUrl: "/tmp/workspace/photo.png",
|
||||
mediaLocalRoots,
|
||||
accountId: "default",
|
||||
gifPlayback: false,
|
||||
}),
|
||||
);
|
||||
expect(result).toMatchObject({ channel: "whatsapp", messageId: "msg-1" });
|
||||
const options = sendMessageOptionsAt(sendMessageWhatsApp, 0, "whatsapp:+15551234567", "photo");
|
||||
expect(options.verbose).toBe(false);
|
||||
expect(options.mediaUrl).toBe("/tmp/workspace/photo.png");
|
||||
expect(options.mediaLocalRoots).toBe(mediaLocalRoots);
|
||||
expect(options.accountId).toBe("default");
|
||||
expect(options.gifPlayback).toBe(false);
|
||||
expect(result.channel).toBe("whatsapp");
|
||||
expect(result.messageId).toBe("msg-1");
|
||||
});
|
||||
|
||||
it("forwards audioAsVoice to sendMessageWhatsApp", async () => {
|
||||
@@ -78,15 +99,10 @@ describe("createWhatsAppOutboundBase", () => {
|
||||
deps: { sendWhatsApp: sendMessageWhatsApp },
|
||||
});
|
||||
|
||||
expect(sendMessageWhatsApp).toHaveBeenCalledWith(
|
||||
"whatsapp:+15551234567",
|
||||
"voice",
|
||||
expect.objectContaining({
|
||||
mediaUrl: "/tmp/workspace/voice.ogg",
|
||||
audioAsVoice: true,
|
||||
accountId: "default",
|
||||
}),
|
||||
);
|
||||
const options = sendMessageOptionsAt(sendMessageWhatsApp, 0, "whatsapp:+15551234567", "voice");
|
||||
expect(options.mediaUrl).toBe("/tmp/workspace/voice.ogg");
|
||||
expect(options.audioAsVoice).toBe(true);
|
||||
expect(options.accountId).toBe("default");
|
||||
});
|
||||
|
||||
it("uses the configured default account for quote metadata lookup when accountId is omitted", async () => {
|
||||
@@ -123,19 +139,14 @@ describe("createWhatsAppOutboundBase", () => {
|
||||
replyToId: "reply-1",
|
||||
});
|
||||
|
||||
expect(sendMessageWhatsApp).toHaveBeenCalledWith(
|
||||
"whatsapp:+15551234567",
|
||||
"reply",
|
||||
expect.objectContaining({
|
||||
quotedMessageKey: {
|
||||
id: "reply-1",
|
||||
remoteJid: "15551234567@s.whatsapp.net",
|
||||
fromMe: false,
|
||||
participant: "111@s.whatsapp.net",
|
||||
messageText: "quoted body",
|
||||
},
|
||||
}),
|
||||
);
|
||||
const options = sendMessageOptionsAt(sendMessageWhatsApp, 0, "whatsapp:+15551234567", "reply");
|
||||
expect(options.quotedMessageKey).toEqual({
|
||||
id: "reply-1",
|
||||
remoteJid: "15551234567@s.whatsapp.net",
|
||||
fromMe: false,
|
||||
participant: "111@s.whatsapp.net",
|
||||
messageText: "quoted body",
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes mixed-case defaultAccount before quote metadata lookup", async () => {
|
||||
@@ -173,19 +184,14 @@ describe("createWhatsAppOutboundBase", () => {
|
||||
replyToId: "reply-case",
|
||||
});
|
||||
|
||||
expect(sendMessageWhatsApp).toHaveBeenCalledWith(
|
||||
"whatsapp:+15551234567",
|
||||
"reply",
|
||||
expect.objectContaining({
|
||||
quotedMessageKey: {
|
||||
id: "reply-case",
|
||||
remoteJid: "15551234567@s.whatsapp.net",
|
||||
fromMe: false,
|
||||
participant: "333@s.whatsapp.net",
|
||||
messageText: "case-normalized body",
|
||||
},
|
||||
}),
|
||||
);
|
||||
const options = sendMessageOptionsAt(sendMessageWhatsApp, 0, "whatsapp:+15551234567", "reply");
|
||||
expect(options.quotedMessageKey).toEqual({
|
||||
id: "reply-case",
|
||||
remoteJid: "15551234567@s.whatsapp.net",
|
||||
fromMe: false,
|
||||
participant: "333@s.whatsapp.net",
|
||||
messageText: "case-normalized body",
|
||||
});
|
||||
});
|
||||
|
||||
it("matches sorted default-account fallback for quote metadata lookup when defaultAccount is unset", async () => {
|
||||
@@ -222,19 +228,14 @@ describe("createWhatsAppOutboundBase", () => {
|
||||
replyToId: "reply-2",
|
||||
});
|
||||
|
||||
expect(sendMessageWhatsApp).toHaveBeenCalledWith(
|
||||
"whatsapp:+15551234567",
|
||||
"reply",
|
||||
expect.objectContaining({
|
||||
quotedMessageKey: {
|
||||
id: "reply-2",
|
||||
remoteJid: "15551234567@s.whatsapp.net",
|
||||
fromMe: false,
|
||||
participant: "222@s.whatsapp.net",
|
||||
messageText: "sorted default body",
|
||||
},
|
||||
}),
|
||||
);
|
||||
const options = sendMessageOptionsAt(sendMessageWhatsApp, 0, "whatsapp:+15551234567", "reply");
|
||||
expect(options.quotedMessageKey).toEqual({
|
||||
id: "reply-2",
|
||||
remoteJid: "15551234567@s.whatsapp.net",
|
||||
fromMe: false,
|
||||
participant: "222@s.whatsapp.net",
|
||||
messageText: "sorted default body",
|
||||
});
|
||||
});
|
||||
|
||||
it("reuses the cached inbound remoteJid when the outbound target normalizes differently", async () => {
|
||||
@@ -272,19 +273,19 @@ describe("createWhatsAppOutboundBase", () => {
|
||||
replyToId: "reply-lid",
|
||||
});
|
||||
|
||||
expect(sendMessageWhatsApp).toHaveBeenCalledWith(
|
||||
const options = sendMessageOptionsAt(
|
||||
sendMessageWhatsApp,
|
||||
0,
|
||||
"whatsapp:+5511976136970",
|
||||
"reply",
|
||||
expect.objectContaining({
|
||||
quotedMessageKey: {
|
||||
id: "reply-lid",
|
||||
remoteJid: "277038292303944@lid",
|
||||
fromMe: true,
|
||||
participant: "5511976136970@s.whatsapp.net",
|
||||
messageText: "quoted from lid chat",
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(options.quotedMessageKey).toEqual({
|
||||
id: "reply-lid",
|
||||
remoteJid: "277038292303944@lid",
|
||||
fromMe: true,
|
||||
participant: "5511976136970@s.whatsapp.net",
|
||||
messageText: "quoted from lid chat",
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes explicit accountId before quote metadata lookup", async () => {
|
||||
@@ -321,19 +322,14 @@ describe("createWhatsAppOutboundBase", () => {
|
||||
replyToId: "reply-explicit",
|
||||
});
|
||||
|
||||
expect(sendMessageWhatsApp).toHaveBeenCalledWith(
|
||||
"whatsapp:+15551234567",
|
||||
"reply",
|
||||
expect.objectContaining({
|
||||
quotedMessageKey: {
|
||||
id: "reply-explicit",
|
||||
remoteJid: "15551234567@s.whatsapp.net",
|
||||
fromMe: false,
|
||||
participant: "333@s.whatsapp.net",
|
||||
messageText: "explicit account body",
|
||||
},
|
||||
}),
|
||||
);
|
||||
const options = sendMessageOptionsAt(sendMessageWhatsApp, 0, "whatsapp:+15551234567", "reply");
|
||||
expect(options.quotedMessageKey).toEqual({
|
||||
id: "reply-explicit",
|
||||
remoteJid: "15551234567@s.whatsapp.net",
|
||||
fromMe: false,
|
||||
participant: "333@s.whatsapp.net",
|
||||
messageText: "explicit account body",
|
||||
});
|
||||
});
|
||||
|
||||
it("falls back to the target JID when quote metadata only exists in a different conversation", async () => {
|
||||
@@ -370,19 +366,19 @@ describe("createWhatsAppOutboundBase", () => {
|
||||
replyToId: "reply-group",
|
||||
});
|
||||
|
||||
expect(sendMessageWhatsApp).toHaveBeenCalledWith(
|
||||
const options = sendMessageOptionsAt(
|
||||
sendMessageWhatsApp,
|
||||
0,
|
||||
"whatsapp:+5511976136970",
|
||||
"reply",
|
||||
expect.objectContaining({
|
||||
quotedMessageKey: {
|
||||
id: "reply-group",
|
||||
remoteJid: "5511976136970@s.whatsapp.net",
|
||||
fromMe: false,
|
||||
participant: undefined,
|
||||
messageText: undefined,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(options.quotedMessageKey).toEqual({
|
||||
id: "reply-group",
|
||||
remoteJid: "5511976136970@s.whatsapp.net",
|
||||
fromMe: false,
|
||||
participant: undefined,
|
||||
messageText: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes mediaUrls before payload delivery", async () => {
|
||||
@@ -410,14 +406,14 @@ describe("createWhatsAppOutboundBase", () => {
|
||||
});
|
||||
|
||||
expect(sendMessageWhatsApp).toHaveBeenCalledTimes(1);
|
||||
expect(sendMessageWhatsApp).toHaveBeenCalledWith(
|
||||
const options = sendMessageOptionsAt(
|
||||
sendMessageWhatsApp,
|
||||
0,
|
||||
"whatsapp:+15551234567",
|
||||
"caption",
|
||||
expect.objectContaining({
|
||||
verbose: false,
|
||||
mediaUrl: "/tmp/voice.ogg",
|
||||
}),
|
||||
);
|
||||
expect(options.verbose).toBe(false);
|
||||
expect(options.mediaUrl).toBe("/tmp/voice.ogg");
|
||||
});
|
||||
|
||||
it("keeps explicit mediaUrl first when payload also includes mediaUrls", async () => {
|
||||
@@ -445,22 +441,15 @@ describe("createWhatsAppOutboundBase", () => {
|
||||
deps: { sendWhatsApp: sendMessageWhatsApp },
|
||||
});
|
||||
|
||||
expect(sendMessageWhatsApp).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
const firstOptions = sendMessageOptionsAt(
|
||||
sendMessageWhatsApp,
|
||||
0,
|
||||
"whatsapp:+15551234567",
|
||||
"caption",
|
||||
expect.objectContaining({
|
||||
mediaUrl: "/tmp/primary.ogg",
|
||||
}),
|
||||
);
|
||||
expect(sendMessageWhatsApp).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
"whatsapp:+15551234567",
|
||||
"",
|
||||
expect.objectContaining({
|
||||
mediaUrl: "/tmp/secondary.ogg",
|
||||
}),
|
||||
);
|
||||
expect(firstOptions.mediaUrl).toBe("/tmp/primary.ogg");
|
||||
const secondOptions = sendMessageOptionsAt(sendMessageWhatsApp, 1, "whatsapp:+15551234567", "");
|
||||
expect(secondOptions.mediaUrl).toBe("/tmp/secondary.ogg");
|
||||
});
|
||||
|
||||
it("uses the caller-provided text normalization for payload delivery", async () => {
|
||||
@@ -487,13 +476,13 @@ describe("createWhatsAppOutboundBase", () => {
|
||||
deps: { sendWhatsApp: sendMessageWhatsApp },
|
||||
});
|
||||
|
||||
expect(sendMessageWhatsApp).toHaveBeenCalledWith(
|
||||
const options = sendMessageOptionsAt(
|
||||
sendMessageWhatsApp,
|
||||
0,
|
||||
"whatsapp:+15551234567",
|
||||
" indented",
|
||||
expect.objectContaining({
|
||||
verbose: false,
|
||||
}),
|
||||
);
|
||||
expect(options.verbose).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects structured-only payloads instead of reporting an empty successful send", async () => {
|
||||
|
||||
Reference in New Issue
Block a user