fix(whatsapp): allow media-only sends and normalize leading blank payloads (#14408)

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
Karim Naguib
2026-02-11 21:21:21 -08:00
committed by GitHub
parent 186dc0363f
commit 7a0591ef87
11 changed files with 352 additions and 14 deletions

View File

@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from "vitest";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { GatewayRequestContext } from "./types.js";
import { sendHandlers } from "./send.js";
@@ -47,6 +47,67 @@ const makeContext = (): GatewayRequestContext =>
}) as unknown as GatewayRequestContext;
describe("gateway send mirroring", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("accepts media-only sends without message", async () => {
mocks.deliverOutboundPayloads.mockResolvedValue([{ messageId: "m-media", channel: "slack" }]);
const respond = vi.fn();
await sendHandlers.send({
params: {
to: "channel:C1",
mediaUrl: "https://example.com/a.png",
channel: "slack",
idempotencyKey: "idem-media-only",
},
respond,
context: makeContext(),
req: { type: "req", id: "1", method: "send" },
client: null,
isWebchatConnect: () => false,
});
expect(mocks.deliverOutboundPayloads).toHaveBeenCalledWith(
expect.objectContaining({
payloads: [{ text: "", mediaUrl: "https://example.com/a.png", mediaUrls: undefined }],
}),
);
expect(respond).toHaveBeenCalledWith(
true,
expect.objectContaining({ messageId: "m-media" }),
undefined,
expect.objectContaining({ channel: "slack" }),
);
});
it("rejects empty sends when neither text nor media is present", async () => {
const respond = vi.fn();
await sendHandlers.send({
params: {
to: "channel:C1",
message: " ",
channel: "slack",
idempotencyKey: "idem-empty",
},
respond,
context: makeContext(),
req: { type: "req", id: "1", method: "send" },
client: null,
isWebchatConnect: () => false,
});
expect(mocks.deliverOutboundPayloads).not.toHaveBeenCalled();
expect(respond).toHaveBeenCalledWith(
false,
undefined,
expect.objectContaining({
message: expect.stringContaining("text or media is required"),
}),
);
});
it("does not mirror when delivery returns no results", async () => {
mocks.deliverOutboundPayloads.mockResolvedValue([]);