@@ -16,6 +16,7 @@ import 'package:zulip/model/localizations.dart';
1616import  'package:zulip/model/narrow.dart' ;
1717import  'package:zulip/model/store.dart' ;
1818import  'package:zulip/widgets/content.dart' ;
19+ import  'package:zulip/widgets/emoji_reaction.dart' ;
1920import  'package:zulip/widgets/icons.dart' ;
2021import  'package:zulip/widgets/message_list.dart' ;
2122import  'package:zulip/widgets/store.dart' ;
@@ -576,6 +577,99 @@ void main() {
576577    });
577578  });
578579
580+   group ('EditStateMarker' , () {
581+     void  checkMarkersCount ({required  int  edited, required  int  moved}) {
582+       check (find.byIcon (ZulipIcons .edited).evaluate ()).length.equals (edited);
583+       check (find.byIcon (ZulipIcons .message_moved).evaluate ()).length.equals (moved);
584+     }
585+ 
586+     testWidgets ('no edited or moved messages' , (WidgetTester  tester) async  {
587+       final  message =  eg.streamMessage ();
588+       await  setupMessageListPage (tester, messages:  [message]);
589+       checkMarkersCount (edited:  0 , moved:  0 );
590+     });
591+ 
592+     testWidgets ('edited and moved messages from events' , (WidgetTester  tester) async  {
593+       final  message =  eg.streamMessage ();
594+       final  message2 =  eg.streamMessage ();
595+       await  setupMessageListPage (tester, messages:  [message, message2]);
596+       checkMarkersCount (edited:  0 , moved:  0 );
597+ 
598+       await  store.handleEvent (eg.updateMessageEditEvent (message, renderedContent:  'edited' ));
599+       await  tester.pump ();
600+       checkMarkersCount (edited:  1 , moved:  0 );
601+ 
602+       await  store.handleEvent (eg.updateMessageMoveEvent (
603+         [message, message2], origTopic:  'old' , newTopic:  'new' ));
604+       await  tester.pump ();
605+       checkMarkersCount (edited:  1 , moved:  1 );
606+ 
607+       await  store.handleEvent (eg.updateMessageEditEvent (message2, renderedContent:  'edited' ));
608+       await  tester.pump ();
609+       checkMarkersCount (edited:  2 , moved:  0 );
610+     });
611+ 
612+     List <List <(String , Rect )>> captureMessageRects (
613+       WidgetTester  tester,
614+       List <Message > messages,
615+       Message  targetMessage,
616+     ) {
617+       assert (messages.contains (targetMessage));
618+       final  List <List <(String , Rect )>> result =  [];
619+       for  (final  message in  messages) {
620+         final  baseFinder =  find.byWidgetPredicate (
621+           (widget) =>  widget is  MessageWithPossibleSender 
622+             &&  widget.item.message.id ==  message.id);
623+ 
624+         Rect  getRectMatching (Finder  matching) {
625+           final  finder =  find.descendant (
626+             of:  baseFinder, matching:  matching)..tryEvaluate ();
627+           check (finder.found, because:  '${message .content }: $matching ' )
628+             .length.equals (1 );
629+           return  tester.getRect (finder.first);
630+         }
631+ 
632+         result.add ([
633+           ('MessageWithPossibleSender' , tester.getRect (baseFinder)),
634+           ('MessageContent' , getRectMatching (find.byType (MessageContent ))),
635+           ('Paragraph' , getRectMatching (find.byType (Paragraph ))),
636+           if  (message.id ==  targetMessage.id) ...[
637+             ('Star' , getRectMatching (find.byIcon (ZulipIcons .star_filled))),
638+             ('ReactionChipsList' , getRectMatching (find.byType (ReactionChipsList ))),
639+           ],
640+         ]);
641+       }
642+       return  result;
643+     }
644+ 
645+     testWidgets ('edit state updates do not affect layout' , (WidgetTester  tester) async  {
646+       final  messages =  [
647+         eg.streamMessage (),
648+         eg.streamMessage (
649+           reactions:  [eg.unicodeEmojiReaction, eg.realmEmojiReaction],
650+           flags:  [MessageFlag .starred]),
651+         eg.streamMessage (),
652+       ];
653+       final  StreamMessage  messageWithMarker =  messages[1 ];
654+       await  setupMessageListPage (tester, messages:  messages);
655+       final  rectsBefore =  captureMessageRects (tester, messages, messageWithMarker);
656+       checkMarkersCount (edited:  0 , moved:  0 );
657+ 
658+       await  store.handleEvent (eg.updateMessageMoveEvent (
659+         [messageWithMarker], origTopic:  'old' , newTopic:  messageWithMarker.topic));
660+       await  tester.pump ();
661+       check (captureMessageRects (tester, messages, messageWithMarker))
662+         .deepEquals (rectsBefore);
663+       checkMarkersCount (edited:  0 , moved:  1 );
664+ 
665+       await  store.handleEvent (eg.updateMessageEditEvent (messageWithMarker));
666+       await  tester.pump ();
667+       check (captureMessageRects (tester, messages, messageWithMarker))
668+         .deepEquals (rectsBefore);
669+       checkMarkersCount (edited:  1 , moved:  0 );
670+     });
671+   });
672+ 
579673  group ('_UnreadMarker animations' , () {
580674    // TODO: Improve animation state testing so it is less tied to 
581675    //   implementation details and more focused on output, see: 
0 commit comments