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