@@ -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 < 1500 ; i++ ) {
282
284
await store.addUser (eg.user (userId: i, email: 'user$i @example.com' , fullName: 'User $i ' ));
@@ -346,4 +348,127 @@ void main() {
346
348
doCheck ('Four F' , eg.user (fullName: 'Full Name Four Words' ), false );
347
349
});
348
350
});
351
+
352
+ group ('MentionAutocompleteView sorting users results' , () {
353
+ late PerAccountStore store;
354
+
355
+ Future <void > prepare ({
356
+ List <User > users = const [],
357
+ List <RecentDmConversation > dmConversations = const [],
358
+ }) async {
359
+ store = eg.store (initialSnapshot: eg.initialSnapshot (
360
+ recentPrivateConversations: dmConversations));
361
+ await store.addUsers (users);
362
+ }
363
+
364
+ group ('MentionAutocompleteView.compareByDms' , () {
365
+ const idA = 1 ;
366
+ const idB = 2 ;
367
+
368
+ int compareAB () => MentionAutocompleteView .compareByDms (
369
+ eg.user (userId: idA),
370
+ eg.user (userId: idB),
371
+ store: store,
372
+ );
373
+
374
+ test ('has DMs with userA and userB, latest with userA -> prioritizes userA' , () async {
375
+ await prepare (dmConversations: [
376
+ RecentDmConversation (userIds: [idA], maxMessageId: 200 ),
377
+ RecentDmConversation (userIds: [idA, idB], maxMessageId: 100 ),
378
+ ]);
379
+ check (compareAB ()).isNegative ();
380
+ });
381
+
382
+ test ('has DMs with userA and userB, latest with userB -> prioritizes userB' , () async {
383
+ await prepare (dmConversations: [
384
+ RecentDmConversation (userIds: [idB], maxMessageId: 200 ),
385
+ RecentDmConversation (userIds: [idA, idB], maxMessageId: 100 ),
386
+ ]);
387
+ check (compareAB ()).isGreaterThan (0 );
388
+ });
389
+
390
+ test ('has DMs with userA and userB, equally recent -> prioritizes neither' , () async {
391
+ await prepare (dmConversations: [
392
+ RecentDmConversation (userIds: [idA, idB], maxMessageId: 100 ),
393
+ ]);
394
+ check (compareAB ()).equals (0 );
395
+ });
396
+
397
+ test ('has DMs with userA but not userB -> prioritizes userA' , () async {
398
+ await prepare (dmConversations: [
399
+ RecentDmConversation (userIds: [idA], maxMessageId: 100 ),
400
+ ]);
401
+ check (compareAB ()).isNegative ();
402
+ });
403
+
404
+ test ('has DMs with userB but not userA -> prioritizes userB' , () async {
405
+ await prepare (dmConversations: [
406
+ RecentDmConversation (userIds: [idB], maxMessageId: 100 ),
407
+ ]);
408
+ check (compareAB ()).isGreaterThan (0 );
409
+ });
410
+
411
+ test ('doesn\' t have DMs with userA or userB -> prioritizes neither' , () async {
412
+ await prepare (dmConversations: []);
413
+ check (compareAB ()).equals (0 );
414
+ });
415
+ });
416
+
417
+ group ('autocomplete suggests relevant users in the following order: '
418
+ '1. Users most recent in the DM conversations' , () {
419
+ Future <void > checkResultsIn (Narrow narrow, {required List <int > expected}) async {
420
+ final users = [
421
+ eg.user (userId: 0 ),
422
+ eg.user (userId: 1 ),
423
+ eg.user (userId: 2 ),
424
+ eg.user (userId: 3 ),
425
+ eg.user (userId: 4 ),
426
+ ];
427
+
428
+ final dmConversations = [
429
+ RecentDmConversation (userIds: [3 ], maxMessageId: 300 ),
430
+ RecentDmConversation (userIds: [0 ], maxMessageId: 200 ),
431
+ RecentDmConversation (userIds: [0 , 1 ], maxMessageId: 100 ),
432
+ ];
433
+
434
+ await prepare (users: users, dmConversations: dmConversations);
435
+ final view = MentionAutocompleteView .init (store: store, narrow: narrow);
436
+
437
+ bool done = false ;
438
+ view.addListener (() { done = true ; });
439
+ view.query = MentionAutocompleteQuery ('' );
440
+ await Future (() {});
441
+ check (done).isTrue ();
442
+ final results = view.results
443
+ .map ((e) => (e as UserMentionAutocompleteResult ).userId)
444
+ .toList ();
445
+ check (results).deepEquals (expected);
446
+ }
447
+
448
+ test ('StreamNarrow' , () async {
449
+ await checkResultsIn (const StreamNarrow (1 ), expected: [3 , 0 , 1 , 2 , 4 ]);
450
+ });
451
+
452
+ test ('TopicNarrow' , () async {
453
+ await checkResultsIn (const TopicNarrow (1 , 'topic' ), expected: [3 , 0 , 1 , 2 , 4 ]);
454
+ });
455
+
456
+ test ('DmNarrow' , () async {
457
+ await checkResultsIn (
458
+ DmNarrow (allRecipientIds: [eg.selfUser.userId],
459
+ selfUserId: eg.selfUser.userId),
460
+ expected: [3 , 0 , 1 , 2 , 4 ],
461
+ );
462
+ });
463
+
464
+ test ('CombinedFeedNarrow' , () async {
465
+ // As we do not expect a compose box in [CombinedFeedNarrow], it should
466
+ // not proceed to show any results.
467
+ await check (checkResultsIn (
468
+ const CombinedFeedNarrow (),
469
+ expected: [0 , 1 , 2 , 3 , 4 ])
470
+ ).throws ((e) => e.isA <AssertionError >());
471
+ });
472
+ });
473
+ });
349
474
}
0 commit comments