mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 18:50:42 +00:00
fix(whatsapp): remove ack reactions after replies
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
createAckReactionHandle,
|
||||
removeAckReactionHandleAfterReply,
|
||||
removeAckReactionAfterReply,
|
||||
shouldAckReaction,
|
||||
shouldAckReactionForWhatsApp,
|
||||
@@ -178,6 +180,48 @@ describe("shouldAckReactionForWhatsApp", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("createAckReactionHandle", () => {
|
||||
it("tracks a successful ack send", async () => {
|
||||
const send = vi.fn().mockResolvedValue(undefined);
|
||||
const remove = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
const handle = createAckReactionHandle({
|
||||
ackReactionValue: " 👀 ",
|
||||
send,
|
||||
remove,
|
||||
});
|
||||
|
||||
expect(handle).toMatchObject({ ackReactionValue: "👀", remove });
|
||||
expect(send).toHaveBeenCalledTimes(1);
|
||||
await expect(handle?.ackReactionPromise).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it("tracks a failed ack send without throwing", async () => {
|
||||
const error = new Error("nope");
|
||||
const onSendError = vi.fn();
|
||||
|
||||
const handle = createAckReactionHandle({
|
||||
ackReactionValue: "👀",
|
||||
send: vi.fn().mockRejectedValue(error),
|
||||
remove: vi.fn().mockResolvedValue(undefined),
|
||||
onSendError,
|
||||
});
|
||||
|
||||
await expect(handle?.ackReactionPromise).resolves.toBe(false);
|
||||
expect(onSendError).toHaveBeenCalledWith(error);
|
||||
});
|
||||
|
||||
it("skips empty ack values", () => {
|
||||
const handle = createAckReactionHandle({
|
||||
ackReactionValue: " ",
|
||||
send: vi.fn().mockResolvedValue(undefined),
|
||||
remove: vi.fn().mockResolvedValue(undefined),
|
||||
});
|
||||
|
||||
expect(handle).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("removeAckReactionAfterReply", () => {
|
||||
it("removes only when ack succeeded", async () => {
|
||||
const remove = vi.fn().mockResolvedValue(undefined);
|
||||
@@ -206,3 +250,20 @@ describe("removeAckReactionAfterReply", () => {
|
||||
expect(remove).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("removeAckReactionHandleAfterReply", () => {
|
||||
it("removes through an ack handle", async () => {
|
||||
const remove = vi.fn().mockResolvedValue(undefined);
|
||||
removeAckReactionHandleAfterReply({
|
||||
removeAfterReply: true,
|
||||
ackReaction: {
|
||||
ackReactionPromise: Promise.resolve(true),
|
||||
ackReactionValue: "👀",
|
||||
remove,
|
||||
},
|
||||
});
|
||||
|
||||
await flushMicrotasks();
|
||||
expect(remove).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,12 @@ export type AckReactionScope = "all" | "direct" | "group-all" | "group-mentions"
|
||||
|
||||
export type WhatsAppAckReactionMode = "always" | "mentions" | "never";
|
||||
|
||||
export type AckReactionHandle = {
|
||||
ackReactionPromise: Promise<boolean>;
|
||||
ackReactionValue: string;
|
||||
remove: () => Promise<void>;
|
||||
};
|
||||
|
||||
export type AckReactionGateParams = {
|
||||
scope: AckReactionScope | undefined;
|
||||
isDirect: boolean;
|
||||
@@ -78,6 +84,37 @@ export function shouldAckReactionForWhatsApp(params: {
|
||||
});
|
||||
}
|
||||
|
||||
export function createAckReactionHandle(params: {
|
||||
ackReactionValue: string;
|
||||
send: () => Promise<void>;
|
||||
remove: () => Promise<void>;
|
||||
onSendError?: (err: unknown) => void;
|
||||
}): AckReactionHandle | null {
|
||||
const ackReactionValue = params.ackReactionValue.trim();
|
||||
if (!ackReactionValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let sendPromise: Promise<void>;
|
||||
try {
|
||||
sendPromise = params.send();
|
||||
} catch (err) {
|
||||
sendPromise = Promise.reject(err);
|
||||
}
|
||||
|
||||
return {
|
||||
ackReactionPromise: sendPromise.then(
|
||||
() => true,
|
||||
(err) => {
|
||||
params.onSendError?.(err);
|
||||
return false;
|
||||
},
|
||||
),
|
||||
ackReactionValue,
|
||||
remove: params.remove,
|
||||
};
|
||||
}
|
||||
|
||||
export function removeAckReactionAfterReply(params: {
|
||||
removeAfterReply: boolean;
|
||||
ackReactionPromise: Promise<boolean> | null;
|
||||
@@ -101,3 +138,17 @@ export function removeAckReactionAfterReply(params: {
|
||||
params.remove().catch((err) => params.onError?.(err));
|
||||
});
|
||||
}
|
||||
|
||||
export function removeAckReactionHandleAfterReply(params: {
|
||||
removeAfterReply: boolean;
|
||||
ackReaction: AckReactionHandle | null | undefined;
|
||||
onError?: (err: unknown) => void;
|
||||
}) {
|
||||
removeAckReactionAfterReply({
|
||||
removeAfterReply: params.removeAfterReply,
|
||||
ackReactionPromise: params.ackReaction?.ackReactionPromise ?? null,
|
||||
ackReactionValue: params.ackReaction?.ackReactionValue ?? null,
|
||||
remove: params.ackReaction?.remove ?? (async () => {}),
|
||||
onError: params.onError,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user