@@ -23,6 +23,7 @@ import {
23
23
Create ,
24
24
CryptographicKey ,
25
25
Emoji ,
26
+ EmojiReact ,
26
27
Follow ,
27
28
Image ,
28
29
Like as RawLike ,
@@ -47,7 +48,7 @@ import { parseSemVer } from "./bot.ts";
47
48
import type { CustomEmoji } from "./emoji.ts" ;
48
49
import type { FollowRequest } from "./follow.ts" ;
49
50
import type { Message , MessageClass , SharedMessage } from "./message.ts" ;
50
- import type { Like } from "./reaction.ts" ;
51
+ import type { Like , Reaction } from "./reaction.ts" ;
51
52
import { MemoryRepository } from "./repository.ts" ;
52
53
import { SessionImpl } from "./session-impl.ts" ;
53
54
import type { Session } from "./session.ts" ;
@@ -1902,6 +1903,212 @@ Deno.test("BotImpl.onUnliked()", async () => {
1902
1903
assertEquals ( likes , [ ] ) ;
1903
1904
} ) ;
1904
1905
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
+
1905
2112
Deno . test ( "BotImpl.dispatchNodeInfo()" , ( ) => {
1906
2113
const bot = new BotImpl < void > ( {
1907
2114
kv : new MemoryKvStore ( ) ,
@@ -2176,3 +2383,5 @@ function createMockInboxContext(
2176
2383
} ;
2177
2384
return ctx ;
2178
2385
}
2386
+
2387
+ // cSpell: ignore thumbsup
0 commit comments