ensure_visible_test.dart 27.2 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:math' as math;

import 'package:flutter_test/flutter_test.dart';
8
import 'package:flutter/rendering.dart';
9 10
import 'package:flutter/widgets.dart';

11
Finder findKey(int i) => find.byKey(ValueKey<int>(i));
12

13
Widget buildSingleChildScrollView(Axis scrollDirection, { bool reverse = false }) {
14
  return Directionality(
15
    textDirection: TextDirection.ltr,
16 17
    child: Center(
      child: SizedBox(
18 19
        width: 600.0,
        height: 400.0,
20
        child: SingleChildScrollView(
21 22
          scrollDirection: scrollDirection,
          reverse: reverse,
23
          child: ListBody(
24 25
            mainAxis: scrollDirection,
            children: <Widget>[
26 27 28 29 30 31 32
              Container(key: const ValueKey<int>(0), width: 200.0, height: 200.0),
              Container(key: const ValueKey<int>(1), width: 200.0, height: 200.0),
              Container(key: const ValueKey<int>(2), width: 200.0, height: 200.0),
              Container(key: const ValueKey<int>(3), width: 200.0, height: 200.0),
              Container(key: const ValueKey<int>(4), width: 200.0, height: 200.0),
              Container(key: const ValueKey<int>(5), width: 200.0, height: 200.0),
              Container(key: const ValueKey<int>(6), width: 200.0, height: 200.0),
33 34 35 36 37 38 39 40
            ],
          ),
        ),
      ),
    ),
  );
}

41
Widget buildListView(Axis scrollDirection, { bool reverse = false, bool shrinkWrap = false }) {
42
  return Directionality(
43
    textDirection: TextDirection.ltr,
44 45
    child: Center(
      child: SizedBox(
46 47
        width: 600.0,
        height: 400.0,
48
        child: ListView(
49 50
          scrollDirection: scrollDirection,
          reverse: reverse,
51
          addSemanticIndexes: false,
52
          shrinkWrap: shrinkWrap,
53
          children: <Widget>[
54 55 56 57 58 59 60
            Container(key: const ValueKey<int>(0), width: 200.0, height: 200.0),
            Container(key: const ValueKey<int>(1), width: 200.0, height: 200.0),
            Container(key: const ValueKey<int>(2), width: 200.0, height: 200.0),
            Container(key: const ValueKey<int>(3), width: 200.0, height: 200.0),
            Container(key: const ValueKey<int>(4), width: 200.0, height: 200.0),
            Container(key: const ValueKey<int>(5), width: 200.0, height: 200.0),
            Container(key: const ValueKey<int>(6), width: 200.0, height: 200.0),
61 62 63 64 65 66 67
          ],
        ),
      ),
    ),
  );
}

