@@ -41,6 +41,8 @@ void main() {
41
41
42
42
Future <GlobalKey <ComposeBoxController >> prepareComposeBox (WidgetTester tester, {
43
43
required Narrow narrow,
44
+ User ? selfUser,
45
+ int ? realmWaitingPeriodThreshold,
44
46
List <User > users = const [],
45
47
List <ZulipStream > streams = const [],
46
48
}) async {
@@ -49,16 +51,19 @@ void main() {
49
51
'Add a channel with "streamId" the same as of $narrow .streamId to the store.' );
50
52
}
51
53
addTearDown (testBinding.reset);
52
- await testBinding.globalStore.add (eg.selfAccount, eg.initialSnapshot ());
54
+ selfUser ?? = eg.selfUser;
55
+ final selfAccount = eg.account (user: selfUser);
56
+ await testBinding.globalStore.add (selfAccount, eg.initialSnapshot (
57
+ realmWaitingPeriodThreshold: realmWaitingPeriodThreshold));
53
58
54
- store = await testBinding.globalStore.perAccount (eg. selfAccount.id);
59
+ store = await testBinding.globalStore.perAccount (selfAccount.id);
55
60
56
- await store.addUsers ([eg. selfUser, ...users]);
61
+ await store.addUsers ([selfUser, ...users]);
57
62
await store.addStreams (streams);
58
63
connection = store.connection as FakeApiConnection ;
59
64
60
65
final controllerKey = GlobalKey <ComposeBoxController >();
61
- await tester.pumpWidget (TestZulipApp (accountId: eg. selfAccount.id,
66
+ await tester.pumpWidget (TestZulipApp (accountId: selfAccount.id,
62
67
child: Column (
63
68
// This positions the compose box at the bottom of the screen,
64
69
// simulating the layout of the message list page.
@@ -303,17 +308,20 @@ void main() {
303
308
304
309
Future <void > prepareComposeBoxWithNavigation (WidgetTester tester) async {
305
310
addTearDown (testBinding.reset);
306
- await testBinding.globalStore.add (eg.selfAccount, eg.initialSnapshot ());
311
+ final selfUser = eg.selfUser;
312
+ final selfAccount = eg.account (user: selfUser);
313
+ await testBinding.globalStore.add (selfAccount, eg.initialSnapshot ());
307
314
308
- store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
315
+ store = await testBinding.globalStore.perAccount (selfAccount.id);
316
+ await store.addUser (selfUser);
309
317
await store.addStream (channel);
310
318
connection = store.connection as FakeApiConnection ;
311
319
312
320
await tester.pumpWidget (const ZulipApp ());
313
321
await tester.pump ();
314
322
final navigator = await ZulipApp .navigator;
315
323
unawaited (navigator.push (MaterialAccountWidgetRoute (
316
- accountId: eg. selfAccount.id, page: ComposeBox (narrow: narrow))));
324
+ accountId: selfAccount.id, page: ComposeBox (narrow: narrow))));
317
325
await tester.pumpAndSettle ();
318
326
}
319
327
@@ -581,7 +589,9 @@ void main() {
581
589
});
582
590
583
591
group ('error banner' , () {
584
- Finder contentFieldFinder () => find.descendant (
592
+ final zulipLocalizations = GlobalLocalizations .zulipLocalizations;
593
+
594
+ Finder inputFieldFinder () => find.descendant (
585
595
of: find.byType (ComposeBox ),
586
596
matching: find.byType (TextField ));
587
597
@@ -590,24 +600,26 @@ void main() {
590
600
matching: find.widgetWithIcon (IconButton , icon));
591
601
592
602
void checkComposeBoxParts ({required bool areShown}) {
593
- check (contentFieldFinder ().evaluate ().length).equals (areShown ? 1 : 0 );
603
+ final inputFieldCount = inputFieldFinder ().evaluate ().length;
604
+ areShown ? check (inputFieldCount).isGreaterThan (0 ) : check (inputFieldCount).equals (0 );
594
605
check (attachButtonFinder (Icons .attach_file).evaluate ().length).equals (areShown ? 1 : 0 );
595
606
check (attachButtonFinder (Icons .image).evaluate ().length).equals (areShown ? 1 : 0 );
596
607
check (attachButtonFinder (Icons .camera_alt).evaluate ().length).equals (areShown ? 1 : 0 );
597
608
}
598
609
599
- void checkBanner ({required bool isShown}) {
600
- final bannerTextFinder = find.text (GlobalLocalizations .zulipLocalizations
601
- .errorBannerDeactivatedDmLabel);
602
- check (bannerTextFinder.evaluate ().length).equals (isShown ? 1 : 0 );
610
+ void checkBannerWithLabel (String label, {required bool isShown}) {
611
+ check (find.text (label).evaluate ().length).equals (isShown ? 1 : 0 );
603
612
}
604
613
605
- void checkComposeBox ( {required bool isShown }) {
614
+ void checkComposeBoxIsShown ( bool isShown, {required String bannerLabel }) {
606
615
checkComposeBoxParts (areShown: isShown);
607
- checkBanner ( isShown: ! isShown);
616
+ checkBannerWithLabel (bannerLabel, isShown: ! isShown);
608
617
}
609
618
610
619
group ('in DMs with deactivated users' , () {
620
+ void checkComposeBox ({required bool isShown}) => checkComposeBoxIsShown (isShown,
621
+ bannerLabel: zulipLocalizations.errorBannerDeactivatedDmLabel);
622
+
611
623
Future <void > changeUserStatus (WidgetTester tester,
612
624
{required User user, required bool isActive}) async {
613
625
await store.handleEvent (RealmUserUpdateEvent (id: 1 ,
@@ -686,5 +698,103 @@ void main() {
686
698
});
687
699
});
688
700
});
701
+
702
+ group ('in channel/topic narrow according to channel post policy' , () {
703
+ void checkComposeBox ({required bool isShown}) => checkComposeBoxIsShown (isShown,
704
+ bannerLabel: zulipLocalizations.errorBannerCannotPostInChannelLabel);
705
+
706
+ final narrowTestCases = [
707
+ ('channel' , const ChannelNarrow (1 )),
708
+ ('topic' , const TopicNarrow (1 , 'topic' )),
709
+ ];
710
+
711
+ for (final (String narrowType, Narrow narrow) in narrowTestCases) {
712
+ testWidgets ('compose box is shown in $narrowType narrow' , (tester) async {
713
+ await prepareComposeBox (tester,
714
+ narrow: narrow,
715
+ selfUser: eg.user (role: UserRole .administrator),
716
+ streams: [eg.stream (streamId: 1 ,
717
+ channelPostPolicy: ChannelPostPolicy .moderators)]);
718
+ checkComposeBox (isShown: true );
719
+ });
720
+
721
+ testWidgets ('error banner is shown in $narrowType narrow' , (tester) async {
722
+ await prepareComposeBox (tester,
723
+ narrow: narrow,
724
+ selfUser: eg.user (role: UserRole .moderator),
725
+ streams: [eg.stream (streamId: 1 ,
726
+ channelPostPolicy: ChannelPostPolicy .administrators)]);
727
+ checkComposeBox (isShown: false );
728
+ });
729
+ }
730
+
731
+ Future <void > changeUserRole (WidgetTester tester, {
732
+ required User user,
733
+ required UserRole role,
734
+ }) async {
735
+ await store.handleEvent (RealmUserUpdateEvent (id: 1 ,
736
+ userId: user.userId, role: role));
737
+ await tester.pump ();
738
+ }
739
+
740
+ Future <void > changeChannelPolicy (WidgetTester tester, {
741
+ required ZulipStream channel,
742
+ required ChannelPostPolicy policy,
743
+ }) async {
744
+ await store.handleEvent (eg.channelUpdateEvent (channel,
745
+ property: ChannelPropertyName .channelPostPolicy, value: policy));
746
+ await tester.pump ();
747
+ }
748
+
749
+ testWidgets ('user role decreases -> compose box is replaced with the banner' , (tester) async {
750
+ final selfUser = eg.user (role: UserRole .administrator);
751
+ await prepareComposeBox (tester,
752
+ narrow: const ChannelNarrow (1 ),
753
+ selfUser: selfUser,
754
+ streams: [eg.stream (streamId: 1 , channelPostPolicy: ChannelPostPolicy .administrators)]);
755
+ checkComposeBox (isShown: true );
756
+
757
+ await changeUserRole (tester, user: selfUser, role: UserRole .moderator);
758
+ checkComposeBox (isShown: false );
759
+ });
760
+
761
+ testWidgets ('user role increases -> banner is replaced with the compose box' , (tester) async {
762
+ final selfUser = eg.user (role: UserRole .guest);
763
+ await prepareComposeBox (tester,
764
+ narrow: const ChannelNarrow (1 ),
765
+ selfUser: selfUser,
766
+ streams: [eg.stream (streamId: 1 , channelPostPolicy: ChannelPostPolicy .moderators)]);
767
+ checkComposeBox (isShown: false );
768
+
769
+ await changeUserRole (tester, user: selfUser, role: UserRole .administrator);
770
+ checkComposeBox (isShown: true );
771
+ });
772
+
773
+ testWidgets ('channel policy becomes stricter -> compose box is replaced with the banner' , (tester) async {
774
+ final selfUser = eg.user (role: UserRole .guest);
775
+ final channel = eg.stream (streamId: 1 , channelPostPolicy: ChannelPostPolicy .any);
776
+ await prepareComposeBox (tester,
777
+ narrow: const ChannelNarrow (1 ),
778
+ selfUser: selfUser,
779
+ streams: [channel]);
780
+ checkComposeBox (isShown: true );
781
+
782
+ await changeChannelPolicy (tester, channel: channel, policy: ChannelPostPolicy .fullMembers);
783
+ checkComposeBox (isShown: false );
784
+ });
785
+
786
+ testWidgets ('channel policy becomes less strict -> banner is replaced with the compose box' , (tester) async {
787
+ final selfUser = eg.user (role: UserRole .moderator);
788
+ final channel = eg.stream (streamId: 1 , channelPostPolicy: ChannelPostPolicy .administrators);
789
+ await prepareComposeBox (tester,
790
+ narrow: const ChannelNarrow (1 ),
791
+ selfUser: selfUser,
792
+ streams: [channel]);
793
+ checkComposeBox (isShown: false );
794
+
795
+ await changeChannelPolicy (tester, channel: channel, policy: ChannelPostPolicy .moderators);
796
+ checkComposeBox (isShown: true );
797
+ });
798
+ });
689
799
});
690
800
}
0 commit comments