@@ -127,8 +127,10 @@ export const Generic = () => {
127127 const createChannel = ( messagesOverride ) => {
128128 const id = uuidv4 ( ) ;
129129 const cid = `messaging:${ id } ` ;
130- const begin = getRandomInt ( 0 , allUsers . length - 2 ) ; // begin shouldn't be the end of users.length
131- const end = getRandomInt ( begin + 1 , allUsers . length - 1 ) ;
130+ // always guarantee at least 2 members for ease of use; cases that need to test specific behaviour
131+ // for 1 or 0 member channels should explicitly generate them.
132+ const begin = getRandomInt ( 0 , allUsers . length - 3 ) ; // begin shouldn't be the end of users.length
133+ const end = getRandomInt ( begin + 2 , allUsers . length - 1 ) ;
132134 const usersForMembers = allUsers . slice ( begin , end ) ;
133135 const members = usersForMembers . map ( ( user ) =>
134136 generateMember ( {
@@ -785,6 +787,155 @@ export const Generic = () => {
785787 } ) ;
786788 } ) ;
787789
790+ it ( 'should correctly add multiple reactions to the DB' , async ( ) => {
791+ useMockedApis ( chatClient , [ queryChannelsApi ( channels ) ] ) ;
792+ renderComponent ( ) ;
793+ act ( ( ) => dispatchConnectionChangedEvent ( chatClient ) ) ;
794+ await act ( async ( ) => await chatClient . offlineDb . syncManager . invokeSyncStatusListeners ( true ) ) ;
795+ await waitFor ( ( ) => expect ( screen . getByTestId ( 'channel-list' ) ) . toBeTruthy ( ) ) ;
796+
797+ const targetChannel = channels [ getRandomInt ( 0 , channels . length - 1 ) ] ;
798+ const targetMessage =
799+ targetChannel . messages [ getRandomInt ( 0 , targetChannel . messages . length - 1 ) ] ;
800+ const reactionMember =
801+ targetChannel . members [ getRandomInt ( 0 , targetChannel . members . length - 1 ) ] ;
802+ const someOtherMember = targetChannel . members . filter (
803+ ( member ) => reactionMember . user . id !== member . user . id ,
804+ ) [ getRandomInt ( 0 , targetChannel . members . length - 2 ) ] ;
805+
806+ const newReactions = [
807+ generateReaction ( {
808+ message_id : targetMessage . id ,
809+ type : 'wow' ,
810+ user : reactionMember . user ,
811+ } ) ,
812+ generateReaction ( {
813+ message_id : targetMessage . id ,
814+ type : 'wow' ,
815+ user : someOtherMember . user ,
816+ } ) ,
817+ generateReaction ( {
818+ message_id : targetMessage . id ,
819+ type : 'love' ,
820+ user : reactionMember . user ,
821+ } ) ,
822+ ] ;
823+ const messageWithNewReactionBase = {
824+ ...targetMessage ,
825+ latest_reactions : [ ...targetMessage . latest_reactions ] ,
826+ } ;
827+ const newLatestReactions = [ ] ;
828+
829+ newReactions . forEach ( ( newReaction ) => {
830+ newLatestReactions . push ( newReaction ) ;
831+ const messageWithNewReaction = {
832+ ...messageWithNewReactionBase ,
833+ latest_reactions : [ ...messageWithNewReactionBase . latest_reactions , ...newLatestReactions ] ,
834+ } ;
835+ act ( ( ) =>
836+ dispatchReactionNewEvent (
837+ chatClient ,
838+ newReaction ,
839+ messageWithNewReaction ,
840+ targetChannel . channel ,
841+ ) ,
842+ ) ;
843+ } ) ;
844+
845+ const finalReactionCount =
846+ messageWithNewReactionBase . latest_reactions . length +
847+ newReactions . filter (
848+ ( newReaction ) =>
849+ ! messageWithNewReactionBase . latest_reactions . some (
850+ ( initialReaction ) =>
851+ initialReaction . type === newReaction . type &&
852+ initialReaction . user . id === newReaction . user . id ,
853+ ) ,
854+ ) . length ;
855+
856+ await waitFor ( async ( ) => {
857+ const reactionsRows = await BetterSqlite . selectFromTable ( 'reactions' ) ;
858+ const matchingReactionsRows = reactionsRows . filter (
859+ ( r ) => r . messageId === messageWithNewReactionBase . id ,
860+ ) ;
861+
862+ expect ( matchingReactionsRows . length ) . toBe ( finalReactionCount ) ;
863+ newReactions . forEach ( ( newReaction ) => {
864+ expect (
865+ matchingReactionsRows . filter (
866+ ( reaction ) =>
867+ reaction . type === newReaction . type && reaction . userId === newReaction . user . id ,
868+ ) . length ,
869+ ) . toBe ( 1 ) ;
870+ } ) ;
871+ } ) ;
872+ } ) ;
873+
874+ it ( 'should gracefully handle multiple reaction.new events of the same type for the same user' , async ( ) => {
875+ useMockedApis ( chatClient , [ queryChannelsApi ( channels ) ] ) ;
876+ renderComponent ( ) ;
877+ act ( ( ) => dispatchConnectionChangedEvent ( chatClient ) ) ;
878+ await act ( async ( ) => await chatClient . offlineDb . syncManager . invokeSyncStatusListeners ( true ) ) ;
879+ await waitFor ( ( ) => expect ( screen . getByTestId ( 'channel-list' ) ) . toBeTruthy ( ) ) ;
880+
881+ const targetChannel = channels [ getRandomInt ( 0 , channels . length - 1 ) ] ;
882+ const targetMessage =
883+ targetChannel . messages [ getRandomInt ( 0 , targetChannel . messages . length - 1 ) ] ;
884+ const reactionMember =
885+ targetChannel . members [ getRandomInt ( 0 , targetChannel . members . length - 1 ) ] ;
886+
887+ const newReactions = [
888+ generateReaction ( {
889+ message_id : targetMessage . id ,
890+ type : 'wow' ,
891+ user : reactionMember . user ,
892+ } ) ,
893+ generateReaction ( {
894+ message_id : targetMessage . id ,
895+ type : 'wow' ,
896+ user : reactionMember . user ,
897+ } ) ,
898+ generateReaction ( {
899+ message_id : targetMessage . id ,
900+ type : 'wow' ,
901+ user : reactionMember . user ,
902+ } ) ,
903+ ] ;
904+ const messageWithNewReactionBase = {
905+ ...targetMessage ,
906+ latest_reactions : [ ...targetMessage . latest_reactions ] ,
907+ } ;
908+ const newLatestReactions = [ ] ;
909+
910+ newReactions . forEach ( ( newReaction ) => {
911+ newLatestReactions . push ( newReaction ) ;
912+ const messageWithNewReaction = {
913+ ...messageWithNewReactionBase ,
914+ latest_reactions : [ ...messageWithNewReactionBase . latest_reactions , ...newLatestReactions ] ,
915+ } ;
916+ act ( ( ) =>
917+ dispatchReactionNewEvent (
918+ chatClient ,
919+ newReaction ,
920+ messageWithNewReaction ,
921+ targetChannel . channel ,
922+ ) ,
923+ ) ;
924+ } ) ;
925+
926+ await waitFor ( async ( ) => {
927+ const reactionsRows = await BetterSqlite . selectFromTable ( 'reactions' ) ;
928+ const matchingReactionsRows = reactionsRows . filter (
929+ ( r ) =>
930+ r . type === 'wow' &&
931+ r . userId === reactionMember . user . id &&
932+ r . messageId === messageWithNewReactionBase . id ,
933+ ) ;
934+
935+ expect ( matchingReactionsRows . length ) . toBe ( 1 ) ;
936+ } ) ;
937+ } ) ;
938+
788939 it ( 'should remove a reaction from DB when reaction is deleted' , async ( ) => {
789940 useMockedApis ( chatClient , [ queryChannelsApi ( channels ) ] ) ;
790941
@@ -877,6 +1028,103 @@ export const Generic = () => {
8771028 } ) ;
8781029 } ) ;
8791030
1031+ it ( 'should correctly upsert reactions when enforce_unique is true' , async ( ) => {
1032+ useMockedApis ( chatClient , [ queryChannelsApi ( channels ) ] ) ;
1033+ renderComponent ( ) ;
1034+ act ( ( ) => dispatchConnectionChangedEvent ( chatClient ) ) ;
1035+ await act ( async ( ) => await chatClient . offlineDb . syncManager . invokeSyncStatusListeners ( true ) ) ;
1036+ await waitFor ( ( ) => expect ( screen . getByTestId ( 'channel-list' ) ) . toBeTruthy ( ) ) ;
1037+
1038+ const targetChannel = channels [ getRandomInt ( 0 , channels . length - 1 ) ] ;
1039+ const targetMessage =
1040+ targetChannel . messages [ getRandomInt ( 0 , targetChannel . messages . length - 1 ) ] ;
1041+ const reactionMember =
1042+ targetChannel . members [ getRandomInt ( 0 , targetChannel . members . length - 1 ) ] ;
1043+
1044+ const newReactions = [
1045+ generateReaction ( {
1046+ message_id : targetMessage . id ,
1047+ type : 'wow' ,
1048+ user : reactionMember . user ,
1049+ } ) ,
1050+ generateReaction ( {
1051+ message_id : targetMessage . id ,
1052+ type : 'love' ,
1053+ user : reactionMember . user ,
1054+ } ) ,
1055+ ] ;
1056+ const messageWithNewReactionBase = {
1057+ ...targetMessage ,
1058+ latest_reactions : [ ...targetMessage . latest_reactions ] ,
1059+ } ;
1060+ const newLatestReactions = [ ] ;
1061+
1062+ newReactions . forEach ( ( newReaction ) => {
1063+ newLatestReactions . push ( newReaction ) ;
1064+ const messageWithNewReaction = {
1065+ ...messageWithNewReactionBase ,
1066+ latest_reactions : [ ...messageWithNewReactionBase . latest_reactions , ...newLatestReactions ] ,
1067+ } ;
1068+ act ( ( ) =>
1069+ dispatchReactionNewEvent (
1070+ chatClient ,
1071+ newReaction ,
1072+ messageWithNewReaction ,
1073+ targetChannel . channel ,
1074+ ) ,
1075+ ) ;
1076+ } ) ;
1077+
1078+ await waitFor ( async ( ) => {
1079+ const reactionsRows = await BetterSqlite . selectFromTable ( 'reactions' ) ;
1080+ const matchingReactionsRows = reactionsRows . filter (
1081+ ( r ) =>
1082+ r . messageId === messageWithNewReactionBase . id && r . userId === reactionMember . user . id ,
1083+ ) ;
1084+
1085+ expect ( matchingReactionsRows . length ) . toBe ( 2 ) ;
1086+ newReactions . forEach ( ( newReaction ) => {
1087+ expect (
1088+ matchingReactionsRows . filter (
1089+ ( reaction ) =>
1090+ reaction . type === newReaction . type && reaction . userId === newReaction . user . id ,
1091+ ) . length ,
1092+ ) . toBe ( 1 ) ;
1093+ } ) ;
1094+ } ) ;
1095+
1096+ const uniqueReaction = generateReaction ( {
1097+ message_id : targetMessage . id ,
1098+ type : 'like' ,
1099+ user : reactionMember . user ,
1100+ } ) ;
1101+ const messageWithNewReaction = {
1102+ ...targetMessage ,
1103+ latest_reactions : [ ...targetMessage . latest_reactions , uniqueReaction ] ,
1104+ } ;
1105+
1106+ act ( ( ) =>
1107+ dispatchReactionUpdatedEvent (
1108+ chatClient ,
1109+ uniqueReaction ,
1110+ messageWithNewReaction ,
1111+ targetChannel . channel ,
1112+ ) ,
1113+ ) ;
1114+
1115+ await waitFor ( async ( ) => {
1116+ const reactionsRows = await BetterSqlite . selectFromTable ( 'reactions' ) ;
1117+ const matchingReactionsRows = reactionsRows . filter (
1118+ ( r ) =>
1119+ r . type === uniqueReaction . type &&
1120+ r . userId === reactionMember . user . id &&
1121+ r . messageId === messageWithNewReaction . id ,
1122+ ) ;
1123+
1124+ expect ( matchingReactionsRows . length ) . toBe ( 1 ) ;
1125+ } ) ;
1126+ } ) ;
1127+
8801128 it ( 'should add a member to DB when a new member is added to channel' , async ( ) => {
8811129 useMockedApis ( chatClient , [ queryChannelsApi ( channels ) ] ) ;
8821130 renderComponent ( ) ;
0 commit comments