test(whatsapp): share inbox reconnect fixtures

This commit is contained in:
Vincent Koc
2026-04-12 08:28:51 +01:00
parent 6259064f93
commit e4abecd0f2

View File

@@ -32,6 +32,45 @@ function nextMessageId(label: string): string {
return `${label}-${nextMessageSequence}`;
}
function createSocketRef(): NonNullable<InboxMonitorOptions["socketRef"]> {
return { current: null };
}
async function primeInboundReplyHandle(params: {
onMessage: ReturnType<typeof vi.fn>;
socketRef: NonNullable<InboxMonitorOptions["socketRef"]>;
upsertId: string;
retryPolicy: NonNullable<InboxMonitorOptions["disconnectRetryPolicy"]>;
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<void>;
}
| 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<InboxMonitorOptions["socketRef"]> = { 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<void>;
}
| 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<InboxMonitorOptions["socketRef"]> = { 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<void>;
}
| 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<InboxMonitorOptions["socketRef"]> = { 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<void>;
}
| undefined;
expect(inbound).toBeDefined();
socketRef.current = null;