@@ -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 is not '
278
280
'reflected in 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 ' ));
@@ -348,4 +350,128 @@ void main() {
348
350
doCheck ('Four F' , eg.user (fullName: 'Full Name Four Words' ), false );
349
351
});
350
352
});
353
+
354
+ group ('MentionAutocompleteView sorting users results' , () {
355
+ late PerAccountStore store;
356
+
357
+ Future <void > prepare ({
358
+ List <User > users = const [],
359
+ List <RecentDmConversation > dmConversations = const [],
360
+ }) async {
361
+ store = eg.store (initialSnapshot: eg.initialSnapshot (
362
+ recentPrivateConversations: dmConversations));
363
+ await store.addUsers (users);
364
+ }
365
+
366
+ group ('MentionAutocompleteView.compareByDms' , () {
367
+ const idA = 1 ;
368
+ const idB = 2 ;
369
+
370
+ int compareAB () => MentionAutocompleteView .compareByDms (
371
+ eg.user (userId: idA),
372
+ eg.user (userId: idB),
373
+ store: store,
374
+ );
375
+
376
+ test ('has DMs with userA and userB, latest with userA -> prioritizes userA' , () async {
377
+ await prepare (dmConversations: [
378
+ RecentDmConversation (userIds: [idA], maxMessageId: 200 ),
379
+ RecentDmConversation (userIds: [idA, idB], maxMessageId: 100 ),
380
+ ]);
381
+ check (compareAB ()).isLessThan (0 );
382
+ });
383
+
384
+ test ('has DMs with userA and userB, latest with userB -> prioritizes userB' , () async {
385
+ await prepare (dmConversations: [
386
+ RecentDmConversation (userIds: [idB], maxMessageId: 200 ),
387
+ RecentDmConversation (userIds: [idA, idB], maxMessageId: 100 ),
388
+ ]);
389
+ check (compareAB ()).isGreaterThan (0 );
390
+ });
391
+
392
+ test ('has DMs with userA and userB, equally recent -> prioritizes neither' , () async {
393
+ await prepare (dmConversations: [
394
+ RecentDmConversation (userIds: [idA, idB], maxMessageId: 100 ),
395
+ ]);
396
+ check (compareAB ()).equals (0 );
397
+ });
398
+
399
+ test ('has DMs with userA but not userB -> prioritizes userA' , () async {
400
+ await prepare (dmConversations: [
401
+ RecentDmConversation (userIds: [idA], maxMessageId: 100 ),
402
+ ]);
403
+ check (compareAB ()).isLessThan (0 );
404
+ });
405
+
406
+ test ('has DMs with userB but not userA -> prioritizes userB' , () async {
407
+ await prepare (dmConversations: [
408
+ RecentDmConversation (userIds: [idB], maxMessageId: 100 ),
409
+ ]);
410
+ check (compareAB ()).isGreaterThan (0 );
411
+ });
412
+
413
+ test ('has no DMs with userA or userB -> prioritizes neither' , () async {
414
+ await prepare (dmConversations: []);
415
+ check (compareAB ()).equals (0 );
416
+ });
417
+ });
418
+
419
+ group ('autocomplete suggests relevant users in the intended order' , () {
420
+ // The order should be:
421
+ // 1. Users most recent in the DM conversations
422
+
423
+ Future <void > checkResultsIn (Narrow narrow, {required List <int > expected}) async {
424
+ final users = [
425
+ eg.user (userId: 0 ),
426
+ eg.user (userId: 1 ),
427
+ eg.user (userId: 2 ),
428
+ eg.user (userId: 3 ),
429
+ eg.user (userId: 4 ),
430
+ ];
431
+
432
+ final dmConversations = [
433
+ RecentDmConversation (userIds: [3 ], maxMessageId: 300 ),
434
+ RecentDmConversation (userIds: [0 ], maxMessageId: 200 ),
435
+ RecentDmConversation (userIds: [0 , 1 ], maxMessageId: 100 ),
436
+ ];
437
+
438
+ await prepare (users: users, dmConversations: dmConversations);
439
+ final view = MentionAutocompleteView .init (store: store, narrow: narrow);
440
+
441
+ bool done = false ;
442
+ view.addListener (() { done = true ; });
443
+ view.query = MentionAutocompleteQuery ('' );
444
+ await Future (() {});
445
+ check (done).isTrue ();
446
+ final results = view.results
447
+ .map ((e) => (e as UserMentionAutocompleteResult ).userId)
448
+ .toList ();
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
+ });
351
477
}
0 commit comments