@@ -1252,4 +1252,142 @@ void main() {
12521252        ..status.equals (AnimationStatus .dismissed);
12531253    });
12541254  });
1255+ 
1256+   group ('double-tap gesture' , () {
1257+     Future <void > setupMessageWithReactions (WidgetTester  tester, {
1258+       required  StreamMessage  message,
1259+       required  Narrow  narrow,
1260+       List <Reaction >?  reactions,
1261+     }) async  {
1262+       addTearDown (testBinding.reset); // reset the test binding 
1263+       assert (narrow.containsMessage (message)); // check that the narrow contains the message 
1264+ 
1265+       await  testBinding.globalStore.add (eg.selfAccount, eg.initialSnapshot ()); // add the self account 
1266+       store =  await  testBinding.globalStore.perAccount (eg.selfAccount.id); // get the per account store 
1267+       await  store.addUsers ([
1268+         eg.selfUser,
1269+         eg.user (userId:  message.senderId),
1270+       ]); // add the self user and the message sender 
1271+       final  stream =  eg.stream (streamId:  message.streamId); // create the stream 
1272+       await  store.addStream (stream); // add the stream 
1273+       await  store.addSubscription (eg.subscription (stream)); // add the subscription 
1274+ 
1275+       connection =  store.connection as  FakeApiConnection ; // get the fake api connection 
1276+       connection.prepare (json:  eg.newestGetMessagesResult (
1277+         foundOldest:  true , messages:  [message]).toJson ()); // prepare the response for the message 
1278+       await  tester.pumpWidget (TestZulipApp (accountId:  eg.selfAccount.id,
1279+         child:  MessageListPage (initNarrow:  narrow)),
1280+         ); // pump the widget 
1281+ 
1282+       await  tester.pumpAndSettle ();
1283+     }
1284+ 
1285+     testWidgets ('add thumbs up reaction on double-tap' , (tester) async  {
1286+       final  message =  eg.streamMessage (); // create a message without any reactions 
1287+       await  setupMessageWithReactions (tester,
1288+         message:  message,
1289+         narrow:  TopicNarrow .ofMessage (message)); // setup the message and narrow 
1290+ 
1291+       connection.prepare (json:  {}); // prepare the response for the reaction 
1292+       await  tester.pump (); // pump the widget to make the reaction visible 
1293+ 
1294+       final  messageContent =  find.byType (MessageContent ); // find the message content 
1295+       await  tester.tap (messageContent); // first tap 
1296+       await  tester.pump (const  Duration (milliseconds:  50 )); // wait for some time so that the double-tap is detected 
1297+       await  tester.tap (messageContent); // second tap 
1298+       await  tester.pumpAndSettle (); // wait for the reaction to be added 
1299+ 
1300+       check (connection.lastRequest).isA< http.Request > ()
1301+         ..method.equals ('POST' )
1302+         ..url.path.equals ('/api/v1/messages/${message .id }/reactions' )
1303+         ..bodyFields.deepEquals ({
1304+             'reaction_type' :  'unicode_emoji' ,
1305+             'emoji_code' :  '1f44d' ,  // thumbs up emoji code 
1306+             'emoji_name' :  '+1' ,
1307+           }); // check the last request 
1308+     });
1309+ 
1310+     testWidgets ('remove thumbs up reaction on double-tap when already reacted' , (tester) async  {
1311+       final  message =  eg.streamMessage (reactions:  [
1312+         Reaction (
1313+           emojiName:  '+1' ,
1314+           emojiCode:  '1f44d' ,
1315+           reactionType:  ReactionType .unicodeEmoji,
1316+           userId:  eg.selfAccount.userId)
1317+       ]); // create a message with a thumbs up reaction 
1318+       await  setupMessageWithReactions (tester,
1319+         message:  message,
1320+         narrow:  TopicNarrow .ofMessage (message)); // setup the message and narrow 
1321+ 
1322+       connection.prepare (json:  {}); // prepare the response for the reaction 
1323+       await  tester.pump (); // pump the widget to make the reaction visible 
1324+ 
1325+       final  messageContent =  find.byType (MessageContent ); // find the message content 
1326+       await  tester.tap (messageContent); // first tap 
1327+       await  tester.pump (const  Duration (milliseconds:  50 )); // wait for some time so that the double-tap is detected 
1328+       await  tester.tap (messageContent); // second tap 
1329+       await  tester.pumpAndSettle (); // wait for the reaction to be removed 
1330+ 
1331+       check (connection.lastRequest).isA< http.Request > ()
1332+         ..method.equals ('DELETE' )
1333+         ..url.path.equals ('/api/v1/messages/${message .id }/reactions' )
1334+         ..bodyFields.deepEquals ({
1335+             'reaction_type' :  'unicode_emoji' ,
1336+             'emoji_code' :  '1f44d' ,
1337+             'emoji_name' :  '+1' ,
1338+           }); // check the last request 
1339+     });
1340+ 
1341+     testWidgets ('shows error dialog when adding reaction fails' , (tester) async  {
1342+       final  message =  eg.streamMessage ();
1343+       await  setupMessageWithReactions (tester,
1344+         message:  message,
1345+         narrow:  TopicNarrow .ofMessage (message)); // setup the message and narrow 
1346+ 
1347+       connection.prepare (httpStatus:  400 , json:  {
1348+         'code' :  'BAD_REQUEST' ,
1349+         'msg' :  'Invalid message(s)' ,
1350+         'result' :  'error' ,
1351+       });
1352+ 
1353+       final  messageContent =  find.byType (MessageContent );
1354+       await  tester.tap (messageContent); // first tap 
1355+       await  tester.pump (const  Duration (milliseconds:  50 ));  // wait for some time so that the double-tap is detected 
1356+       await  tester.tap (messageContent); // second tap 
1357+       await  tester.pumpAndSettle (); // wait for the error dialog to show 
1358+ 
1359+       checkErrorDialog (tester,
1360+         expectedTitle:  'Adding reaction failed' ,
1361+         expectedMessage:  'Invalid message(s)' ); // check the error dialog 
1362+     });
1363+ 
1364+     testWidgets ('shows error dialog when removing reaction fails' , (tester) async  {
1365+       final  message =  eg.streamMessage (reactions:  [
1366+         Reaction (
1367+           emojiName:  '+1' ,
1368+           emojiCode:  '1f44d' ,
1369+           reactionType:  ReactionType .unicodeEmoji,
1370+           userId:  eg.selfAccount.userId)
1371+       ]); // create a message with a thumbs up reaction 
1372+       await  setupMessageWithReactions (tester,
1373+         message:  message,
1374+         narrow:  TopicNarrow .ofMessage (message)); // setup the message and narrow 
1375+ 
1376+       connection.prepare (httpStatus:  400 , json:  {
1377+         'code' :  'BAD_REQUEST' ,
1378+         'msg' :  'Invalid message(s)' ,
1379+         'result' :  'error' ,
1380+       }); // prepare the response for the reaction 
1381+ 
1382+       final  messageContent =  find.byType (MessageContent ); // find the message content 
1383+       await  tester.tap (messageContent); // first tap 
1384+       await  tester.pump (const  Duration (milliseconds:  50 ));  // wait for some time so that the double-tap is detected 
1385+       await  tester.tap (messageContent); // second tap 
1386+       await  tester.pumpAndSettle (); // wait for the error dialog to show 
1387+ 
1388+       checkErrorDialog (tester,
1389+         expectedTitle:  'Removing reaction failed' ,
1390+         expectedMessage:  'Invalid message(s)' ); // check the error dialog 
1391+     });
1392+   });
12551393}
0 commit comments