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