git » sdk » commit 49f911a

Fix custom reaction issue

author Eric Roberts
2026-09-09 21:03:15 UTC
committer Stephen Paul Weber
2026-09-14 13:41:46 UTC
parent 47af9111bb32c51c223f3c0c1ec45f24bf0777a7

Fix custom reaction issue

We had code that should allow rescinding a custom reaction, however it
had bugs. It's almost never (maybe actually never) exercised, and
there's no test for it, so nobody noticed.

I was experimenting with adding linting which exposed the typo on
reactToMesssage.

I was able to write a failing test and then fix the code, which also
necessitated fixing the fact that html() doesn't exist anymore either.

borogove/persistence/IDB.js +4 -1
test/persistence-tests.ts +74 -0

diff --git a/borogove/persistence/IDB.js b/borogove/persistence/IDB.js
index cd245a9..8386dc1 100644
--- a/borogove/persistence/IDB.js
+++ b/borogove/persistence/IDB.js
@@ -1278,7 +1278,10 @@ export default async (dbname, media, tokenize, stemmer) => {
 						]),
 					),
 			);
-			if (reactionResult?.value?.append && message.html().trim() == "") {
+			if (
+				reactionResult?.value?.append &&
+				message.body().toPlainText().trim() == ""
+			) {
 				const reactToMessage = await this.getMessage(
 					account,
 					message.chatId(),
diff --git a/test/persistence-tests.ts b/test/persistence-tests.ts
index 55d3ab4..0a4ef6c 100644
--- a/test/persistence-tests.ts
+++ b/test/persistence-tests.ts
@@ -2369,6 +2369,80 @@ export function sharedPersistenceTests(test: PersistenceTest) {
 
 		expect(result).toBe("Hello");
 	});
+
+	test("allows rescinding a custom reaction", async ({
+		page,
+		borogove,
+		persistence,
+	}) => {
+		const result = await page.evaluate(
+			async ({ borogove, persistence }) => {
+				const account = "alice@example.com";
+				const chatId = "hatter@example.com";
+				const targetLocalId = "target-message";
+				const reactionMessageId = "reaction-message";
+				const timestamp = "2026-09-09T12:00:00Z";
+
+				const targetBuilder = new borogove.ChatMessageBuilder({
+					localId: targetLocalId,
+					senderId: account,
+					direction: 1,
+				});
+				targetBuilder.sortId = "a0";
+				targetBuilder.to = borogove.JID.parse(chatId);
+				targetBuilder.from = borogove.JID.parse(account);
+				targetBuilder.recipients = [targetBuilder.to];
+				targetBuilder.replyTo = [targetBuilder.from];
+
+				await persistence.storeMessages(account, [targetBuilder.build()]);
+
+				const reaction = new borogove.CustomEmojiReaction(
+					account,
+					timestamp,
+					"tada",
+					"https://example.com/tada.png",
+					reactionMessageId,
+				);
+				const update = new borogove.ReactionUpdate(
+					reactionMessageId,
+					null,
+					null,
+					targetLocalId,
+					chatId,
+					account,
+					timestamp,
+					[reaction],
+					borogove.ReactionUpdateKind.AppendReactions,
+				);
+
+				const withReaction = await persistence.storeReaction(account, update);
+
+				const emptyBuilder = new borogove.ChatMessageBuilder({
+					localId: reactionMessageId,
+					senderId: account,
+					direction: 1,
+				});
+				emptyBuilder.sortId = "a1";
+				emptyBuilder.to = borogove.JID.parse(chatId);
+				emptyBuilder.from = borogove.JID.parse(account);
+				emptyBuilder.recipients = [emptyBuilder.to];
+				emptyBuilder.replyTo = [emptyBuilder.from];
+
+				const [stored] = await persistence.storeMessages(account, [
+					emptyBuilder.build(),
+				]);
+
+				return {
+					before: [...withReaction!.reactions.keys()],
+					after: [...stored.reactions.keys()],
+				};
+			},
+			{ borogove, persistence },
+		);
+
+		expect(result.before).toEqual(["https://example.com/tada.png"]);
+		expect(result.after).toEqual([]);
+	});
 }
 
 type TestKeyPair = {