68
void main() {
69

Josh Soref's avatar
Josh Soref committed
70 71
  group('SingleChildScrollView', () {
    testWidgets('SingleChildScrollView ensureVisible Axis.vertical', (WidgetTester tester) async {
72
      BuildContext findContext(int i) => tester.element(findKey(i));
73

74
      await tester.pumpWidget(buildSingleChildScrollView(Axis.vertical));
75

Adam Barth's avatar
Adam Barth committed
76
      Scrollable.ensureVisible(findContext(3));
77
      await tester.pump();
78
      expect(tester.getTopLeft(findKey(3)).dy, equals(100.0));
79

Adam Barth's avatar
Adam Barth committed
80
      Scrollable.ensureVisible(findContext(6));
81
      await tester.pump();
82
      expect(tester.getTopLeft(findKey(6)).dy, equals(300.0));
83

Adam Barth's avatar
Adam Barth committed
84
      Scrollable.ensureVisible(findContext(4), alignment: 1.0);
85
      await tester.pump();
86
      expect(tester.getBottomRight(findKey(4)).dy, equals(500.0));
87

Adam Barth's avatar
Adam Barth committed
88
      Scrollable.ensureVisible(findContext(0), alignment: 1.0);
89
      await tester.pump();
90
      expect(tester.getTopLeft(findKey(0)).dy, equals(100.0));
91

Adam Barth's avatar
Adam Barth committed
92
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
93 94
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
95
      expect(tester.getTopLeft(findKey(3)).dy, equals(100.0));
96 97
    });

Josh Soref's avatar
Josh Soref committed
98
    testWidgets('SingleChildScrollView ensureVisible Axis.horizontal', (WidgetTester tester) async {
99 100 101 102
      BuildContext findContext(int i) => tester.element(findKey(i));

      await tester.pumpWidget(buildSingleChildScrollView(Axis.horizontal));

Adam Barth's avatar
Adam Barth committed
103
      Scrollable.ensureVisible(findContext(3));
104
      await tester.pump();
105
      expect(tester.getTopLeft(findKey(3)).dx, equals(100.0));
106

Adam Barth's avatar
Adam Barth committed
107
      Scrollable.ensureVisible(findContext(6));
108
      await tester.pump();
109
      expect(tester.getTopLeft(findKey(6)).dx, equals(500.0));
110

Adam Barth's avatar
Adam Barth committed
111
      Scrollable.ensureVisible(findContext(4), alignment: 1.0);
112
      await tester.pump();
113
      expect(tester.getBottomRight(findKey(4)).dx, equals(700.0));
114

Adam Barth's avatar
Adam Barth committed
115
      Scrollable.ensureVisible(findContext(0), alignment: 1.0);
116
      await tester.pump();
117
      expect(tester.getTopLeft(findKey(0)).dx, equals(100.0));
118

Adam Barth's avatar
Adam Barth committed
119
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
120 121
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
122
      expect(tester.getTopLeft(findKey(3)).dx, equals(100.0));
123 124
    });

Josh Soref's avatar
Josh Soref committed
125
    testWidgets('SingleChildScrollView ensureVisible Axis.vertical reverse', (WidgetTester tester) async {
126 127 128 129
      BuildContext findContext(int i) => tester.element(findKey(i));

      await tester.pumpWidget(buildSingleChildScrollView(Axis.vertical, reverse: true));

Adam Barth's avatar
Adam Barth committed
130
      Scrollable.ensureVisible(findContext(3));
131
      await tester.pump();
132
      expect(tester.getBottomRight(findKey(3)).dy, equals(500.0));
133

Adam Barth's avatar
Adam Barth committed
134
      Scrollable.ensureVisible(findContext(0));
135
      await tester.pump();
136
      expect(tester.getBottomRight(findKey(0)).dy, equals(300.0));
137

Adam Barth's avatar
Adam Barth committed
138
      Scrollable.ensureVisible(findContext(2), alignment: 1.0);
139
      await tester.pump();
140
      expect(tester.getTopLeft(findKey(2)).dy, equals(100.0));
141

Adam Barth's avatar
Adam Barth committed
142
      Scrollable.ensureVisible(findContext(6), alignment: 1.0);
143
      await tester.pump();
144
      expect(tester.getBottomRight(findKey(6)).dy, equals(500.0));
145

Adam Barth's avatar
Adam Barth committed
146
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
147 148
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
149
      expect(tester.getBottomRight(findKey(3)).dy, equals(500.0));
150 151
    });

Josh Soref's avatar
Josh Soref committed
152
    testWidgets('SingleChildScrollView ensureVisible Axis.horizontal reverse', (WidgetTester tester) async {
153 154 155 156
      BuildContext findContext(int i) => tester.element(findKey(i));

      await tester.pumpWidget(buildSingleChildScrollView(Axis.horizontal, reverse: true));

Adam Barth's avatar
Adam Barth committed
157
      Scrollable.ensureVisible(findContext(3));
158
      await tester.pump();
159
      expect(tester.getBottomRight(findKey(3)).dx, equals(700.0));
160

Adam Barth's avatar
Adam Barth committed
161
      Scrollable.ensureVisible(findContext(0));
162
      await tester.pump();
163
      expect(tester.getBottomRight(findKey(0)).dx, equals(300.0));
164

Adam Barth's avatar
Adam Barth committed
165
      Scrollable.ensureVisible(findContext(2), alignment: 1.0);
166
      await tester.pump();
167
      expect(tester.getTopLeft(findKey(2)).dx, equals(100.0));
168

Adam Barth's avatar
Adam Barth committed
169
      Scrollable.ensureVisible(findContext(6), alignment: 1.0);
170
      await tester.pump();
171
      expect(tester.getBottomRight(findKey(6)).dx, equals(700.0));
172

Adam Barth's avatar
Adam Barth committed
173
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
174 175
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
176
      expect(tester.getBottomRight(findKey(3)).dx, equals(700.0));
177 178
    });

Josh Soref's avatar
Josh Soref committed
179
    testWidgets('SingleChildScrollView ensureVisible rotated child', (WidgetTester tester) async {
180 181 182
      BuildContext findContext(int i) => tester.element(findKey(i));

      await tester.pumpWidget(
183 184
        Center(
          child: SizedBox(
185 186
            width: 600.0,
            height: 400.0,
187 188
            child: SingleChildScrollView(
              child: ListBody(
189
                children: <Widget>[
190 191 192 193
                  Container(height: 200.0),
                  Container(height: 200.0),
                  Container(height: 200.0),
                  Container(
194
                    height: 200.0,
195 196 197 198
                    child: Center(
                      child: Transform(
                        transform: Matrix4.rotationZ(math.pi),
                        child: Container(
199
                          key: const ValueKey<int>(0),
200 201
                          width: 100.0,
                          height: 100.0,
202
                          color: const Color(0xFFFFFFFF),
203 204 205 206
                        ),
                      ),
                    ),
                  ),
207 208 209
                  Container(height: 200.0),
                  Container(height: 200.0),
                  Container(height: 200.0),
210 211 212 213 214 215
                ],
              ),
            ),
          ),
        )
      );
216

Adam Barth's avatar
Adam Barth committed
217
      Scrollable.ensureVisible(findContext(0));
218
      await tester.pump();
219
      expect(tester.getBottomRight(findKey(0)).dy, closeTo(100.0, 0.1));
220

Adam Barth's avatar
Adam Barth committed
221
      Scrollable.ensureVisible(findContext(0), alignment: 1.0);
222
      await tester.pump();
223
      expect(tester.getTopLeft(findKey(0)).dy, closeTo(500.0, 0.1));
224
    });
225 226
  });

227 228 229
  group('ListView', () {
    testWidgets('ListView ensureVisible Axis.vertical', (WidgetTester tester) async {
      BuildContext findContext(int i) => tester.element(findKey(i));
230
      Future<void> prepare(double offset) async {
Adam Barth's avatar
Adam Barth committed
231
        tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset);
232 233 234 235 236 237
        await tester.pump();
      }

      await tester.pumpWidget(buildListView(Axis.vertical));

      await prepare(480.0);
Adam Barth's avatar
Adam Barth committed
238
      Scrollable.ensureVisible(findContext(3));
239
      await tester.pump();
240
      expect(tester.getTopLeft(findKey(3)).dy, equals(100.0));
241 242

      await prepare(1083.0);
Adam Barth's avatar
Adam Barth committed
243
      Scrollable.ensureVisible(findContext(6));
244
      await tester.pump();
245
      expect(tester.getTopLeft(findKey(6)).dy, equals(300.0));
246 247

      await prepare(735.0);
Adam Barth's avatar
Adam Barth committed
248
      Scrollable.ensureVisible(findContext(4), alignment: 1.0);
249
      await tester.pump();
250
      expect(tester.getBottomRight(findKey(4)).dy, equals(500.0));
251 252

      await prepare(123.0);
Adam Barth's avatar
Adam Barth committed
253
      Scrollable.ensureVisible(findContext(0), alignment: 1.0);
254
      await tester.pump();
255
      expect(tester.getTopLeft(findKey(0)).dy, equals(100.0));
256 257

      await prepare(523.0);
Adam Barth's avatar
Adam Barth committed
258
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
259 260
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
261
      expect(tester.getTopLeft(findKey(3)).dy, equals(100.0));
262 263 264 265
    });

    testWidgets('ListView ensureVisible Axis.horizontal', (WidgetTester tester) async {
      BuildContext findContext(int i) => tester.element(findKey(i));
266
      Future<void> prepare(double offset) async {
Adam Barth's avatar
Adam Barth committed
267
        tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset);
268 269 270 271 272 273
        await tester.pump();
      }

      await tester.pumpWidget(buildListView(Axis.horizontal));

      await prepare(23.0);
Adam Barth's avatar
Adam Barth committed
274
      Scrollable.ensureVisible(findContext(3));
275
      await tester.pump();
276
      expect(tester.getTopLeft(findKey(3)).dx, equals(100.0));
277 278

      await prepare(843.0);
Adam Barth's avatar
Adam Barth committed
279
      Scrollable.ensureVisible(findContext(6));
280
      await tester.pump();
281
      expect(tester.getTopLeft(findKey(6)).dx, equals(500.0));
282 283

      await prepare(415.0);
Adam Barth's avatar
Adam Barth committed
284
      Scrollable.ensureVisible(findContext(4), alignment: 1.0);
285
      await tester.pump();
286
      expect(tester.getBottomRight(findKey(4)).dx, equals(700.0));
287 288

      await prepare(46.0);
Adam Barth's avatar
Adam Barth committed
289
      Scrollable.ensureVisible(findContext(0), alignment: 1.0);
290
      await tester.pump();
291
      expect(tester.getTopLeft(findKey(0)).dx, equals(100.0));
292 293

      await prepare(211.0);
Adam Barth's avatar
Adam Barth committed
294
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
295 296
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
297
      expect(tester.getTopLeft(findKey(3)).dx, equals(100.0));
298 299 300 301
    });

    testWidgets('ListView ensureVisible Axis.vertical reverse', (WidgetTester tester) async {
      BuildContext findContext(int i) => tester.element(findKey(i));
302
      Future<void> prepare(double offset) async {
Adam Barth's avatar
Adam Barth committed
303
        tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset);
304 305 306 307 308 309
        await tester.pump();
      }

      await tester.pumpWidget(buildListView(Axis.vertical, reverse: true));

      await prepare(211.0);
Adam Barth's avatar
Adam Barth committed
310
      Scrollable.ensureVisible(findContext(3));
311
      await tester.pump();
312
      expect(tester.getBottomRight(findKey(3)).dy, equals(500.0));
313 314

      await prepare(23.0);
Adam Barth's avatar
Adam Barth committed
315
      Scrollable.ensureVisible(findContext(0));
316
      await tester.pump();
317
      expect(tester.getBottomRight(findKey(0)).dy, equals(500.0));
318 319

      await prepare(230.0);
Adam Barth's avatar
Adam Barth committed
320
      Scrollable.ensureVisible(findContext(2), alignment: 1.0);
321
      await tester.pump();
322
      expect(tester.getTopLeft(findKey(2)).dy, equals(100.0));
323 324

      await prepare(1083.0);
Adam Barth's avatar
Adam Barth committed
325
      Scrollable.ensureVisible(findContext(6), alignment: 1.0);
326
      await tester.pump();
327
      expect(tester.getBottomRight(findKey(6)).dy, equals(300.0));
328 329

      await prepare(345.0);
Adam Barth's avatar
Adam Barth committed
330
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
331 332
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
333
      expect(tester.getBottomRight(findKey(3)).dy, equals(500.0));
334 335 336 337
    });

    testWidgets('ListView ensureVisible Axis.horizontal reverse', (WidgetTester tester) async {
      BuildContext findContext(int i) => tester.element(findKey(i));
338
      Future<void> prepare(double offset) async {
Adam Barth's avatar
Adam Barth committed
339
        tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset);
340 341 342 343 344 345
        await tester.pump();
      }

      await tester.pumpWidget(buildListView(Axis.horizontal, reverse: true));

      await prepare(211.0);
Adam Barth's avatar
Adam Barth committed
346
      Scrollable.ensureVisible(findContext(3));
347
      await tester.pump();
348
      expect(tester.getBottomRight(findKey(3)).dx, equals(700.0));
349 350

      await prepare(23.0);
Adam Barth's avatar
Adam Barth committed
351
      Scrollable.ensureVisible(findContext(0));
352
      await tester.pump();
353
      expect(tester.getBottomRight(findKey(0)).dx, equals(700.0));
354 355

      await prepare(230.0);
Adam Barth's avatar
Adam Barth committed
356
      Scrollable.ensureVisible(findContext(2), alignment: 1.0);
357
      await tester.pump();
358
      expect(tester.getTopLeft(findKey(2)).dx, equals(100.0));
359 360

      await prepare(1083.0);
Adam Barth's avatar
Adam Barth committed
361
      Scrollable.ensureVisible(findContext(6), alignment: 1.0);
362
      await tester.pump();
363
      expect(tester.getBottomRight(findKey(6)).dx, equals(300.0));
364 365

      await prepare(345.0);
Adam Barth's avatar
Adam Barth committed
366
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
367 368
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
369
      expect(tester.getBottomRight(findKey(3)).dx, equals(700.0));
370 371 372 373 374
    });

    // TODO(abarth): Unskip this test. See https://github.com/flutter/flutter/issues/7919
    testWidgets('ListView ensureVisible negative child', (WidgetTester tester) async {
      BuildContext findContext(int i) => tester.element(findKey(i));
375
      Future<void> prepare(double offset) async {
Adam Barth's avatar
Adam Barth committed
376
        tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset);
377 378 379 380
        await tester.pump();
      }

      double getOffset() {
Adam Barth's avatar
Adam Barth committed
381
        return tester.state<ScrollableState>(find.byType(Scrollable)).position.pixels;
382 383 384
      }

      Widget buildSliver(int i) {
385 386 387
        return SliverToBoxAdapter(
          key: ValueKey<int>(i),
          child: Container(width: 200.0, height: 200.0),
388 389 390
        );
      }

391
      await tester.pumpWidget(
392
        Directionality(
393
          textDirection: TextDirection.ltr,
394 395
          child: Center(
            child: SizedBox(
396 397
              width: 600.0,
              height: 400.0,
398
              child: Scrollable(
399
                viewportBuilder: (BuildContext context, ViewportOffset offset) {
400
                  return Viewport(
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
                    offset: offset,
                    center: const ValueKey<int>(4),
                    slivers: <Widget>[
                      buildSliver(0),
                      buildSliver(1),
                      buildSliver(2),
                      buildSliver(3),
                      buildSliver(4),
                      buildSliver(5),
                      buildSliver(6),
                    ],
                  );
                },
              ),
            ),
416 417
          ),
        ),
418
      );
419 420

      await prepare(-125.0);
Adam Barth's avatar
Adam Barth committed
421
      Scrollable.ensureVisible(findContext(3));
422 423 424 425
      await tester.pump();
      expect(getOffset(), equals(-200.0));

      await prepare(-225.0);
Adam Barth's avatar
Adam Barth committed
426
      Scrollable.ensureVisible(findContext(2));
427 428 429 430 431 432
      await tester.pump();
      expect(getOffset(), equals(-400.0));
    }, skip: true);

    testWidgets('ListView ensureVisible rotated child', (WidgetTester tester) async {
      BuildContext findContext(int i) => tester.element(findKey(i));
433
      Future<void> prepare(double offset) async {
Adam Barth's avatar
Adam Barth committed
434
        tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset);
435 436 437
        await tester.pump();
      }

438
      await tester.pumpWidget(Directionality(
439
        textDirection: TextDirection.ltr,
440 441
        child: Center(
          child: SizedBox(
442 443
            width: 600.0,
            height: 400.0,
444
            child: ListView(
445
              children: <Widget>[
446 447 448 449
                Container(height: 200.0),
                Container(height: 200.0),
                Container(height: 200.0),
                Container(
450
                  height: 200.0,
451 452 453 454
                  child: Center(
                    child: Transform(
                      transform: Matrix4.rotationZ(math.pi),
                      child: Container(
455
                        key: const ValueKey<int>(0),
456 457
                        width: 100.0,
                        height: 100.0,
458
                        color: const Color(0xFFFFFFFF),
459 460 461 462
                      ),
                    ),
                  ),
                ),
463 464 465
                Container(height: 200.0),
                Container(height: 200.0),
                Container(height: 200.0),
466 467 468
              ],
            ),
          ),
469
        ),
470
      ));
471 472

      await prepare(321.0);
Adam Barth's avatar
Adam Barth committed
473
      Scrollable.ensureVisible(findContext(0));
474
      await tester.pump();
475
      expect(tester.getBottomRight(findKey(0)).dy, closeTo(100.0, 0.1));
476

Adam Barth's avatar
Adam Barth committed
477
      Scrollable.ensureVisible(findContext(0), alignment: 1.0);
478
      await tester.pump();
479
      expect(tester.getTopLeft(findKey(0)).dy, closeTo(500.0, 0.1));
480
    });
