@@ -23,6 +23,7 @@ import {
2323 Create ,
2424 CryptographicKey ,
2525 Emoji ,
26+ EmojiReact ,
2627 Follow ,
2728 Image ,
2829 Like as RawLike ,
@@ -47,7 +48,7 @@ import { parseSemVer } from "./bot.ts";
4748import type { CustomEmoji } from "./emoji.ts" ;
4849import type { FollowRequest } from "./follow.ts" ;
4950import type { Message , MessageClass , SharedMessage } from "./message.ts" ;
50- import type { Like } from "./reaction.ts" ;
51+ import type { Like , Reaction } from "./reaction.ts" ;
5152import { MemoryRepository } from "./repository.ts" ;
5253import { SessionImpl } from "./session-impl.ts" ;
5354import type { Session } from "./session.ts" ;
@@ -1902,6 +1903,212 @@ Deno.test("BotImpl.onUnliked()", async () => {
19021903 assertEquals ( likes , [ ] ) ;
19031904} ) ;
19041905
1906+ Deno . test ( "BotImpl.onReacted()" , async ( ) => {
1907+ const bot = new BotImpl < void > ( {
1908+ kv : new MemoryKvStore ( ) ,
1909+ username : "bot" ,
1910+ } ) ;
1911+ const reactions : [ Session < void > , Reaction < void > ] [ ] = [ ] ;
1912+ bot . onReact = ( session , reaction ) =>
1913+ void ( reactions . push ( [ session , reaction ] ) ) ;
1914+ const ctx = createMockInboxContext ( bot , "https://example.com" , "bot" ) ;
1915+
1916+ // Test with Like containing an emoji name
1917+ const rawLike = new RawLike ( {
1918+ id : new URL ( "https://example.com/ap/actor/bot/like/1" ) ,
1919+ actor : new URL ( "https://example.com/ap/actor/bot" ) ,
1920+ name : ":heart:" ,
1921+ object : new Note ( {
1922+ id : new URL ( "https://example.com/ap/actor/bot/note/1" ) ,
1923+ attribution : new URL ( "https://example.com/ap/actor/bot" ) ,
1924+ to : PUBLIC_COLLECTION ,
1925+ cc : new URL ( "https://example.com/ap/actor/bot/followers" ) ,
1926+ content : "Hello, world!" ,
1927+ } ) ,
1928+ tags : [
1929+ new Emoji ( {
1930+ id : new URL ( "https://example.com/ap/emoji/heart" ) ,
1931+ name : ":heart:" ,
1932+ icon : new Image ( {
1933+ mediaType : "image/png" ,
1934+ url : new URL ( "https://example.com/emoji/heart.png" ) ,
1935+ } ) ,
1936+ } ) ,
1937+ ] ,
1938+ } ) ;
1939+
1940+ await bot . onReacted ( ctx , rawLike ) ;
1941+ assertEquals ( reactions . length , 1 ) ;
1942+ const [ session , reaction ] = reactions [ 0 ] ;
1943+ assertEquals ( session . bot , bot ) ;
1944+ assertEquals ( session . context , ctx ) ;
1945+ assertEquals ( reaction . raw , rawLike ) ;
1946+ assertEquals ( reaction . id , rawLike . id ) ;
1947+ assertEquals ( reaction . actor . id , rawLike . actorId ) ;
1948+ assertEquals ( reaction . message . id , rawLike . objectId ) ;
1949+ assertInstanceOf ( reaction . emoji , Emoji ) ;
1950+ assertEquals ( reaction . emoji . name , ":heart:" ) ;
1951+ assertEquals ( ctx . sentActivities , [ ] ) ;
1952+ assertEquals ( ctx . forwardedRecipients , [ ] ) ;
1953+
1954+ // Test with EmojiReact
1955+ reactions . pop ( ) ;
1956+ const emojiReact = new EmojiReact ( {
1957+ id : new URL ( "https://example.com/ap/actor/bot/react/1" ) ,
1958+ actor : new URL ( "https://example.com/ap/actor/bot" ) ,
1959+ name : ":thumbsup:" ,
1960+ object : new Note ( {
1961+ id : new URL ( "https://example.com/ap/actor/bot/note/1" ) ,
1962+ attribution : new URL ( "https://example.com/ap/actor/bot" ) ,
1963+ to : PUBLIC_COLLECTION ,
1964+ cc : new URL ( "https://example.com/ap/actor/bot/followers" ) ,
1965+ content : "Hello, world!" ,
1966+ } ) ,
1967+ tags : [
1968+ new Emoji ( {
1969+ id : new URL ( "https://example.com/ap/emoji/thumbsup" ) ,
1970+ name : ":thumbsup:" ,
1971+ icon : new Image ( {
1972+ mediaType : "image/png" ,
1973+ url : new URL ( "https://example.com/emoji/thumbsup.png" ) ,
1974+ } ) ,
1975+ } ) ,
1976+ ] ,
1977+ } ) ;
1978+
1979+ await bot . onReacted ( ctx , emojiReact ) ;
1980+ assertEquals ( reactions . length , 1 ) ;
1981+ const [ session2 , reaction2 ] = reactions [ 0 ] ;
1982+ assertEquals ( session2 . bot , bot ) ;
1983+ assertEquals ( session2 . context , ctx ) ;
1984+ assertEquals ( reaction2 . raw , emojiReact ) ;
1985+ assertEquals ( reaction2 . id , emojiReact . id ) ;
1986+ assertEquals ( reaction2 . actor . id , emojiReact . actorId ) ;
1987+ assertEquals ( reaction2 . message . id , emojiReact . objectId ) ;
1988+ assertInstanceOf ( reaction2 . emoji , Emoji ) ;
1989+ assertEquals ( reaction2 . emoji . name , ":thumbsup:" ) ;
1990+ assertEquals ( ctx . sentActivities , [ ] ) ;
1991+ assertEquals ( ctx . forwardedRecipients , [ ] ) ;
1992+ } ) ;
1993+
1994+ Deno . test ( "BotImpl.onUnreacted()" , async ( ) => {
1995+ const bot = new BotImpl < void > ( {
1996+ kv : new MemoryKvStore ( ) ,
1997+ username : "bot" ,
1998+ } ) ;
1999+ const reactions : [ Session < void > , Reaction < void > ] [ ] = [ ] ;
2000+ bot . onUnreact = ( session , reaction ) =>
2001+ void ( reactions . push ( [ session , reaction ] ) ) ;
2002+ const ctx = createMockInboxContext ( bot , "https://example.com" , "bot" ) ;
2003+
2004+ // Test with Like containing an emoji name
2005+ const rawLike = new RawLike ( {
2006+ id : new URL ( "https://example.com/ap/actor/bot/like/1" ) ,
2007+ actor : new URL ( "https://example.com/ap/actor/bot" ) ,
2008+ name : ":heart:" ,
2009+ object : new Note ( {
2010+ id : new URL ( "https://example.com/ap/actor/bot/note/1" ) ,
2011+ attribution : new URL ( "https://example.com/ap/actor/bot" ) ,
2012+ to : PUBLIC_COLLECTION ,
2013+ cc : new URL ( "https://example.com/ap/actor/bot/followers" ) ,
2014+ content : "Hello, world!" ,
2015+ } ) ,
2016+ tags : [
2017+ new Emoji ( {
2018+ id : new URL ( "https://example.com/ap/emoji/heart" ) ,
2019+ name : ":heart:" ,
2020+ icon : new Image ( {
2021+ mediaType : "image/png" ,
2022+ url : new URL ( "https://example.com/emoji/heart.png" ) ,
2023+ } ) ,
2024+ } ) ,
2025+ ] ,
2026+ } ) ;
2027+
2028+ const undo = new Undo ( {
2029+ id : new URL ( "https://example.com/ap/actor/bot/unreact/1" ) ,
2030+ actor : new URL ( "https://example.com/ap/actor/bot" ) ,
2031+ object : rawLike ,
2032+ } ) ;
2033+
2034+ await bot . onUnreacted ( ctx , undo ) ;
2035+ assertEquals ( reactions . length , 1 ) ;
2036+ const [ session , reaction ] = reactions [ 0 ] ;
2037+ assertEquals ( session . bot , bot ) ;
2038+ assertEquals ( session . context , ctx ) ;
2039+ assertEquals ( reaction . raw , rawLike ) ;
2040+ assertEquals ( reaction . id , rawLike . id ) ;
2041+ assertEquals ( reaction . actor . id , rawLike . actorId ) ;
2042+ assertEquals ( reaction . message . id , rawLike . objectId ) ;
2043+ assertInstanceOf ( reaction . emoji , Emoji ) ;
2044+ assertEquals ( reaction . emoji . name , ":heart:" ) ;
2045+ assertEquals ( ctx . sentActivities , [ ] ) ;
2046+ assertEquals ( ctx . forwardedRecipients , [ ] ) ;
2047+
2048+ // Test with EmojiReact
2049+ reactions . pop ( ) ;
2050+ const emojiReact = new EmojiReact ( {
2051+ id : new URL ( "https://example.com/ap/actor/bot/react/1" ) ,
2052+ actor : new URL ( "https://example.com/ap/actor/bot" ) ,
2053+ name : ":thumbsup:" ,
2054+ object : new Note ( {
2055+ id : new URL ( "https://example.com/ap/actor/bot/note/1" ) ,
2056+ attribution : new URL ( "https://example.com/ap/actor/bot" ) ,
2057+ to : PUBLIC_COLLECTION ,
2058+ cc : new URL ( "https://example.com/ap/actor/bot/followers" ) ,
2059+ content : "Hello, world!" ,
2060+ } ) ,
2061+ tags : [
2062+ new Emoji ( {
2063+ id : new URL ( "https://example.com/ap/emoji/thumbsup" ) ,
2064+ name : ":thumbsup:" ,
2065+ icon : new Image ( {
2066+ mediaType : "image/png" ,
2067+ url : new URL ( "https://example.com/emoji/thumbsup.png" ) ,
2068+ } ) ,
2069+ } ) ,
2070+ ] ,
2071+ } ) ;
2072+
2073+ const undoEmojiReact = new Undo ( {
2074+ id : new URL ( "https://example.com/ap/actor/bot/unreact/2" ) ,
2075+ actor : new URL ( "https://example.com/ap/actor/bot" ) ,
2076+ object : emojiReact ,
2077+ } ) ;
2078+
2079+ await bot . onUnreacted ( ctx , undoEmojiReact ) ;
2080+ assertEquals ( reactions . length , 1 ) ;
2081+ const [ session2 , reaction2 ] = reactions [ 0 ] ;
2082+ assertEquals ( session2 . bot , bot ) ;
2083+ assertEquals ( session2 . context , ctx ) ;
2084+ assertEquals ( reaction2 . raw , emojiReact ) ;
2085+ assertEquals ( reaction2 . id , emojiReact . id ) ;
2086+ assertEquals ( reaction2 . actor . id , emojiReact . actorId ) ;
2087+ assertEquals ( reaction2 . message . id , emojiReact . objectId ) ;
2088+ assertInstanceOf ( reaction2 . emoji , Emoji ) ;
2089+ assertEquals ( reaction2 . emoji . name , ":thumbsup:" ) ;
2090+ assertEquals ( ctx . sentActivities , [ ] ) ;
2091+ assertEquals ( ctx . forwardedRecipients , [ ] ) ;
2092+
2093+ // Test with mismatched actor
2094+ reactions . pop ( ) ;
2095+ const invalidUndo = undoEmojiReact . clone ( {
2096+ actor : new URL ( "https://example.com/ap/actor/another" ) ,
2097+ } ) ;
2098+ await bot . onUnreacted ( ctx , invalidUndo ) ;
2099+ assertEquals ( reactions , [ ] ) ;
2100+
2101+ // Test with non-reaction object
2102+ reactions . pop ( ) ;
2103+ const nonReactionUndo = new Undo ( {
2104+ id : new URL ( "https://example.com/ap/actor/bot/unreact/3" ) ,
2105+ actor : new URL ( "https://example.com/ap/actor/bot" ) ,
2106+ object : new Note ( { } ) ,
2107+ } ) ;
2108+ await bot . onUnreacted ( ctx , nonReactionUndo ) ;
2109+ assertEquals ( reactions , [ ] ) ;
2110+ } ) ;
2111+
19052112Deno . test ( "BotImpl.dispatchNodeInfo()" , ( ) => {
19062113 const bot = new BotImpl < void > ( {
19072114 kv : new MemoryKvStore ( ) ,
@@ -2176,3 +2383,5 @@ function createMockInboxContext(
21762383 } ;
21772384 return ctx ;
21782385}
2386+
2387+ // cSpell: ignore thumbsup
0 commit comments