diff --git a/extensions/whatsapp/src/monitor-inbox.streams-inbound-messages.test.ts b/extensions/whatsapp/src/monitor-inbox.streams-inbound-messages.test.ts index e77270d4a39..541c3943739 100644 --- a/extensions/whatsapp/src/monitor-inbox.streams-inbound-messages.test.ts +++ b/extensions/whatsapp/src/monitor-inbox.streams-inbound-messages.test.ts @@ -32,6 +32,45 @@ function nextMessageId(label: string): string { return `${label}-${nextMessageSequence}`; } +function createSocketRef(): NonNullable { + return { current: null }; +} + +async function primeInboundReplyHandle(params: { + onMessage: ReturnType; + socketRef: NonNullable; + upsertId: string; + retryPolicy: NonNullable; + useCurrentSock?: boolean; +}) { + const { listener, sock } = await startInboxMonitor(params.onMessage as InboxOnMessage, { + socketRef: params.socketRef, + shouldRetryDisconnect: () => true, + disconnectRetryPolicy: params.retryPolicy, + }); + const sourceSock = params.useCurrentSock ? getSock() : sock; + sourceSock.ev.emit( + "messages.upsert", + buildNotifyMessageUpsert({ + id: nextMessageId(params.upsertId), + remoteJid: "999@s.whatsapp.net", + text: "ping", + timestamp: 1_700_000_000, + pushName: "Tester", + }), + ); + await waitForMessageCalls(params.onMessage, 1); + + const inbound = params.onMessage.mock.calls.at(0)?.at(0) as + | { + reply: (text: string) => Promise; + } + | undefined; + expect(inbound).toBeDefined(); + + return { listener, sock, inbound }; +} + describe("web monitor inbox", () => { installWebMonitorInboxUnitTestHooks(); @@ -258,12 +297,12 @@ describe("web monitor inbox", () => { it("waits for a replacement socket before sending replies", async () => { const onMessage = vi.fn(async () => undefined); - const socketRef: NonNullable = { current: null }; - - const { listener, sock } = await startInboxMonitor(onMessage as InboxOnMessage, { + const socketRef = createSocketRef(); + const { listener, sock, inbound } = await primeInboundReplyHandle({ + onMessage, socketRef, - shouldRetryDisconnect: () => true, - disconnectRetryPolicy: { + upsertId: "reconnect-gap", + retryPolicy: { initialMs: 10, maxMs: 10, factor: 1, @@ -271,24 +310,6 @@ describe("web monitor inbox", () => { maxAttempts: 2, }, }); - sock.ev.emit( - "messages.upsert", - buildNotifyMessageUpsert({ - id: nextMessageId("reconnect-gap"), - remoteJid: "999@s.whatsapp.net", - text: "ping", - timestamp: 1_700_000_000, - pushName: "Tester", - }), - ); - await waitForMessageCalls(onMessage, 1); - - const inbound = onMessage.mock.calls.at(0)?.at(0) as - | { - reply: (text: string) => Promise; - } - | undefined; - expect(inbound).toBeDefined(); const replacementSock = { sendMessage: vi.fn(async () => undefined), @@ -314,12 +335,12 @@ describe("web monitor inbox", () => { it("retries timed-out sends on the same socket without clearing the socket ref", async () => { const onMessage = vi.fn(async () => undefined); - const socketRef: NonNullable = { current: null }; - - const { listener, sock } = await startInboxMonitor(onMessage as InboxOnMessage, { + const socketRef = createSocketRef(); + const { listener, sock, inbound } = await primeInboundReplyHandle({ + onMessage, socketRef, - shouldRetryDisconnect: () => true, - disconnectRetryPolicy: { + upsertId: "timeout-retry", + retryPolicy: { initialMs: 1, maxMs: 1, factor: 1, @@ -327,24 +348,6 @@ describe("web monitor inbox", () => { maxAttempts: 2, }, }); - sock.ev.emit( - "messages.upsert", - buildNotifyMessageUpsert({ - id: nextMessageId("timeout-retry"), - remoteJid: "999@s.whatsapp.net", - text: "ping", - timestamp: 1_700_000_000, - pushName: "Tester", - }), - ); - await waitForMessageCalls(onMessage, 1); - - const inbound = onMessage.mock.calls.at(0)?.at(0) as - | { - reply: (text: string) => Promise; - } - | undefined; - expect(inbound).toBeDefined(); sock.sendMessage .mockRejectedValueOnce(new Error("operation timed out")) @@ -366,37 +369,20 @@ describe("web monitor inbox", () => { it("bounds reconnect-gap retries even when reconnect attempts are unlimited", async () => { const onMessage = vi.fn(async () => undefined); - const socketRef: NonNullable = { current: null }; - - const { listener } = await startInboxMonitor(onMessage as InboxOnMessage, { + const socketRef = createSocketRef(); + const { listener, inbound } = await primeInboundReplyHandle({ + onMessage, socketRef, - shouldRetryDisconnect: () => true, - disconnectRetryPolicy: { + upsertId: "unlimited-reconnect-send-bound", + retryPolicy: { initialMs: 1, maxMs: 1, factor: 1, jitter: 0, maxAttempts: 0, }, + useCurrentSock: true, }); - getSock().ev.emit( - "messages.upsert", - buildNotifyMessageUpsert({ - id: nextMessageId("unlimited-reconnect-send-bound"), - remoteJid: "999@s.whatsapp.net", - text: "ping", - timestamp: 1_700_000_000, - pushName: "Tester", - }), - ); - await waitForMessageCalls(onMessage, 1); - - const inbound = onMessage.mock.calls.at(0)?.at(0) as - | { - reply: (text: string) => Promise; - } - | undefined; - expect(inbound).toBeDefined(); socketRef.current = null;