@@ -5,9 +5,11 @@ 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' ;
12
+ import 'package:zulip/model/store.dart' ;
11
13
import 'package:zulip/widgets/compose_box.dart' ;
12
14
13
15
import '../example_data.dart' as eg;
@@ -166,7 +168,7 @@ void main() {
166
168
});
167
169
168
170
test ('MentionAutocompleteView misc' , () async {
169
- const narrow = CombinedFeedNarrow ( );
171
+ const narrow = StreamNarrow ( 1 );
170
172
final store = eg.store ();
171
173
await store.addUsers ([eg.selfUser, eg.otherUser, eg.thirdUser]);
172
174
final view = MentionAutocompleteView .init (store: store, narrow: narrow);
@@ -183,7 +185,7 @@ void main() {
183
185
184
186
test ('MentionAutocompleteView not starve timers' , () {
185
187
fakeAsync ((binding) async {
186
- const narrow = CombinedFeedNarrow ( );
188
+ const narrow = StreamNarrow ( 1 );
187
189
final store = eg.store ();
188
190
await store.addUsers ([eg.selfUser, eg.otherUser, eg.thirdUser]);
189
191
final view = MentionAutocompleteView .init (store: store, narrow: narrow);
@@ -218,7 +220,7 @@ void main() {
218
220
});
219
221
220
222
test ('MentionAutocompleteView yield between batches of 1000' , () async {
221
- const narrow = CombinedFeedNarrow ( );
223
+ const narrow = StreamNarrow ( 1 );
222
224
final store = eg.store ();
223
225
for (int i = 0 ; i < 2500 ; i++ ) {
224
226
await store.addUser (eg.user (userId: i, email: 'user$i @example.com' , fullName: 'User $i ' ));
@@ -241,7 +243,7 @@ void main() {
241
243
});
242
244
243
245
test ('MentionAutocompleteView new query during computation replaces old' , () async {
244
- const narrow = CombinedFeedNarrow ( );
246
+ const narrow = StreamNarrow ( 1 );
245
247
final store = eg.store ();
246
248
for (int i = 0 ; i < 1500 ; i++ ) {
247
249
await store.addUser (eg.user (userId: i, email: 'user$i @example.com' , fullName: 'User $i ' ));
@@ -276,7 +278,7 @@ void main() {
276
278
277
279
test ('MentionAutocompleteView mutating store.users while in progress does not '
278
280
'interrupt the current query results' , () async {
279
- const narrow = CombinedFeedNarrow ( );
281
+ const narrow = StreamNarrow ( 1 );
280
282
final store = eg.store ();
281
283
for (int i = 0 ; i < 2500 ; i++ ) {
282
284
await store.addUser (eg.user (userId: i, email: 'user$i @example.com' , fullName: 'User $i ' ));
@@ -349,4 +351,127 @@ void main() {
349
351
doCheck ('Four F' , eg.user (fullName: 'Full Name Four Words' ), false );
350
352
});
351
353
});
354
+
355
+ group ('MentionAutocompleteView sorting users results' , () {
356
+ late PerAccountStore store;
357
+
358
+ Future <void > prepare ({
359
+ List <User > users = const [],
360
+ List <RecentDmConversation > dmConversations = const [],
361
+ }) async {
362
+ store = eg.store (initialSnapshot: eg.initialSnapshot (
363
+ recentPrivateConversations: dmConversations));
364
+ await store.addUsers (users);
365
+ }
366
+
367
+ group ('MentionAutocompleteView.compareByDms' , () {
368
+ const idA = 1 ;
369
+ const idB = 2 ;
370
+
371
+ int compareAB () => MentionAutocompleteView .compareByDms (
372
+ eg.user (userId: idA),
373
+ eg.user (userId: idB),
374
+ store: store,
375
+ );
376
+
377
+ test ('has DMs with userA and userB, latest with userA -> prioritizes userA' , () async {
378
+ await prepare (dmConversations: [
379
+ RecentDmConversation (userIds: [idA], maxMessageId: 200 ),
380
+ RecentDmConversation (userIds: [idA, idB], maxMessageId: 100 ),
381
+ ]);
382
+ check (compareAB ()).isLessThan (0 );
383
+ });
384
+
385
+ test ('has DMs with userA and userB, latest with userB -> prioritizes userB' , () async {
386
+ await prepare (dmConversations: [
387
+ RecentDmConversation (userIds: [idB], maxMessageId: 200 ),
388
+ RecentDmConversation (userIds: [idA, idB], maxMessageId: 100 ),
389
+ ]);
390
+ check (compareAB ()).isGreaterThan (0 );
391
+ });
392
+
393
+ test ('has DMs with userA and userB, equally recent -> prioritizes neither' , () async {
394
+ await prepare (dmConversations: [
395
+ RecentDmConversation (userIds: [idA, idB], maxMessageId: 100 ),
396
+ ]);
397
+ check (compareAB ()).equals (0 );
398
+ });
399
+
400
+ test ('has DMs with userA but not userB -> prioritizes userA' , () async {
401
+ await prepare (dmConversations: [
402
+ RecentDmConversation (userIds: [idA], maxMessageId: 100 ),
403
+ ]);
404
+ check (compareAB ()).isLessThan (0 );
405
+ });
406
+
407
+ test ('has DMs with userB but not userA -> prioritizes userB' , () async {
408
+ await prepare (dmConversations: [
409
+ RecentDmConversation (userIds: [idB], maxMessageId: 100 ),
410
+ ]);
411
+ check (compareAB ()).isGreaterThan (0 );
412
+ });
413
+
414
+ test ('has no DMs with userA or userB -> prioritizes neither' , () async {
415
+ await prepare (dmConversations: []);
416
+ check (compareAB ()).equals (0 );
417
+ });
418
+ });
419
+
420
+ group ('autocomplete suggests relevant users in the intended order' , () {
421
+ // The order should be:
422
+ // 1. Users most recent in the DM conversations
423
+
424
+ Future <void > checkResultsIn (Narrow narrow, {required List <int > expected}) async {
425
+ final users = [
426
+ eg.user (userId: 0 ),
427
+ eg.user (userId: 1 ),
428
+ eg.user (userId: 2 ),
429
+ eg.user (userId: 3 ),
430
+ eg.user (userId: 4 ),
431
+ ];
432
+
433
+ final dmConversations = [
434
+ RecentDmConversation (userIds: [3 ], maxMessageId: 300 ),
435
+ RecentDmConversation (userIds: [0 ], maxMessageId: 200 ),
436
+ RecentDmConversation (userIds: [0 , 1 ], maxMessageId: 100 ),
437
+ ];
438
+
439
+ await prepare (users: users, dmConversations: dmConversations);
440
+ final view = MentionAutocompleteView .init (store: store, narrow: narrow);
441
+
442
+ bool done = false ;
443
+ view.addListener (() { done = true ; });
444
+ view.query = MentionAutocompleteQuery ('' );
445
+ await Future (() {});
446
+ check (done).isTrue ();
447
+ final results = view.results
448
+ .map ((e) => (e as UserMentionAutocompleteResult ).userId);
449
+ check (results).deepEquals (expected);
450
+ }
451
+
452
+ test ('StreamNarrow' , () async {
453
+ await checkResultsIn (const StreamNarrow (1 ), expected: [3 , 0 , 1 , 2 , 4 ]);
454
+ });
455
+
456
+ test ('TopicNarrow' , () async {
457
+ await checkResultsIn (const TopicNarrow (1 , 'topic' ), expected: [3 , 0 , 1 , 2 , 4 ]);
458
+ });
459
+
460
+ test ('DmNarrow' , () async {
461
+ await checkResultsIn (
462
+ DmNarrow .withUser (eg.selfUser.userId, selfUserId: eg.selfUser.userId),
463
+ expected: [3 , 0 , 1 , 2 , 4 ],
464
+ );
465
+ });
466
+
467
+ test ('CombinedFeedNarrow' , () async {
468
+ // As we do not expect a compose box in [CombinedFeedNarrow], it should
469
+ // not proceed to show any results.
470
+ await check (checkResultsIn (
471
+ const CombinedFeedNarrow (),
472
+ expected: [0 , 1 , 2 , 3 , 4 ])
473
+ ).throws ();
474
+ });
475
+ });
476
+ });
352
477
}
0 commit comments