481 482
  });

483 484 485
  group('ListView shrinkWrap', () {
    testWidgets('ListView ensureVisible Axis.vertical', (WidgetTester tester) async {
      BuildContext findContext(int i) => tester.element(findKey(i));
486
      Future<void> prepare(double offset) async {
Adam Barth's avatar
Adam Barth committed
487
        tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset);
488 489 490 491 492 493
        await tester.pump();
      }

      await tester.pumpWidget(buildListView(Axis.vertical, shrinkWrap: true));

      await prepare(480.0);
Adam Barth's avatar
Adam Barth committed
494
      Scrollable.ensureVisible(findContext(3));
495
      await tester.pump();
496
      expect(tester.getTopLeft(findKey(3)).dy, equals(100.0));
497 498

      await prepare(1083.0);
Adam Barth's avatar
Adam Barth committed
499
      Scrollable.ensureVisible(findContext(6));
500
      await tester.pump();
501
      expect(tester.getTopLeft(findKey(6)).dy, equals(300.0));
502 503

      await prepare(735.0);
Adam Barth's avatar
Adam Barth committed
504
      Scrollable.ensureVisible(findContext(4), alignment: 1.0);
505
      await tester.pump();
506
      expect(tester.getBottomRight(findKey(4)).dy, equals(500.0));
507 508

      await prepare(123.0);
Adam Barth's avatar
Adam Barth committed
509
      Scrollable.ensureVisible(findContext(0), alignment: 1.0);
510
      await tester.pump();
511
      expect(tester.getTopLeft(findKey(0)).dy, equals(100.0));
512 513

      await prepare(523.0);
Adam Barth's avatar
Adam Barth committed
514
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
515 516
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
517
      expect(tester.getTopLeft(findKey(3)).dy, equals(100.0));
518 519 520 521
    });

    testWidgets('ListView ensureVisible Axis.horizontal', (WidgetTester tester) async {
      BuildContext findContext(int i) => tester.element(findKey(i));
522
      Future<void> prepare(double offset) async {
Adam Barth's avatar
Adam Barth committed
523
        tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset);
524 525 526 527 528 529
        await tester.pump();
      }

      await tester.pumpWidget(buildListView(Axis.horizontal, shrinkWrap: true));

      await prepare(23.0);
Adam Barth's avatar
Adam Barth committed
530
      Scrollable.ensureVisible(findContext(3));
531
      await tester.pump();
532
      expect(tester.getTopLeft(findKey(3)).dx, equals(100.0));
533 534

      await prepare(843.0);
Adam Barth's avatar
Adam Barth committed
535
      Scrollable.ensureVisible(findContext(6));
536
      await tester.pump();
537
      expect(tester.getTopLeft(findKey(6)).dx, equals(500.0));
538 539

      await prepare(415.0);
Adam Barth's avatar
Adam Barth committed
540
      Scrollable.ensureVisible(findContext(4), alignment: 1.0);
541
      await tester.pump();
542
      expect(tester.getBottomRight(findKey(4)).dx, equals(700.0));
543 544

      await prepare(46.0);
Adam Barth's avatar
Adam Barth committed
545
      Scrollable.ensureVisible(findContext(0), alignment: 1.0);
546
      await tester.pump();
547
      expect(tester.getTopLeft(findKey(0)).dx, equals(100.0));
548 549

      await prepare(211.0);
Adam Barth's avatar
Adam Barth committed
550
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
551 552
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
553
      expect(tester.getTopLeft(findKey(3)).dx, equals(100.0));
554 555 556 557
    });

    testWidgets('ListView ensureVisible Axis.vertical reverse', (WidgetTester tester) async {
      BuildContext findContext(int i) => tester.element(findKey(i));
558
      Future<void> prepare(double offset) async {
Adam Barth's avatar
Adam Barth committed
559
        tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset);
560 561 562 563 564 565
        await tester.pump();
      }

      await tester.pumpWidget(buildListView(Axis.vertical, reverse: true, shrinkWrap: true));

      await prepare(211.0);
Adam Barth's avatar
Adam Barth committed
566
      Scrollable.ensureVisible(findContext(3));
567
      await tester.pump();
568
      expect(tester.getBottomRight(findKey(3)).dy, equals(500.0));
569 570

      await prepare(23.0);
Adam Barth's avatar
Adam Barth committed
571
      Scrollable.ensureVisible(findContext(0));
572
      await tester.pump();
573
      expect(tester.getBottomRight(findKey(0)).dy, equals(500.0));
574 575

      await prepare(230.0);
Adam Barth's avatar
Adam Barth committed
576
      Scrollable.ensureVisible(findContext(2), alignment: 1.0);
577
      await tester.pump();
578
      expect(tester.getTopLeft(findKey(2)).dy, equals(100.0));
579 580

      await prepare(1083.0);
Adam Barth's avatar
Adam Barth committed
581
      Scrollable.ensureVisible(findContext(6), alignment: 1.0);
582
      await tester.pump();
583
      expect(tester.getBottomRight(findKey(6)).dy, equals(300.0));
584 585

      await prepare(345.0);
Adam Barth's avatar
Adam Barth committed
586
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
587 588
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
589
      expect(tester.getBottomRight(findKey(3)).dy, equals(500.0));
590 591 592 593
    });

    testWidgets('ListView ensureVisible Axis.horizontal reverse', (WidgetTester tester) async {
      BuildContext findContext(int i) => tester.element(findKey(i));
594
      Future<void> prepare(double offset) async {
Adam Barth's avatar
Adam Barth committed
595
        tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset);
596 597 598 599 600 601
        await tester.pump();
      }

      await tester.pumpWidget(buildListView(Axis.horizontal, reverse: true, shrinkWrap: true));

      await prepare(211.0);
Adam Barth's avatar
Adam Barth committed
602
      Scrollable.ensureVisible(findContext(3));
603
      await tester.pump();
604
      expect(tester.getBottomRight(findKey(3)).dx, equals(700.0));
605 606

      await prepare(23.0);
Adam Barth's avatar
Adam Barth committed
607
      Scrollable.ensureVisible(findContext(0));
608
      await tester.pump();
609
      expect(tester.getBottomRight(findKey(0)).dx, equals(700.0));
610 611

      await prepare(230.0);
Adam Barth's avatar
Adam Barth committed
612
      Scrollable.ensureVisible(findContext(2), alignment: 1.0);
613
      await tester.pump();
614
      expect(tester.getTopLeft(findKey(2)).dx, equals(100.0));
615 616

      await prepare(1083.0);
Adam Barth's avatar
Adam Barth committed
617
      Scrollable.ensureVisible(findContext(6), alignment: 1.0);
618
      await tester.pump();
619
      expect(tester.getBottomRight(findKey(6)).dx, equals(300.0));
620 621

      await prepare(345.0);
Adam Barth's avatar
Adam Barth committed
622
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
623 624
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
625
      expect(tester.getBottomRight(findKey(3)).dx, equals(700.0));
626 627
    });
  });
