@@ -5,6 +5,7 @@ import 'package:checks/checks.dart';
5
5
import 'package:fake_async/fake_async.dart' ;
6
6
import 'package:flutter/cupertino.dart' ;
7
7
import 'package:test/scaffolding.dart' ;
8
+ import 'package:zulip/api/model/initial_snapshot.dart' ;
8
9
import 'package:zulip/api/model/model.dart' ;
9
10
import 'package:zulip/model/autocomplete.dart' ;
10
11
import 'package:zulip/model/narrow.dart' ;
@@ -277,12 +278,12 @@ void main() {
277
278
278
279
group ('MentionAutocompleteView recomputes results and does it only one time' , () {
279
280
Future <void > doCheck ({
281
+ Narrow narrow = const CombinedFeedNarrow (),
280
282
required List <User > users,
281
283
required String rawQuery,
282
284
required Future <void > Function (PerAccountStore store) act,
283
285
required void Function (Iterable <MentionAutocompleteResult >) expect,
284
286
}) async {
285
- const narrow = CombinedFeedNarrow ();
286
287
final store = eg.store ();
287
288
await store.addUsers (users);
288
289
final view = MentionAutocompleteView .init (store: store, narrow: narrow);
@@ -382,6 +383,28 @@ void main() {
382
383
expect: expect,
383
384
);
384
385
});
386
+
387
+ test ('MessageEvent' , () async {
388
+ final users = generateUsers (count: 1500 );
389
+
390
+ Future <void > act (PerAccountStore store) async {
391
+ await store.addMessage (eg.dmMessage (from: eg.selfUser, to: [users[100 ]]));
392
+ }
393
+
394
+ void expect (Iterable <MentionAutocompleteResult > results) {
395
+ check (results.elementAt (0 ))
396
+ .isA <UserMentionAutocompleteResult >()
397
+ .userId.equals (100 );
398
+ }
399
+
400
+ await doCheck (
401
+ narrow: DmNarrow .withUser (100 , selfUserId: eg.selfUser.userId),
402
+ users: users,
403
+ rawQuery: '' ,
404
+ act: act,
405
+ expect: expect,
406
+ );
407
+ });
385
408
});
386
409
387
410
group ('MentionAutocompleteQuery.testUser' , () {
@@ -428,4 +451,157 @@ void main() {
428
451
doCheck ('Four F' , eg.user (fullName: 'Full Name Four Words' ), false );
429
452
});
430
453
});
454
+
455
+ group ('MentionAutocompleteView users results' , () {
456
+ late PerAccountStore store;
457
+ late MentionAutocompleteView view;
458
+
459
+ Future <void > prepare ({
460
+ required List <User > users,
461
+ required List <RecentDmConversation > dmConversations,
462
+ required Narrow narrow,
463
+ }) async {
464
+ store = eg.store (initialSnapshot: eg.initialSnapshot (
465
+ recentPrivateConversations: dmConversations));
466
+ await store.addUsers (users);
467
+ view = MentionAutocompleteView .init (store: store, narrow: narrow);
468
+ }
469
+
470
+ group ('MentionAutocompleteView.compareByDms' , () {
471
+ test ('has DMs with userA and userB, latest with userA, prioritizes userA' , () async {
472
+ await prepare (
473
+ users: [],
474
+ dmConversations: [
475
+ RecentDmConversation (userIds: [1 ], maxMessageId: 200 ),
476
+ RecentDmConversation (userIds: [1 , 2 ], maxMessageId: 100 ),
477
+ ],
478
+ narrow: const CombinedFeedNarrow (),
479
+ );
480
+
481
+ final userA = eg.user (userId: 1 );
482
+ final userB = eg.user (userId: 2 );
483
+ final compareAB = view.compareByDms (userA, userB);
484
+ check (compareAB).isNegative ();
485
+ });
486
+
487
+ test ('has DMs with userA and userB, latest with userB, prioritizes userB' , () async {
488
+ await prepare (
489
+ users: [],
490
+ dmConversations: [
491
+ RecentDmConversation (userIds: [2 ], maxMessageId: 200 ),
492
+ RecentDmConversation (userIds: [1 , 2 ], maxMessageId: 100 ),
493
+ ],
494
+ narrow: const CombinedFeedNarrow (),
495
+ );
496
+
497
+ final userA = eg.user (userId: 1 );
498
+ final userB = eg.user (userId: 2 );
499
+ final compareAB = view.compareByDms (userA, userB);
500
+ check (compareAB).isGreaterThan (0 );
501
+ });
502
+
503
+ test ('has DMs with userA and userB, equally recent, prioritizes neither' , () async {
504
+ await prepare (
505
+ users: [],
506
+ dmConversations: [
507
+ RecentDmConversation (userIds: [1 , 2 ], maxMessageId: 100 ),
508
+ ],
509
+ narrow: const CombinedFeedNarrow (),
510
+ );
511
+
512
+ final userA = eg.user (userId: 1 );
513
+ final userB = eg.user (userId: 2 );
514
+ final compareAB = view.compareByDms (userA, userB);
515
+ check (compareAB).equals (0 );
516
+ });
517
+
518
+ test ('has DMs with userA but not userB, prioritizes userA' , () async {
519
+ await prepare (
520
+ users: [],
521
+ dmConversations: [
522
+ RecentDmConversation (userIds: [1 ], maxMessageId: 100 ),
523
+ ],
524
+ narrow: const CombinedFeedNarrow (),
525
+ );
526
+
527
+ final userA = eg.user (userId: 1 );
528
+ final userB = eg.user (userId: 2 );
529
+ final compareAB = view.compareByDms (userA, userB);
530
+ check (compareAB).isNegative ();
531
+ });
532
+
533
+ test ('has DMs with userB but not userA, prioritizes userB' , () async {
534
+ await prepare (
535
+ users: [],
536
+ dmConversations: [
537
+ RecentDmConversation (userIds: [2 ], maxMessageId: 100 ),
538
+ ],
539
+ narrow: const CombinedFeedNarrow (),
540
+ );
541
+
542
+ final userA = eg.user (userId: 1 );
543
+ final userB = eg.user (userId: 2 );
544
+ final compareAB = view.compareByDms (userA, userB);
545
+ check (compareAB).isGreaterThan (0 );
546
+ });
547
+
548
+ test ('doesn\' t have DMs with userA or userB, prioritizes neither' , () async {
549
+ await prepare (
550
+ users: [],
551
+ dmConversations: [],
552
+ narrow: const CombinedFeedNarrow (),
553
+ );
554
+
555
+ final userA = eg.user (userId: 1 );
556
+ final userB = eg.user (userId: 2 );
557
+ final compareAB = view.compareByDms (userA, userB);
558
+ check (compareAB).equals (0 );
559
+ });
560
+ });
561
+
562
+ test ('autocomplete suggests relevant users in the following order: '
563
+ '1. Users most recent in the DM conversations' , () async {
564
+ final users = [
565
+ eg.user (userId: 1 ),
566
+ eg.user (userId: 2 ),
567
+ eg.user (userId: 3 ),
568
+ eg.user (userId: 4 ),
569
+ eg.user (userId: 5 ),
570
+ ];
571
+
572
+ final dmConversations = [
573
+ RecentDmConversation (userIds: [4 ], maxMessageId: 300 ),
574
+ RecentDmConversation (userIds: [1 ], maxMessageId: 200 ),
575
+ RecentDmConversation (userIds: [1 , 2 ], maxMessageId: 100 ),
576
+ ];
577
+
578
+ Future <void > checkResultsIn (Narrow narrow, {required List <int > expected}) async {
579
+ await prepare (users: users, dmConversations: dmConversations, narrow: narrow);
580
+
581
+ bool done = false ;
582
+ view.addListener (() { done = true ; });
583
+ view.query = MentionAutocompleteQuery ('' );
584
+ await Future (() {});
585
+ check (done).isTrue ();
586
+ final results = view.results
587
+ .map ((e) => (e as UserMentionAutocompleteResult ).userId)
588
+ .toList ();
589
+ check (results).deepEquals (expected);
590
+ }
591
+
592
+ const streamNarrow = StreamNarrow (1 );
593
+ await checkResultsIn (streamNarrow, expected: [4 , 1 , 2 , 3 , 5 ]);
594
+
595
+ const topicNarrow = TopicNarrow (1 , 'topic' );
596
+ await checkResultsIn (topicNarrow, expected: [4 , 1 , 2 , 3 , 5 ]);
597
+
598
+ final dmNarrow = DmNarrow (allRecipientIds: [eg.selfUser.userId], selfUserId: eg.selfUser.userId);
599
+ await checkResultsIn (dmNarrow, expected: [4 , 1 , 2 , 3 , 5 ]);
600
+
601
+ const allMessagesNarrow = CombinedFeedNarrow ();
602
+ // Results are in the original order as we do not sort them for
603
+ // [AllMessagesNarrow] because we can not access autocomplete for now.
604
+ await checkResultsIn (allMessagesNarrow, expected: [1 , 2 , 3 , 4 , 5 ]);
605
+ });
606
+ });
431
607
}
0 commit comments