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