628 629 630 631

  group('Scrollable with center', () {
    testWidgets('ensureVisible', (WidgetTester tester) async {
      BuildContext findContext(int i) => tester.element(findKey(i));
632
      Future<void> prepare(double offset) async {
633 634 635 636
        tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset);
        await tester.pump();
      }

637
      await tester.pumpWidget(
638
        Directionality(
639
          textDirection: TextDirection.ltr,
640 641
          child: Center(
            child: SizedBox(
642 643
              width: 600.0,
              height: 400.0,
644
              child: Scrollable(
645
                viewportBuilder: (BuildContext context, ViewportOffset offset) {
646
                  return Viewport(
647 648 649
                    offset: offset,
                    center: const ValueKey<String>('center'),
                    slivers: <Widget>[
650 651 652 653 654 655 656 657 658 659 660 661 662
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(-6), width: 200.0, height: 200.0)),
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(-5), width: 200.0, height: 200.0)),
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(-4), width: 200.0, height: 200.0)),
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(-3), width: 200.0, height: 200.0)),
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(-2), width: 200.0, height: 200.0)),
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(-1), width: 200.0, height: 200.0)),
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(0), width: 200.0, height: 200.0), key: const ValueKey<String>('center')),
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(1), width: 200.0, height: 200.0)),
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(2), width: 200.0, height: 200.0)),
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(3), width: 200.0, height: 200.0)),
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(4), width: 200.0, height: 200.0)),
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(5), width: 200.0, height: 200.0)),
                      SliverToBoxAdapter(child: Container(key: const ValueKey<int>(6), width: 200.0, height: 200.0)),
