@@ -177,6 +177,67 @@ void main() {
177
177
178
178
debugNetworkImageHttpClientProvider = null ;
179
179
});
180
+
181
+ testWidgets ('user options appear in the correct rendering order and do not scroll down' , (tester) async {
182
+ final List <User > users = [
183
+ eg.user (userId: 1 , fullName: 'Aaditya' , avatarUrl: 'user1.png' ),
184
+ eg.user (userId: 2 , fullName: 'Alya' , avatarUrl: 'user2.png' ),
185
+ eg.user (userId: 3 , fullName: 'Aman' , avatarUrl: 'user3.png' ),
186
+ eg.user (userId: 4 , fullName: 'Anders' , avatarUrl: 'user4.png' ),
187
+ eg.user (userId: 5 , fullName: 'Anthony' , avatarUrl: 'user5.png' ),
188
+ eg.user (userId: 6 , fullName: 'Apoorva' , avatarUrl: 'user6.png' ),
189
+ eg.user (userId: 7 , fullName: 'Asif' , avatarUrl: 'user7.png' ),
190
+ eg.user (userId: 8 , fullName: 'Asim' , avatarUrl: 'user8.png' )
191
+ ];
192
+
193
+ final composeInputFinder = await setupToComposeInput (tester, users: users);
194
+ final store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
195
+
196
+ final expectedUserSequence = users;
197
+ // Options are filtered correctly for query
198
+ // TODO(#226): Remove this extra edit when this bug is fixed.
199
+ await tester.enterText (composeInputFinder, 'hello @' );
200
+ await tester.pumpAndSettle ();
201
+ await tester.enterText (composeInputFinder, 'hello @A' );
202
+ await tester.pumpAndSettle ();
203
+ // Only first seven users render initially, 8th user has to be accessed by scrolling up
204
+ final List <double > positions = [];
205
+ for (int i = 0 ;i < 7 ;i++ ){
206
+ final user = expectedUserSequence[i];
207
+ checkUserShown (user, store, expected: true );
208
+ final finder = find.text (user.fullName);
209
+ check (because: 'Each user option should be rendered (index: $i )' ,finder).findsOne ();
210
+ positions.add (tester.getTopLeft (finder).dy);
211
+ }
212
+ for (int i = 7 ; i < expectedUserSequence.length;i++ ){
213
+ final user = expectedUserSequence[i];
214
+ checkUserShown (user, store, expected: false );
215
+ }
216
+ final listViewFinder = find.byType (ListView );
217
+ check (because: "reason: 'ListView should be rendered'" ,listViewFinder,).findsOne ();
218
+
219
+ final initialScrollOffset = tester.getTopLeft (listViewFinder).dy;
220
+ await tester.drag (listViewFinder, const Offset (0 , - 50 ));
221
+ await tester.pumpAndSettle ();
222
+ final scrollOffsetAfterDragDown = tester.getTopLeft (listViewFinder).dy;
223
+
224
+ check (because: 'ListView should not scroll down because it is already at the bottom' ,scrollOffsetAfterDragDown).equals (initialScrollOffset);
225
+
226
+ for (int i = 0 ;i < 6 ;i++ ){
227
+ check (because: '${expectedUserSequence [i + 1 ]} should appear above ${expectedUserSequence [i ]} because of reverse order' , positions[i]).isGreaterThan (positions[i+ 1 ]);
228
+ }
229
+
230
+ await tester.drag (listViewFinder, const Offset (0 , 200 )); // Should be capped at prev position
231
+ await tester.pumpAndSettle ();
232
+
233
+ checkUserShown (users.last, store, expected: true );
234
+ checkUserShown (users.first, store, expected: false );
235
+
236
+ // 8th user should be above 7th user
237
+ check (because: "8th user should be above 7th user" ,
238
+ tester.getTopLeft (find.text (users.last.fullName)).dy ).isLessThan (tester.getTopLeft (find.text (users[users.length - 2 ].fullName)).dy);
239
+ debugNetworkImageHttpClientProvider = null ;
240
+ });
180
241
});
181
242
182
243
group ('emoji' , () {
@@ -247,6 +308,98 @@ void main() {
247
308
debugNetworkImageHttpClientProvider = null ;
248
309
});
249
310
311
+ testWidgets ('emoji options appear in the correct rendering order and do not scroll down' , (tester) async {
312
+ final composeInputFinder = await setupToComposeInput (tester);
313
+ final store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
314
+
315
+ store.setServerEmojiData (
316
+ ServerEmojiData (
317
+ codeToNames: {
318
+ '1f4a4' : ['zzz' , 'sleepy' ], // Unicode emoji for "zzz"
319
+ '1f52a' : ['biohazard' ],
320
+ '1f92a' : ['zany_face' ],
321
+ '1f993' : ['zebra' ],
322
+ '0030-fe0f-20e3' : ['zero' ],
323
+ '1f9d0' : ['zombie' ],
324
+ },
325
+ ),
326
+ );
327
+ await store.handleEvent (
328
+ RealmEmojiUpdateEvent (
329
+ id: 1 ,
330
+ realmEmoji: {
331
+ '1' : eg.realmEmojiItem (emojiCode: '1' , emojiName: 'buzzing' ),
332
+ },
333
+ ),
334
+ );
335
+
336
+ const zulipOptionLabel = 'zulip' ;
337
+ const zanyFaceOptionLabel = 'zany_face' ;
338
+ const zebraOptionLabel = 'zebra' ;
339
+ const zzzOptionLabel = 'zzz, sleepy' ;
340
+ const unicodeGlyph = '💤' ;
341
+ const zombieOptionLabel = 'zombie' ;
342
+ const zeroOptionLabel = 'zero' ;
343
+ const buzzingOptionLabel = 'buzzing' ;
344
+ const biohazardOptionLabel = 'biohazard' ;
345
+
346
+ // Adjust the order so the best match appears last
347
+ final emojiSequence = [
348
+ zulipOptionLabel,
349
+ zzzOptionLabel,
350
+ unicodeGlyph,
351
+ zanyFaceOptionLabel,
352
+ zebraOptionLabel,
353
+ zeroOptionLabel,
354
+ zombieOptionLabel,
355
+ buzzingOptionLabel,
356
+ // biohazardOptionLabel, this won't be rendered in the list initally since it is the 7th option.
357
+ ];
358
+
359
+ // Enter a query; options appear, of all three emoji types.
360
+ // TODO(#226): Remove this extra edit when this bug is fixed.
361
+ await tester.enterText (composeInputFinder, 'hi :' );
362
+ await tester.enterText (composeInputFinder, 'hi :z' );
363
+ await tester.pumpAndSettle ();
364
+
365
+ final listViewFinder = find.byType (ListView );
366
+ check (because: "reason: 'ListView should be rendered'" ,listViewFinder,).findsOne ();
367
+
368
+ final positions = emojiSequence.map ((icon) {
369
+ final finder = find.text (icon);
370
+ check (because: "Each emoji option should be rendered" , finder).findsOne ();
371
+ return tester.getTopLeft (finder).dy;
372
+ }).toList ();
373
+
374
+ for (int i = 0 ; i < positions.length - 1 ; i++ ) {
375
+ check (because: "${emojiSequence [i + 1 ]} should appear above ${emojiSequence [i ]} because of reverse order" ,
376
+ positions[i]).isGreaterThan (positions[i + 1 ]);
377
+ }
378
+
379
+ final initialScrollOffset = tester.getTopLeft (listViewFinder).dy;
380
+ await tester.drag (listViewFinder, const Offset (0 , - 50 ));
381
+ await tester.pumpAndSettle ();
382
+ final scrollOffsetAfterDragDown = tester.getTopLeft (listViewFinder).dy;
383
+
384
+ check (because: "ListView should not scroll down because it is already at the bottom" ,
385
+ scrollOffsetAfterDragDown).equals (initialScrollOffset);
386
+
387
+ final biohazardFinder = find.text (biohazardOptionLabel);
388
+ check (because: "The biohazard emoji should not be visible before scrolling up" ,biohazardFinder).findsNothing ();
389
+
390
+ // Scroll up
391
+ await tester.drag (listViewFinder, const Offset (0 , 50 ));
392
+ await tester.pumpAndSettle ();
393
+
394
+ check (because: "The biohazard emoji should be visible after scrolling up" ,biohazardFinder).findsOne ();
395
+
396
+ final firstEmojiPositionAfterScrollUp = tester.getTopLeft (find.text (emojiSequence[0 ])).dy;
397
+ check (because: "Scrolling up should reveal other emoji matches" ,firstEmojiPositionAfterScrollUp).isGreaterOrEqual (positions[0 ]);
398
+
399
+ debugNetworkImageHttpClientProvider = null ;
400
+
401
+ });
402
+
250
403
testWidgets ('text emoji means just show text' , (tester) async {
251
404
final composeInputFinder = await setupToComposeInput (tester);
252
405
final store = await testBinding.globalStore.perAccount (eg.selfAccount.id);
0 commit comments