@@ -395,8 +395,10 @@ void main() {
395
395
});
396
396
});
397
397
398
- group ('compose box in DMs with deactivated users' , () {
399
- Finder contentFieldFinder () => find.descendant (
398
+ group ('compose box replacing with error banner' , () {
399
+ final zulipLocalizations = GlobalLocalizations .zulipLocalizations;
400
+
401
+ Finder inputFieldFinder () => find.descendant (
400
402
of: find.byType (ComposeBox ),
401
403
matching: find.byType (TextField ));
402
404
@@ -405,97 +407,249 @@ void main() {
405
407
matching: find.widgetWithIcon (IconButton , icon));
406
408
407
409
void checkComposeBoxParts ({required bool areShown}) {
408
- check (contentFieldFinder ().evaluate ().length).equals (areShown ? 1 : 0 );
410
+ final inputFieldCount = inputFieldFinder ().evaluate ().length;
411
+ areShown ? check (inputFieldCount).isGreaterThan (0 ) : check (inputFieldCount).equals (0 );
409
412
check (attachButtonFinder (Icons .attach_file).evaluate ().length).equals (areShown ? 1 : 0 );
410
413
check (attachButtonFinder (Icons .image).evaluate ().length).equals (areShown ? 1 : 0 );
411
414
check (attachButtonFinder (Icons .camera_alt).evaluate ().length).equals (areShown ? 1 : 0 );
412
415
}
413
416
414
- void checkBanner ({required bool isShown}) {
415
- final bannerTextFinder = find.text (GlobalLocalizations .zulipLocalizations
416
- .errorBannerDeactivatedDmLabel);
417
- check (bannerTextFinder.evaluate ().length).equals (isShown ? 1 : 0 );
417
+ void checkBannerWithLabel (String label, {required bool isShown}) {
418
+ check (find.text (label).evaluate ().length).equals (isShown ? 1 : 0 );
418
419
}
419
420
420
- void checkComposeBox ( {required bool isShown }) {
421
+ void checkComposeBoxIsShown ( bool isShown, {required String bannerLabel }) {
421
422
checkComposeBoxParts (areShown: isShown);
422
- checkBanner ( isShown: ! isShown);
423
+ checkBannerWithLabel (bannerLabel, isShown: ! isShown);
423
424
}
424
425
425
- Future <void > changeUserStatus (WidgetTester tester,
426
- {required User user, required bool isActive}) async {
427
- await store.handleEvent (RealmUserUpdateEvent (id: 1 ,
428
- userId: user.userId, isActive: isActive));
429
- await tester.pump ();
430
- }
426
+ group ('in DMs with deactivated users' , () {
427
+ void checkComposeBox ({required bool isShown}) => checkComposeBoxIsShown (isShown,
428
+ bannerLabel: zulipLocalizations.errorBannerDeactivatedDmLabel);
431
429
432
- DmNarrow dmNarrowWith (User otherUser) => DmNarrow .withUser (otherUser.userId,
433
- selfUserId: eg.selfUser.userId);
430
+ Future <void > changeUserStatus (WidgetTester tester,
431
+ {required User user, required bool isActive}) async {
432
+ await store.handleEvent (RealmUserUpdateEvent (id: 1 ,
433
+ userId: user.userId, isActive: isActive));
434
+ await tester.pump ();
435
+ }
434
436
435
- DmNarrow groupDmNarrowWith ( List < User > otherUsers ) => DmNarrow .withOtherUsers (
436
- otherUsers. map ((u) => u.userId), selfUserId: eg.selfUser.userId);
437
+ DmNarrow dmNarrowWith ( User otherUser ) => DmNarrow .withUser (otherUser.userId,
438
+ selfUserId: eg.selfUser.userId);
437
439
438
- group ('1:1 DMs' , () {
439
- testWidgets ('compose box replaced with a banner' , (tester) async {
440
- final deactivatedUser = eg.user (isActive: false );
441
- await prepareComposeBox (tester, narrow: dmNarrowWith (deactivatedUser),
442
- users: [deactivatedUser]);
443
- checkComposeBox (isShown: false );
444
- });
440
+ DmNarrow groupDmNarrowWith (List <User > otherUsers) => DmNarrow .withOtherUsers (
441
+ otherUsers.map ((u) => u.userId), selfUserId: eg.selfUser.userId);
445
442
446
- testWidgets ('active user becomes deactivated -> '
447
- 'compose box is replaced with a banner' , (tester) async {
448
- final activeUser = eg.user (isActive: true );
449
- await prepareComposeBox (tester, narrow: dmNarrowWith (activeUser),
450
- users: [activeUser]);
451
- checkComposeBox (isShown: true );
443
+ group ('1:1 DMs' , () {
444
+ testWidgets ('compose box replaced with a banner' , (tester) async {
445
+ final deactivatedUser = eg.user (isActive: false );
446
+ await prepareComposeBox (tester, narrow: dmNarrowWith (deactivatedUser),
447
+ users: [deactivatedUser]);
448
+ checkComposeBox (isShown: false );
449
+ });
452
450
453
- await changeUserStatus (tester, user: activeUser, isActive: false );
454
- checkComposeBox (isShown: false );
451
+ testWidgets ('active user becomes deactivated -> '
452
+ 'compose box is replaced with a banner' , (tester) async {
453
+ final activeUser = eg.user (isActive: true );
454
+ await prepareComposeBox (tester, narrow: dmNarrowWith (activeUser),
455
+ users: [activeUser]);
456
+ checkComposeBox (isShown: true );
457
+
458
+ await changeUserStatus (tester, user: activeUser, isActive: false );
459
+ checkComposeBox (isShown: false );
460
+ });
461
+
462
+ testWidgets ('deactivated user becomes active -> '
463
+ 'banner is replaced with the compose box' , (tester) async {
464
+ final deactivatedUser = eg.user (isActive: false );
465
+ await prepareComposeBox (tester, narrow: dmNarrowWith (deactivatedUser),
466
+ users: [deactivatedUser]);
467
+ checkComposeBox (isShown: false );
468
+
469
+ await changeUserStatus (tester, user: deactivatedUser, isActive: true );
470
+ checkComposeBox (isShown: true );
471
+ });
455
472
});
456
473
457
- testWidgets ('deactivated user becomes active -> '
458
- 'banner is replaced with the compose box' , (tester) async {
459
- final deactivatedUser = eg.user (isActive: false );
460
- await prepareComposeBox (tester, narrow: dmNarrowWith (deactivatedUser),
461
- users: [deactivatedUser]);
462
- checkComposeBox (isShown: false );
474
+ group ('group DMs' , () {
475
+ testWidgets ('compose box replaced with a banner' , (tester) async {
476
+ final deactivatedUsers = [eg.user (isActive: false ), eg.user (isActive: false )];
477
+ await prepareComposeBox (tester, narrow: groupDmNarrowWith (deactivatedUsers),
478
+ users: deactivatedUsers);
479
+ checkComposeBox (isShown: false );
480
+ });
463
481
464
- await changeUserStatus (tester, user: deactivatedUser, isActive: true );
465
- checkComposeBox (isShown: true );
482
+ testWidgets ('at least one user becomes deactivated -> '
483
+ 'compose box is replaced with a banner' , (tester) async {
484
+ final activeUsers = [eg.user (isActive: true ), eg.user (isActive: true )];
485
+ await prepareComposeBox (tester, narrow: groupDmNarrowWith (activeUsers),
486
+ users: activeUsers);
487
+ checkComposeBox (isShown: true );
488
+
489
+ await changeUserStatus (tester, user: activeUsers[0 ], isActive: false );
490
+ checkComposeBox (isShown: false );
491
+ });
492
+
493
+ testWidgets ('all deactivated users become active -> '
494
+ 'banner is replaced with the compose box' , (tester) async {
495
+ final deactivatedUsers = [eg.user (isActive: false ), eg.user (isActive: false )];
496
+ await prepareComposeBox (tester, narrow: groupDmNarrowWith (deactivatedUsers),
497
+ users: deactivatedUsers);
498
+ checkComposeBox (isShown: false );
499
+
500
+ await changeUserStatus (tester, user: deactivatedUsers[0 ], isActive: true );
501
+ checkComposeBox (isShown: false );
502
+
503
+ await changeUserStatus (tester, user: deactivatedUsers[1 ], isActive: true );
504
+ checkComposeBox (isShown: true );
505
+ });
466
506
});
467
507
});
468
508
469
- group ('group DMs' , () {
470
- testWidgets ('compose box replaced with a banner' , (tester) async {
471
- final deactivatedUsers = [eg.user (isActive: false ), eg.user (isActive: false )];
472
- await prepareComposeBox (tester, narrow: groupDmNarrowWith (deactivatedUsers),
473
- users: deactivatedUsers);
474
- checkComposeBox (isShown: false );
509
+ group ('in topic/channel narrow according to channel post policy' , () {
510
+ void checkComposeBox ({required bool isShown}) => checkComposeBoxIsShown (isShown,
511
+ bannerLabel: zulipLocalizations.errorBannerCannotPostInChannelLabel);
512
+
513
+ final testCases = [
514
+ (ChannelPostPolicy .unknown, UserRole .unknown, true ),
515
+ (ChannelPostPolicy .unknown, UserRole .guest, true ),
516
+ (ChannelPostPolicy .unknown, UserRole .member, true ),
517
+ (ChannelPostPolicy .unknown, UserRole .moderator, true ),
518
+ (ChannelPostPolicy .unknown, UserRole .administrator, true ),
519
+ (ChannelPostPolicy .unknown, UserRole .owner, true ),
520
+ (ChannelPostPolicy .any, UserRole .unknown, true ),
521
+ (ChannelPostPolicy .any, UserRole .guest, true ),
522
+ (ChannelPostPolicy .any, UserRole .member, true ),
523
+ (ChannelPostPolicy .any, UserRole .moderator, true ),
524
+ (ChannelPostPolicy .any, UserRole .administrator, true ),
525
+ (ChannelPostPolicy .any, UserRole .owner, true ),
526
+ (ChannelPostPolicy .fullMembers, UserRole .unknown, true ),
527
+ (ChannelPostPolicy .fullMembers, UserRole .guest, false ),
528
+ (ChannelPostPolicy .fullMembers, UserRole .member, true ),
529
+ (ChannelPostPolicy .fullMembers, UserRole .moderator, true ),
530
+ (ChannelPostPolicy .fullMembers, UserRole .administrator, true ),
531
+ (ChannelPostPolicy .fullMembers, UserRole .owner, true ),
532
+ (ChannelPostPolicy .moderators, UserRole .unknown, true ),
533
+ (ChannelPostPolicy .moderators, UserRole .guest, false ),
534
+ (ChannelPostPolicy .moderators, UserRole .member, false ),
535
+ (ChannelPostPolicy .moderators, UserRole .moderator, true ),
536
+ (ChannelPostPolicy .moderators, UserRole .administrator, true ),
537
+ (ChannelPostPolicy .moderators, UserRole .owner, true ),
538
+ (ChannelPostPolicy .administrators, UserRole .unknown, true ),
539
+ (ChannelPostPolicy .administrators, UserRole .guest, false ),
540
+ (ChannelPostPolicy .administrators, UserRole .member, false ),
541
+ (ChannelPostPolicy .administrators, UserRole .moderator, false ),
542
+ (ChannelPostPolicy .administrators, UserRole .administrator, true ),
543
+ (ChannelPostPolicy .administrators, UserRole .owner, true ),
544
+ ];
545
+
546
+ for (final testCase in testCases) {
547
+ final (ChannelPostPolicy policy, UserRole role, bool canPost) = testCase;
548
+
549
+ testWidgets ('"${role .name }" user ${canPost ? 'can' : "can't" } post in channel with "${policy .name }" policy' , (tester) async {
550
+ final selfUser = eg.user (role: role);
551
+ await prepareComposeBox (tester,
552
+ narrow: const ChannelNarrow (1 ),
553
+ selfUser: selfUser,
554
+ streams: [eg.stream (streamId: 1 , channelPostPolicy: policy)]);
555
+ checkComposeBox (isShown: canPost);
556
+ });
557
+
558
+ testWidgets ('"${role .name }" user ${canPost ? 'can' : "can't" } post in topic with "${policy .name }" channel policy' , (tester) async {
559
+ final selfUser = eg.user (role: role);
560
+ await prepareComposeBox (tester,
561
+ narrow: const TopicNarrow (1 , 'topic' ),
562
+ selfUser: selfUser,
563
+ streams: [eg.stream (streamId: 1 , channelPostPolicy: policy)]);
564
+ checkComposeBox (isShown: canPost);
565
+ });
566
+ }
567
+
568
+ group ('only "full member" user can post in channel with "fullMembers" policy' , () {
569
+ testWidgets ('"full member" -> can post in channel' , (tester) async {
570
+ final selfUser = eg.user (role: UserRole .member,
571
+ dateJoined: DateTime .now ().subtract (const Duration (days: 30 )).toIso8601String ());
572
+ await prepareComposeBox (tester,
573
+ narrow: const ChannelNarrow (1 ),
574
+ selfUser: selfUser,
575
+ realmWaitingPeriodThreshold: 30 ,
576
+ streams: [eg.stream (streamId: 1 , channelPostPolicy: ChannelPostPolicy .fullMembers)]);
577
+ checkComposeBox (isShown: true );
578
+ });
579
+
580
+ testWidgets ('not a "full member" -> cannot post in channel' , (tester) async {
581
+ final selfUser = eg.user (role: UserRole .member,
582
+ dateJoined: DateTime .now ().subtract (const Duration (days: 29 )).toIso8601String ());
583
+ await prepareComposeBox (tester,
584
+ narrow: const ChannelNarrow (1 ),
585
+ selfUser: selfUser,
586
+ realmWaitingPeriodThreshold: 30 ,
587
+ streams: [eg.stream (streamId: 1 , channelPostPolicy: ChannelPostPolicy .fullMembers)]);
588
+ checkComposeBox (isShown: false );
589
+ });
475
590
});
476
591
477
- testWidgets ('at least one user becomes deactivated -> '
478
- 'compose box is replaced with a banner' , (tester) async {
479
- final activeUsers = [eg.user (isActive: true ), eg.user (isActive: true )];
480
- await prepareComposeBox (tester, narrow: groupDmNarrowWith (activeUsers),
481
- users: activeUsers);
592
+ Future <void > changeUserRole (WidgetTester tester,
593
+ {required User user, required UserRole role}) async {
594
+ await store.handleEvent (RealmUserUpdateEvent (id: 1 ,
595
+ userId: user.userId, role: role));
596
+ await tester.pump ();
597
+ }
598
+
599
+ Future <void > changeChannelPolicy (WidgetTester tester,
600
+ {required ZulipStream channel, required ChannelPostPolicy policy}) async {
601
+ await store.handleEvent (eg.channelUpdateEvent (channel,
602
+ property: ChannelPropertyName .channelPostPolicy, value: policy));
603
+ await tester.pump ();
604
+ }
605
+
606
+ testWidgets ('user role decreases -> compose box is replaced with the banner' , (tester) async {
607
+ final selfUser = eg.user (role: UserRole .administrator);
608
+ await prepareComposeBox (tester,
609
+ narrow: const ChannelNarrow (1 ),
610
+ selfUser: selfUser,
611
+ streams: [eg.stream (streamId: 1 , channelPostPolicy: ChannelPostPolicy .administrators)]);
482
612
checkComposeBox (isShown: true );
483
613
484
- await changeUserStatus (tester, user: activeUsers[ 0 ], isActive : false );
614
+ await changeUserRole (tester, user: selfUser, role : UserRole .moderator );
485
615
checkComposeBox (isShown: false );
486
616
});
487
617
488
- testWidgets ('all deactivated users become active -> '
489
- 'banner is replaced with the compose box' , (tester) async {
490
- final deactivatedUsers = [eg.user (isActive: false ), eg.user (isActive: false )];
491
- await prepareComposeBox (tester, narrow: groupDmNarrowWith (deactivatedUsers),
492
- users: deactivatedUsers);
618
+ testWidgets ('user role increases -> banner is replaced with the compose box' , (tester) async {
619
+ final selfUser = eg.user (role: UserRole .guest);
620
+ await prepareComposeBox (tester,
621
+ narrow: const ChannelNarrow (1 ),
622
+ selfUser: selfUser,
623
+ streams: [eg.stream (streamId: 1 , channelPostPolicy: ChannelPostPolicy .moderators)]);
493
624
checkComposeBox (isShown: false );
494
625
495
- await changeUserStatus (tester, user: deactivatedUsers[0 ], isActive: true );
626
+ await changeUserRole (tester, user: selfUser, role: UserRole .administrator);
627
+ checkComposeBox (isShown: true );
628
+ });
629
+
630
+ testWidgets ('channel policy becomes stricter -> compose box is replaced with the banner' , (tester) async {
631
+ final selfUser = eg.user (role: UserRole .guest);
632
+ final channel = eg.stream (streamId: 1 , channelPostPolicy: ChannelPostPolicy .any);
633
+ await prepareComposeBox (tester,
634
+ narrow: const ChannelNarrow (1 ),
635
+ selfUser: selfUser,
636
+ streams: [channel]);
637
+ checkComposeBox (isShown: true );
638
+
639
+ await changeChannelPolicy (tester, channel: channel, policy: ChannelPostPolicy .fullMembers);
640
+ checkComposeBox (isShown: false );
641
+ });
642
+
643
+ testWidgets ('channel policy becomes less strict -> banner is replaced with the compose box' , (tester) async {
644
+ final selfUser = eg.user (role: UserRole .moderator);
645
+ final channel = eg.stream (streamId: 1 , channelPostPolicy: ChannelPostPolicy .administrators);
646
+ await prepareComposeBox (tester,
647
+ narrow: const ChannelNarrow (1 ),
648
+ selfUser: selfUser,
649
+ streams: [channel]);
496
650
checkComposeBox (isShown: false );
497
651
498
- await changeUserStatus (tester, user : deactivatedUsers[ 1 ], isActive : true );
652
+ await changeChannelPolicy (tester, channel : channel, policy : ChannelPostPolicy .moderators );
499
653
checkComposeBox (isShown: true );
500
654
});
501
655
});
0 commit comments