@@ -24,6 +24,7 @@ void main() {
24
24
}
25
25
26
26
late MessageListScrollController controller;
27
+ late MessageListScrollPosition position;
27
28
28
29
Future <void > prepare (WidgetTester tester, {
29
30
bool reuseController = false ,
@@ -37,6 +38,7 @@ void main() {
37
38
child: buildList (controller: controller,
38
39
topHeight: topHeight, bottomHeight: bottomHeight)));
39
40
await tester.pump ();
41
+ position = controller.position;
40
42
}
41
43
42
44
// The `skipOffstage: false` produces more informative output
@@ -189,5 +191,70 @@ void main() {
189
191
// … and check the scroll position is preserved, not reset to initial.
190
192
check (tester.getRect (findTop)).bottom.equals (400 );
191
193
});
194
+
195
+ group ('scrollToEnd' , () {
196
+ testWidgets ('short -> slow' , (tester) async {
197
+ await prepare (tester, topHeight: 300 , bottomHeight: 600 );
198
+ await tester.drag (findBottom, Offset (0 , 300 ));
199
+ await tester.pump ();
200
+ check (position.extentAfter).equals (300 );
201
+
202
+ // Start scrolling to end, from just a short distance up.
203
+ position.scrollToEnd ();
204
+ await tester.pump ();
205
+ check (position.extentAfter).equals (300 );
206
+ check (position.activity).isA <DrivenScrollActivity >();
207
+
208
+ // The scrolling moves at a stately pace; …
209
+ await tester.pump (Duration (milliseconds: 100 ));
210
+ check (position.extentAfter).equals (200 );
211
+
212
+ await tester.pump (Duration (milliseconds: 100 ));
213
+ check (position.extentAfter).equals (100 );
214
+
215
+ // … then upon reaching the end, …
216
+ await tester.pump (Duration (milliseconds: 100 ));
217
+ check (position.extentAfter).equals (0 );
218
+
219
+ // … goes idle on the next frame, …
220
+ await tester.pump (Duration (milliseconds: 1 ));
221
+ check (position.activity).isA <IdleScrollActivity >();
222
+ // … without moving any farther.
223
+ check (position.extentAfter).equals (0 );
224
+ });
225
+
226
+ testWidgets ('long -> bounded speed' , (tester) async {
227
+ const referenceSpeed = 8000.0 ;
228
+ const seconds = 10 ;
229
+ const distance = seconds * referenceSpeed;
230
+ await prepare (tester, topHeight: distance + 1000 , bottomHeight: 300 );
231
+ await tester.drag (findBottom, Offset (0 , distance));
232
+ await tester.pump ();
233
+ check (position.extentAfter).equals (distance);
234
+
235
+ // Start scrolling to end.
236
+ position.scrollToEnd ();
237
+ await tester.pump ();
238
+ check (position.activity).isA <DrivenScrollActivity >();
239
+
240
+ // Let it scroll, plotting the trajectory.
241
+ final log = < double > [];
242
+ for (int i = 0 ; i < seconds; i++ ) {
243
+ log.add (position.extentAfter);
244
+ await tester.pump (const Duration (seconds: 1 ));
245
+ }
246
+ log.add (position.extentAfter);
247
+ check (log).deepEquals (List .generate (seconds + 1 ,
248
+ (i) => distance - referenceSpeed * i));
249
+
250
+ // Having reached the end, …
251
+ check (position.extentAfter).equals (0 );
252
+ // … it goes idle on the next frame, …
253
+ await tester.pump (Duration (milliseconds: 1 ));
254
+ check (position.activity).isA <IdleScrollActivity >();
255
+ // … without moving any farther.
256
+ check (position.extentAfter).equals (0 );
257
+ });
258
+ });
192
259
});
193
260
}
0 commit comments