@@ -1344,4 +1344,142 @@ void main() {
13441344        ..status.equals (AnimationStatus .dismissed);
13451345    });
13461346  });
1347+ 
1348+   group ('double-tap gesture' , () {
1349+     Future <void > setupMessageWithReactions (WidgetTester  tester, {
1350+       required  StreamMessage  message,
1351+       required  Narrow  narrow,
1352+       List <Reaction >?  reactions,
1353+     }) async  {
1354+       addTearDown (testBinding.reset); // reset the test binding 
1355+       assert (narrow.containsMessage (message)); // check that the narrow contains the message 
1356+ 
1357+       await  testBinding.globalStore.add (eg.selfAccount, eg.initialSnapshot ()); // add the self account 
1358+       store =  await  testBinding.globalStore.perAccount (eg.selfAccount.id); // get the per account store 
1359+       await  store.addUsers ([
1360+         eg.selfUser,
1361+         eg.user (userId:  message.senderId),
1362+       ]); // add the self user and the message sender 
1363+       final  stream =  eg.stream (streamId:  message.streamId); // create the stream 
1364+       await  store.addStream (stream); // add the stream 
1365+       await  store.addSubscription (eg.subscription (stream)); // add the subscription 
1366+ 
1367+       connection =  store.connection as  FakeApiConnection ; // get the fake api connection 
1368+       connection.prepare (json:  eg.newestGetMessagesResult (
1369+         foundOldest:  true , messages:  [message]).toJson ()); // prepare the response for the message 
1370+       await  tester.pumpWidget (TestZulipApp (accountId:  eg.selfAccount.id,
1371+         child:  MessageListPage (initNarrow:  narrow)),
1372+         ); // pump the widget 
1373+ 
1374+       await  tester.pumpAndSettle ();
1375+     }
1376+ 
1377+     testWidgets ('add thumbs up reaction on double-tap' , (tester) async  {
1378+       final  message =  eg.streamMessage (); // create a message without any reactions 
1379+       await  setupMessageWithReactions (tester,
1380+         message:  message,
1381+         narrow:  TopicNarrow .ofMessage (message)); // setup the message and narrow 
1382+ 
1383+       connection.prepare (json:  {}); // prepare the response for the reaction 
1384+       await  tester.pump (); // pump the widget to make the reaction visible 
1385+ 
1386+       final  messageContent =  find.byType (MessageContent ); // find the message content 
1387+       await  tester.tap (messageContent); // first tap 
1388+       await  tester.pump (const  Duration (milliseconds:  50 )); // wait for some time so that the double-tap is detected 
1389+       await  tester.tap (messageContent); // second tap 
1390+       await  tester.pumpAndSettle (); // wait for the reaction to be added 
1391+ 
1392+       check (connection.lastRequest).isA< http.Request > ()
1393+         ..method.equals ('POST' )
1394+         ..url.path.equals ('/api/v1/messages/${message .id }/reactions' )
1395+         ..bodyFields.deepEquals ({
1396+             'reaction_type' :  'unicode_emoji' ,
1397+             'emoji_code' :  '1f44d' ,  // thumbs up emoji code 
1398+             'emoji_name' :  '+1' ,
1399+           }); // check the last request 
1400+     });
1401+ 
1402+     testWidgets ('remove thumbs up reaction on double-tap when already reacted' , (tester) async  {
1403+       final  message =  eg.streamMessage (reactions:  [
1404+         Reaction (
1405+           emojiName:  '+1' ,
1406+           emojiCode:  '1f44d' ,
1407+           reactionType:  ReactionType .unicodeEmoji,
1408+           userId:  eg.selfAccount.userId)
1409+       ]); // create a message with a thumbs up reaction 
1410+       await  setupMessageWithReactions (tester,
1411+         message:  message,
1412+         narrow:  TopicNarrow .ofMessage (message)); // setup the message and narrow 
1413+ 
1414+       connection.prepare (json:  {}); // prepare the response for the reaction 
1415+       await  tester.pump (); // pump the widget to make the reaction visible 
1416+ 
1417+       final  messageContent =  find.byType (MessageContent ); // find the message content 
1418+       await  tester.tap (messageContent); // first tap 
1419+       await  tester.pump (const  Duration (milliseconds:  50 )); // wait for some time so that the double-tap is detected 
1420+       await  tester.tap (messageContent); // second tap 
1421+       await  tester.pumpAndSettle (); // wait for the reaction to be removed 
1422+ 
1423+       check (connection.lastRequest).isA< http.Request > ()
1424+         ..method.equals ('DELETE' )
1425+         ..url.path.equals ('/api/v1/messages/${message .id }/reactions' )
1426+         ..bodyFields.deepEquals ({
1427+             'reaction_type' :  'unicode_emoji' ,
1428+             'emoji_code' :  '1f44d' ,
1429+             'emoji_name' :  '+1' ,
1430+           }); // check the last request 
1431+     });
1432+ 
1433+     testWidgets ('shows error dialog when adding reaction fails' , (tester) async  {
1434+       final  message =  eg.streamMessage ();
1435+       await  setupMessageWithReactions (tester,
1436+         message:  message,
1437+         narrow:  TopicNarrow .ofMessage (message)); // setup the message and narrow 
1438+ 
1439+       connection.prepare (httpStatus:  400 , json:  {
1440+         'code' :  'BAD_REQUEST' ,
1441+         'msg' :  'Invalid message(s)' ,
1442+         'result' :  'error' ,
1443+       });
1444+ 
1445+       final  messageContent =  find.byType (MessageContent );
1446+       await  tester.tap (messageContent); // first tap 
1447+       await  tester.pump (const  Duration (milliseconds:  50 ));  // wait for some time so that the double-tap is detected 
1448+       await  tester.tap (messageContent); // second tap 
1449+       await  tester.pumpAndSettle (); // wait for the error dialog to show 
1450+ 
1451+       checkErrorDialog (tester,
1452+         expectedTitle:  'Adding reaction failed' ,
1453+         expectedMessage:  'Invalid message(s)' ); // check the error dialog 
1454+     });
1455+ 
1456+     testWidgets ('shows error dialog when removing reaction fails' , (tester) async  {
1457+       final  message =  eg.streamMessage (reactions:  [
1458+         Reaction (
1459+           emojiName:  '+1' ,
1460+           emojiCode:  '1f44d' ,
1461+           reactionType:  ReactionType .unicodeEmoji,
1462+           userId:  eg.selfAccount.userId)
1463+       ]); // create a message with a thumbs up reaction 
1464+       await  setupMessageWithReactions (tester,
1465+         message:  message,
1466+         narrow:  TopicNarrow .ofMessage (message)); // setup the message and narrow 
1467+ 
1468+       connection.prepare (httpStatus:  400 , json:  {
1469+         'code' :  'BAD_REQUEST' ,
1470+         'msg' :  'Invalid message(s)' ,
1471+         'result' :  'error' ,
1472+       }); // prepare the response for the reaction 
1473+ 
1474+       final  messageContent =  find.byType (MessageContent ); // find the message content 
1475+       await  tester.tap (messageContent); // first tap 
1476+       await  tester.pump (const  Duration (milliseconds:  50 ));  // wait for some time so that the double-tap is detected 
1477+       await  tester.tap (messageContent); // second tap 
1478+       await  tester.pumpAndSettle (); // wait for the error dialog to show 
1479+ 
1480+       checkErrorDialog (tester,
1481+         expectedTitle:  'Removing reaction failed' ,
1482+         expectedMessage:  'Invalid message(s)' ); // check the error dialog 
1483+     });
1484+   });
13471485}
0 commit comments