663 664 665 666 667
                    ],
                  );
                },
              ),
            ),
668 669
          ),
        ),
670
      );
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720

      await prepare(480.0);
      Scrollable.ensureVisible(findContext(3));
      await tester.pump();
      expect(tester.getTopLeft(findKey(3)).dy, equals(100.0));

      await prepare(1083.0);
      Scrollable.ensureVisible(findContext(6));
      await tester.pump();
      expect(tester.getTopLeft(findKey(6)).dy, equals(300.0));

      await prepare(735.0);
      Scrollable.ensureVisible(findContext(4), alignment: 1.0);
      await tester.pump();
      expect(tester.getBottomRight(findKey(4)).dy, equals(500.0));

      await prepare(123.0);
      Scrollable.ensureVisible(findContext(0), alignment: 1.0);
      await tester.pump();
      expect(tester.getBottomRight(findKey(0)).dy, equals(500.0));

      await prepare(523.0);
      Scrollable.ensureVisible(findContext(3), duration: const Duration(seconds: 1));
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
      expect(tester.getTopLeft(findKey(3)).dy, equals(100.0));


      await prepare(-480.0);
      Scrollable.ensureVisible(findContext(-3));
      await tester.pump();
      expect(tester.getTopLeft(findKey(-3)).dy, equals(100.0));

      await prepare(-1083.0);
      Scrollable.ensureVisible(findContext(-6));
      await tester.pump();
      expect(tester.getTopLeft(findKey(-6)).dy, equals(100.0));

      await prepare(-735.0);
      Scrollable.ensureVisible(findContext(-4), alignment: 1.0);
      await tester.pump();
      expect(tester.getBottomRight(findKey(-4)).dy, equals(500.0));

      await prepare(-523.0);
      Scrollable.ensureVisible(findContext(-3), duration: const Duration(seconds: 1));
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 1020));
      expect(tester.getTopLeft(findKey(-3)).dy, equals(100.0));
    });
  });
721
}