@@ -589,6 +589,179 @@ void main() {
589
589
});
590
590
});
591
591
592
+ group ('PerAccountStore edit-message methods' , () {
593
+ late PerAccountStore store;
594
+ late FakeApiConnection connection;
595
+ late StreamMessage message;
596
+
597
+ Future <void > prepare () async {
598
+ store = eg.store ();
599
+ connection = store.connection as FakeApiConnection ;
600
+ message = eg.streamMessage ();
601
+ await store.addMessage (message);
602
+ }
603
+
604
+ test ('smoke' , () => awaitFakeAsync ((async ) async {
605
+ await prepare ();
606
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
607
+
608
+ connection.prepare (
609
+ json: UpdateMessageResult ().toJson (), delay: Duration (seconds: 1 ));
610
+ store.editMessage (messageId: message.id, content: 'new content' );
611
+ check (connection.takeRequests ()).single.isA< http.Request > ()
612
+ ..method.equals ('PATCH' )
613
+ ..url.path.equals ('/api/v1/messages/${message .id }' )
614
+ ..bodyFields.deepEquals ({
615
+ 'content' : 'new content' ,
616
+ });
617
+
618
+ async .elapse (Duration (milliseconds: 500 ));
619
+ // Mid-request
620
+ check (store.getEditMessageErrorStatus (message.id)).isNotNull ().isFalse ();
621
+
622
+ async .elapse (Duration (milliseconds: 500 ));
623
+ // Request has succeeded; event hasn't arrived
624
+ check (store.getEditMessageErrorStatus (message.id)).isNotNull ().isFalse ();
625
+
626
+ await store.handleEvent (eg.updateMessageEditEvent (message));
627
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
628
+ }));
629
+
630
+ test ('request fails' , () => awaitFakeAsync ((async ) async {
631
+ await prepare ();
632
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
633
+
634
+ connection.prepare (apiException: eg.apiBadRequest (), delay: Duration (seconds: 1 ));
635
+ store.editMessage (messageId: message.id, content: 'new content' );
636
+ async .elapse (Duration (seconds: 1 ));
637
+ check (store.getEditMessageErrorStatus (message.id)).isNotNull ().isTrue ();
638
+ }));
639
+
640
+ test ('request fails; take failed edit' , () => awaitFakeAsync ((async ) async {
641
+ await prepare ();
642
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
643
+
644
+ connection.prepare (apiException: eg.apiBadRequest (), delay: Duration (seconds: 1 ));
645
+ store.editMessage (messageId: message.id, content: 'new content' );
646
+ async .elapse (Duration (seconds: 1 ));
647
+ check (store.getEditMessageErrorStatus (message.id)).isNotNull ().isTrue ();
648
+
649
+ check (store.takeFailedMessageEdit (message.id)).equals ('new content' );
650
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
651
+ }));
652
+
653
+ test ('takeFailedMessageEdit throws StateError when nothing to take' , () => awaitFakeAsync ((async ) async {
654
+ await prepare ();
655
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
656
+ check (() => store.takeFailedMessageEdit (message.id)).throws <StateError >();
657
+ }));
658
+
659
+ test ('request failure after event arrival' , () => awaitFakeAsync ((async ) async {
660
+ // This can happen with network issues.
661
+
662
+ await prepare ();
663
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
664
+
665
+ connection.prepare (
666
+ httpException: const SocketException ('failed' ), delay: Duration (seconds: 1 ));
667
+ store.editMessage (messageId: message.id, content: 'new content' );
668
+
669
+ async .elapse (Duration (milliseconds: 500 ));
670
+ await store.handleEvent (eg.updateMessageEditEvent (message));
671
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
672
+
673
+ async .elapse (Duration (milliseconds: 500 ));
674
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
675
+ }));
676
+
677
+ test ('request failure before event arrival' , () => awaitFakeAsync ((async ) async {
678
+ // This can happen with network issues.
679
+
680
+ await prepare ();
681
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
682
+
683
+ connection.prepare (
684
+ httpException: const SocketException ('failed' ), delay: Duration (seconds: 1 ));
685
+ store.editMessage (messageId: message.id, content: 'new content' );
686
+
687
+ async .elapse (Duration (seconds: 1 ));
688
+ check (store.getEditMessageErrorStatus (message.id)).isNotNull ().isTrue ();
689
+
690
+ await store.handleEvent (eg.updateMessageEditEvent (message));
691
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
692
+ }));
693
+
694
+ test ('request failure before event arrival; take failed edit in between' , () => awaitFakeAsync ((async ) async {
695
+ // This can happen with network issues.
696
+
697
+ await prepare ();
698
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
699
+
700
+ connection.prepare (
701
+ httpException: const SocketException ('failed' ), delay: Duration (seconds: 1 ));
702
+ store.editMessage (messageId: message.id, content: 'new content' );
703
+
704
+ async .elapse (Duration (seconds: 1 ));
705
+ check (store.getEditMessageErrorStatus (message.id)).isNotNull ().isTrue ();
706
+ check (store.takeFailedMessageEdit (message.id)).equals ('new content' );
707
+
708
+ await store.handleEvent (eg.updateMessageEditEvent (message)); // no error
709
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
710
+ }));
711
+
712
+ test ('request fails, then message deleted' , () => awaitFakeAsync ((async ) async {
713
+ await prepare ();
714
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
715
+
716
+ connection.prepare (apiException: eg.apiBadRequest (), delay: Duration (seconds: 1 ));
717
+ store.editMessage (messageId: message.id, content: 'new content' );
718
+ async .elapse (Duration (seconds: 1 ));
719
+ check (store.getEditMessageErrorStatus (message.id)).isNotNull ().isTrue ();
720
+
721
+ await store.handleEvent (eg.deleteMessageEvent ([message])); // no error
722
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
723
+ }));
724
+
725
+ test ('message deleted while request in progress; we get failure response' , () => awaitFakeAsync ((async ) async {
726
+ await prepare ();
727
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
728
+
729
+ connection.prepare (apiException: eg.apiBadRequest (), delay: Duration (seconds: 1 ));
730
+ store.editMessage (messageId: message.id, content: 'new content' );
731
+
732
+ async .elapse (Duration (milliseconds: 500 ));
733
+ // Mid-request
734
+ check (store.getEditMessageErrorStatus (message.id)).isNotNull ().isFalse ();
735
+
736
+ await store.handleEvent (eg.deleteMessageEvent ([message]));
737
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
738
+
739
+ async .elapse (Duration (milliseconds: 500 ));
740
+ // Request failure, but status has already been cleared
741
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
742
+ }));
743
+
744
+ test ('message deleted while request in progress but we get success response' , () => awaitFakeAsync ((async ) async {
745
+ await prepare ();
746
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
747
+
748
+ connection.prepare (
749
+ json: UpdateMessageResult ().toJson (), delay: Duration (seconds: 1 ));
750
+ store.editMessage (messageId: message.id, content: 'new content' );
751
+
752
+ async .elapse (Duration (milliseconds: 500 ));
753
+ // Mid-request
754
+ check (store.getEditMessageErrorStatus (message.id)).isNotNull ().isFalse ();
755
+
756
+ await store.handleEvent (eg.deleteMessageEvent ([message]));
757
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
758
+
759
+ async .elapse (Duration (milliseconds: 500 ));
760
+ // Request success
761
+ check (store.getEditMessageErrorStatus (message.id)).isNull ();
762
+ }));
763
+ });
764
+
592
765
group ('UpdateMachine.load' , () {
593
766
late TestGlobalStore globalStore;
594
767
late FakeApiConnection connection;
0 commit comments