grid_view_test.dart 26.4 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'package:flutter/gestures.dart' show DragStartBehavior;
6 7 8
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
9

Adam Barth's avatar
Adam Barth committed
10
import '../rendering/mock_canvas.dart';
11
import '../rendering/rendering_tester.dart' show TestClipPaintingContext;
12 13 14
import 'states.dart';

void main() {
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
  // Regression test for https://github.com/flutter/flutter/issues/100451
  testWidgets('GridView.builder respects findChildIndexCallback', (WidgetTester tester) async {
    bool finderCalled = false;
    int itemCount = 7;
    late StateSetter stateSetter;

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: StatefulBuilder(
          builder: (BuildContext context, StateSetter setState) {
            stateSetter = setState;
            return GridView.builder(
              itemCount: itemCount,
              itemBuilder: (BuildContext _, int index) => Container(
                key: Key('$index'),
                height: 2000.0,
              ),
              findChildIndexCallback: (Key key) {
                finderCalled = true;
                return null;
              },
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 4,
              ),
            );
          },
        ),
      )
    );
    expect(finderCalled, false);

    // Trigger update.
    stateSetter(() => itemCount = 77);
    await tester.pump();

    expect(finderCalled, true);
  });

54
  testWidgets('Empty GridView', (WidgetTester tester) async {
55
    await tester.pumpWidget(
56
      Directionality(
57
        textDirection: TextDirection.ltr,
58
        child: GridView.count(
59
          dragStartBehavior: DragStartBehavior.down,
60 61 62 63
          crossAxisCount: 4,
        ),
      ),
    );
64 65
  });

66
  testWidgets('GridView.count control test', (WidgetTester tester) async {
67
    final List<String> log = <String>[];
68

69
    await tester.pumpWidget(
70
      Directionality(
71
        textDirection: TextDirection.ltr,
72
        child: GridView.count(
73
          dragStartBehavior: DragStartBehavior.down,
74
          crossAxisCount: 4,
75
          children: kStates.map<Widget>((String state) {
76
            return GestureDetector(
77
              dragStartBehavior: DragStartBehavior.down,
78 79 80
              onTap: () {
                log.add(state);
              },
81
              child: ColoredBox(
82
                color: const Color(0xFF0000FF),
83
                child: Text(state),
84 85 86 87 88 89
              ),
            );
          }).toList(),
        ),
      ),
    );
90 91 92 93 94 95 96 97 98 99 100 101

    expect(tester.getSize(find.text('Arkansas')), equals(const Size(200.0, 200.0)));

    for (int i = 0; i < 8; ++i) {
      await tester.tap(find.text(kStates[i]));
      expect(log, equals(<String>[kStates[i]]));
      log.clear();
    }

    expect(find.text(kStates[12]), findsNothing);
    expect(find.text('Nevada'), findsNothing);

102
    await tester.drag(find.text('Arkansas'), const Offset(0.0, -200.0));
103 104
    await tester.pump();

105
    for (int i = 0; i < 4; ++i) {
106
      expect(find.text(kStates[i]), findsNothing);
107
    }
108 109 110 111 112 113 114

    for (int i = 4; i < 12; ++i) {
      await tester.tap(find.text(kStates[i]));
      expect(log, equals(<String>[kStates[i]]));
      log.clear();
    }

115
    await tester.drag(find.text('Delaware'), const Offset(0.0, -4000.0));
116 117 118 119 120
    await tester.pump();

    expect(find.text('Alabama'), findsNothing);
    expect(find.text('Pennsylvania'), findsNothing);

121
    expect(tester.getCenter(find.text('Tennessee')), equals(const Offset(300.0, 100.0)));
122 123 124 125 126

    await tester.tap(find.text('Tennessee'));
    expect(log, equals(<String>['Tennessee']));
    log.clear();

127
    await tester.drag(find.text('Tennessee'), const Offset(0.0, 200.0));
128 129 130 131 132 133 134 135 136 137 138
    await tester.pump();

    await tester.tap(find.text('Tennessee'));
    expect(log, equals(<String>['Tennessee']));
    log.clear();

    await tester.tap(find.text('Pennsylvania'));
    expect(log, equals(<String>['Pennsylvania']));
    log.clear();
  });

139
  testWidgets('GridView.extent control test', (WidgetTester tester) async {
140
    final List<String> log = <String>[];
141

142
    await tester.pumpWidget(
143
      Directionality(
144
        textDirection: TextDirection.ltr,
145
        child: GridView.extent(
146
          dragStartBehavior: DragStartBehavior.down,
147
          maxCrossAxisExtent: 200.0,
148
          children: kStates.map<Widget>((String state) {
149
            return GestureDetector(
150
              dragStartBehavior: DragStartBehavior.down,
151 152 153
              onTap: () {
                log.add(state);
              },
154
              child: ColoredBox(
155
                color: const Color(0xFF0000FF),
156
                child: Text(state),
157 158 159 160 161 162
              ),
            );
          }).toList(),
        ),
      ),
    );
163 164 165 166 167 168 169 170 171 172 173

    expect(tester.getSize(find.text('Arkansas')), equals(const Size(200.0, 200.0)));

    for (int i = 0; i < 8; ++i) {
      await tester.tap(find.text(kStates[i]));
      expect(log, equals(<String>[kStates[i]]));
      log.clear();
    }

    expect(find.text('Nevada'), findsNothing);

174
    await tester.drag(find.text('Arkansas'), const Offset(0.0, -4000.0));
175 176 177 178
    await tester.pump();

    expect(find.text('Alabama'), findsNothing);

179
    expect(tester.getCenter(find.text('Tennessee')), equals(const Offset(300.0, 100.0)));
180 181 182 183 184 185

    await tester.tap(find.text('Tennessee'));
    expect(log, equals(<String>['Tennessee']));
    log.clear();
  });

186
  testWidgets('GridView large scroll jump', (WidgetTester tester) async {
187
    final List<int> log = <int>[];
188

189
    await tester.pumpWidget(
190
      Directionality(
191
        textDirection: TextDirection.ltr,
192
        child: GridView.extent(
193 194 195
          scrollDirection: Axis.horizontal,
          maxCrossAxisExtent: 200.0,
          childAspectRatio: 0.75,
196 197
          children: List<Widget>.generate(80, (int i) {
            return Builder(
198 199
              builder: (BuildContext context) {
                log.add(i);
200
                return Text('$i');
201
              },
202 203 204
            );
          }),
        ),
205
      ),
206
    );
207 208 209 210 211 212 213

    expect(tester.getSize(find.text('4')), equals(const Size(200.0 / 0.75, 200.0)));

    expect(log, equals(<int>[
      0, 1, 2, // col 0
      3, 4, 5, // col 1
      6, 7, 8, // col 2
214
      9, 10, 11, // col 3 (in cached area)
215 216 217
    ]));
    log.clear();

218 219 220 221 222 223 224
    for (int i = 0; i < 9; i++) {
      expect(find.text('$i'), findsOneWidget);
    }
    for (int i = 9; i < 80; i++) {
      expect(find.text('$i'), findsNothing);
    }

225 226
    final ScrollableState state = tester.state(find.byType(Scrollable));
    final ScrollPosition position = state.position;
227 228 229 230 231 232
    position.jumpTo(3025.0);

    expect(log, isEmpty);
    await tester.pump();

    expect(log, equals(<int>[
233
      30, 31, 32, // col 10 (in cached area)
234 235 236 237
      33, 34, 35, // col 11
      36, 37, 38, // col 12
      39, 40, 41, // col 13
      42, 43, 44, // col 14
238
      45, 46, 47, // col 15 (in cached area)
239 240 241
    ]));
    log.clear();

242 243 244 245 246 247 248 249 250 251
    for (int i = 0; i < 33; i++) {
      expect(find.text('$i'), findsNothing);
    }
    for (int i = 33; i < 45; i++) {
      expect(find.text('$i'), findsOneWidget);
    }
    for (int i = 45; i < 80; i++) {
      expect(find.text('$i'), findsNothing);
    }

252 253 254 255 256 257
    position.jumpTo(975.0);

    expect(log, isEmpty);
    await tester.pump();

    expect(log, equals(<int>[
258
      6, 7, 8, // col2 (in cached area)
259 260 261 262
      9, 10, 11, // col 3
      12, 13, 14, // col 4
      15, 16, 17, // col 5
      18, 19, 20, // col 6
263
      21, 22, 23, // col 7 (in cached area)
264 265
    ]));
    log.clear();
266 267 268 269 270 271 272 273 274 275

    for (int i = 0; i < 9; i++) {
      expect(find.text('$i'), findsNothing);
    }
    for (int i = 9; i < 21; i++) {
      expect(find.text('$i'), findsOneWidget);
    }
    for (int i = 21; i < 80; i++) {
      expect(find.text('$i'), findsNothing);
    }
276 277
  });

278
  testWidgets('GridView - change crossAxisCount', (WidgetTester tester) async {
279
    final List<int> log = <int>[];
280 281

    await tester.pumpWidget(
282
      Directionality(
283
        textDirection: TextDirection.ltr,
284
        child: GridView(
285 286 287
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 4,
          ),
288 289
          children: List<Widget>.generate(40, (int i) {
            return Builder(
290 291
              builder: (BuildContext context) {
                log.add(i);
292
                return Text('$i');
293
              },
294 295
            );
          }),
296 297 298 299 300 301 302 303 304 305
        ),
      ),
    );

    expect(tester.getSize(find.text('4')), equals(const Size(200.0, 200.0)));

    expect(log, equals(<int>[
      0, 1, 2, 3, // row 0
      4, 5, 6, 7, // row 1
      8, 9, 10, 11, // row 2
306 307
      12, 13, 14, 15, // row 3 (in cached area)
      16, 17, 18, 19, // row 4 (in cached area)
308
    ]));
309 310 311 312 313 314
    for (int i = 0; i < 12; i++) {
      expect(find.text('$i'), findsOneWidget);
    }
    for (int i = 12; i < 40; i++) {
      expect(find.text('$i'), findsNothing);
    }
315 316 317
    log.clear();

    await tester.pumpWidget(
318
      Directionality(
319
        textDirection: TextDirection.ltr,
320
        child: GridView(
321 322 323
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2,
          ),
324 325
          children: List<Widget>.generate(40, (int i) {
            return Builder(
326 327
              builder: (BuildContext context) {
                log.add(i);
328
                return Text('$i');
329
              },
330 331
            );
          }),
332 333 334 335 336 337 338 339
        ),
      ),
    );

    expect(log, equals(<int>[
      0, 1, 2, 3, // row 0
      4, 5, 6, 7, // row 1
      8, 9, 10, 11, // row 2
340 341
      12, 13, 14, 15, // row 3 (in cached area)
      16, 17, 18, 19, // row 4 (in cached area)
342 343 344 345 346 347 348
    ]));
    log.clear();

    expect(tester.getSize(find.text('3')), equals(const Size(400.0, 400.0)));
    expect(find.text('4'), findsNothing);
  });

349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
  testWidgets('SliverGridRegularTileLayout - can handle close to zero mainAxisStride', (WidgetTester tester) async {
    const SliverGridDelegateWithMaxCrossAxisExtent delegate = SliverGridDelegateWithMaxCrossAxisExtent(
      childAspectRatio: 1e300,
      maxCrossAxisExtent: 500.0,
    );
    final SliverGridLayout layout = delegate.getLayout(
      const SliverConstraints(
        axisDirection: AxisDirection.down,
        growthDirection: GrowthDirection.forward,
        userScrollDirection: ScrollDirection.forward,
        scrollOffset: 100.0,
        precedingScrollExtent: 0.0,
        overlap: 0.0,
        remainingPaintExtent: 0.0,
        crossAxisExtent: 500,
        crossAxisDirection: AxisDirection.right,
        viewportMainAxisExtent: 100.0,
        remainingCacheExtent: 0.0,
        cacheOrigin: 0.0,
368
      ),
369 370 371 372
    );
    expect(layout.getMinChildIndexForScrollOffset(1000.0), 0.0);
  });

373
  testWidgets('GridView - change maxChildCrossAxisExtent', (WidgetTester tester) async {
374
    final List<int> log = <int>[];
375 376

    await tester.pumpWidget(
377
      Directionality(
378
        textDirection: TextDirection.ltr,
379
        child: GridView(
380 381 382
          gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
            maxCrossAxisExtent: 200.0,
          ),
383 384
          children: List<Widget>.generate(40, (int i) {
            return Builder(
385 386
              builder: (BuildContext context) {
                log.add(i);
387
                return Text('$i');
388
              },
389 390
            );
          }),
391 392 393 394 395 396 397 398 399 400
        ),
      ),
    );

    expect(tester.getSize(find.text('4')), equals(const Size(200.0, 200.0)));

    expect(log, equals(<int>[
      0, 1, 2, 3, // row 0
      4, 5, 6, 7, // row 1
      8, 9, 10, 11, // row 2
401 402
      12, 13, 14, 15, // row 3 (in cached area)
      16, 17, 18, 19, // row 4 (in cached area)
403
    ]));
404 405 406 407 408 409
    for (int i = 0; i < 12; i++) {
      expect(find.text('$i'), findsOneWidget);
    }
    for (int i = 12; i < 40; i++) {
      expect(find.text('$i'), findsNothing);
    }
410 411 412
    log.clear();

    await tester.pumpWidget(
413
      Directionality(
414
        textDirection: TextDirection.ltr,
415
        child: GridView(
416 417 418
          gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
            maxCrossAxisExtent: 400.0,
          ),
419 420
          children: List<Widget>.generate(40, (int i) {
            return Builder(
421 422
              builder: (BuildContext context) {
                log.add(i);
423
                return Text('$i');
424
              },
425 426
            );
          }),
427 428 429 430 431 432 433 434
        ),
      ),
    );

    expect(log, equals(<int>[
      0, 1, 2, 3, // row 0
      4, 5, 6, 7, // row 1
      8, 9, 10, 11, // row 2
435 436
      12, 13, 14, 15, // row 3 (in cached area)
      16, 17, 18, 19, // row 4 (in cached area)
437 438 439 440 441 442
    ]));
    log.clear();

    expect(tester.getSize(find.text('3')), equals(const Size(400.0, 400.0)));
    expect(find.text('4'), findsNothing);
  });
443

Adam Barth's avatar
Adam Barth committed
444
  testWidgets('One-line GridView paints', (WidgetTester tester) async {
445
    const Color green = Color(0xFF00FF00);
Adam Barth's avatar
Adam Barth committed
446

447
    final Container container = Container(
Adam Barth's avatar
Adam Barth committed
448
      decoration: const BoxDecoration(
449
        color: green,
Adam Barth's avatar
Adam Barth committed
450 451 452
      ),
    );

453
    await tester.pumpWidget(
454
      Directionality(
455
        textDirection: TextDirection.ltr,
456 457
        child: Center(
          child: SizedBox(
458
            height: 200.0,
459
            child: GridView.count(
460
              cacheExtent: 0.0,
461 462 463 464
              crossAxisCount: 2,
              children: <Widget>[ container, container, container, container ],
            ),
          ),
Adam Barth's avatar
Adam Barth committed
465 466
        ),
      ),
467
    );
Adam Barth's avatar
Adam Barth committed
468 469 470 471 472

    expect(find.byType(GridView), paints..rect(color: green)..rect(color: green));
    expect(find.byType(GridView), isNot(paints..rect(color: green)..rect(color: green)..rect(color: green)));
  });

473 474
  testWidgets('GridView in zero context', (WidgetTester tester) async {
    await tester.pumpWidget(
475
      Directionality(
476
        textDirection: TextDirection.ltr,
477
        child: Center(
478
          child: SizedBox.shrink(
479
            child: GridView.count(
480
              crossAxisCount: 4,
481
              children: List<Widget>.generate(20, (int i) {
482
                return Text('$i');
483 484 485 486 487 488 489
              }),
            ),
          ),
        ),
      ),
    );

490
    expect(find.text('0'), findsNothing);
491 492 493 494 495
    expect(find.text('1'), findsNothing);
  });

  testWidgets('GridView in unbounded context', (WidgetTester tester) async {
    await tester.pumpWidget(
496
      Directionality(
497
        textDirection: TextDirection.ltr,
498 499
        child: SingleChildScrollView(
          child: GridView.count(
500
            crossAxisCount: 4,
501
            shrinkWrap: true,
502
            children: List<Widget>.generate(20, (int i) {
503
              return Text('$i');
504 505 506 507 508 509 510
            }),
          ),
        ),
      ),
    );

    expect(find.text('0'), findsOneWidget);
511
    expect(find.text('19'), findsOneWidget);
512 513
  });

514
  testWidgets('GridView.builder control test', (WidgetTester tester) async {
515
    await tester.pumpWidget(
516
      Directionality(
517
        textDirection: TextDirection.ltr,
518
        child: GridView.builder(
519 520 521
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 4,
          ),
522
          shrinkWrap: true,
523 524
          itemCount: 20,
          itemBuilder: (BuildContext context, int index) {
525
            return Text('$index');
526
          },
527 528 529
        ),
      ),
    );
530 531 532 533 534
    expect(find.text('0'), findsOneWidget);
    expect(find.text('11'), findsOneWidget);
    expect(find.text('12'), findsNothing);
  });

535 536
  testWidgets('GridView.builder with undefined itemCount', (WidgetTester tester) async {
    await tester.pumpWidget(
537
      Directionality(
538
        textDirection: TextDirection.ltr,
539
        child: GridView.builder(
540 541 542 543 544
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 4,
          ),
          shrinkWrap: true,
          itemBuilder: (BuildContext context, int index) {
545
            return Text('$index');
546 547 548 549 550 551 552 553 554 555 556
          },
        ),
      ),
    );
    expect(find.text('0'), findsOneWidget);
    expect(find.text('11'), findsOneWidget);
    await tester.drag(find.byType(GridView), const Offset(0.0, -300.0));
    await tester.pump(const Duration(milliseconds: 200));
    expect(find.text('13'), findsOneWidget);
  });

557
  testWidgets('GridView cross axis layout', (WidgetTester tester) async {
558
    final Key target = UniqueKey();
559 560

    Widget build(TextDirection textDirection) {
561
      return Directionality(
562
        textDirection: textDirection,
563
        child: GridView.count(
564 565
          crossAxisCount: 4,
          children: <Widget>[
566
            Container(key: target),
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
          ],
        ),
      );
    }

    await tester.pumpWidget(build(TextDirection.ltr));

    expect(tester.getTopLeft(find.byKey(target)), Offset.zero);
    expect(tester.getBottomRight(find.byKey(target)), const Offset(200.0, 200.0));

    await tester.pumpWidget(build(TextDirection.rtl));

    expect(tester.getTopLeft(find.byKey(target)), const Offset(600.0, 0.0));
    expect(tester.getBottomRight(find.byKey(target)), const Offset(800.0, 200.0));
  });
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609

  testWidgets('GridView crossAxisSpacing', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/27151.
    final Key target = UniqueKey();

    Widget build(TextDirection textDirection) {
      return Directionality(
        textDirection: textDirection,
        child: GridView.count(
          crossAxisCount: 4,
          crossAxisSpacing: 8.0,
          children: <Widget>[
            Container(key: target),
          ],
        ),
      );
    }

    await tester.pumpWidget(build(TextDirection.ltr));

    expect(tester.getTopLeft(find.byKey(target)), Offset.zero);
    expect(tester.getBottomRight(find.byKey(target)), const Offset(194.0, 194.0));

    await tester.pumpWidget(build(TextDirection.rtl));

    expect(tester.getTopLeft(find.byKey(target)), const Offset(606.0, 0.0));
    expect(tester.getBottomRight(find.byKey(target)), const Offset(800.0, 194.0));
  });
610 611 612 613 614 615 616 617 618 619

  testWidgets('GridView does not cache itemBuilder calls', (WidgetTester tester) async {
    final Map<int, int> counters = <int, int>{};

    await tester.pumpWidget(Directionality(
      textDirection: TextDirection.ltr,
      child: GridView.builder(
        itemCount: 1000,
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
        itemBuilder: (BuildContext context, int index) {
620
          counters[index] = (counters[index] ?? 0) + 1;
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
          return SizedBox(
            key: ValueKey<int>(index),
            width: 200,
            height: 200,
          );
        },
      ),
    ));

    expect(find.byKey(const ValueKey<int>(4)), findsOneWidget);
    expect(counters[4], 1);

    await tester.fling(find.byType(GridView), const Offset(0, -300), 5000);
    await tester.pumpAndSettle();

    expect(find.byKey(const ValueKey<int>(4)), findsNothing);
    expect(counters[4], 1);

    await tester.fling(find.byType(GridView), const Offset(0, 300), 5000);
    await tester.pumpAndSettle();

    expect(find.byKey(const ValueKey<int>(4)), findsOneWidget);
    expect(counters[4], 2);
  });
645

646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
  testWidgets('GridView does not report visual overflow unnecessarily', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: GridView(
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
          children: <Widget>[
            Container(height: 200.0),
          ],
        ),
      ),
    );

    // 1st, check that the render object has received the default clip behavior.
    final RenderViewport renderObject = tester.allRenderObjects.whereType<RenderViewport>().first;
    expect(renderObject.clipBehavior, equals(Clip.hardEdge));

    // The context will get Clip.none because there is no actual visual overflow.
    final TestClipPaintingContext context = TestClipPaintingContext();
    renderObject.paint(context, Offset.zero);
    expect(context.clipBehavior, equals(Clip.none));
  });

669 670 671 672 673 674
  testWidgets('GridView respects clipBehavior', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: GridView(
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
          children: <Widget>[
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
          ],
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
        ),
      ),
    );

    // 1st, check that the render object has received the default clip behavior.
    final RenderViewport renderObject = tester.allRenderObjects.whereType<RenderViewport>().first;
    expect(renderObject.clipBehavior, equals(Clip.hardEdge));

    // 2nd, check that the painting context has received the default clip behavior.
    final TestClipPaintingContext context = TestClipPaintingContext();
    renderObject.paint(context, Offset.zero);
    expect(context.clipBehavior, equals(Clip.hardEdge));

    // 3rd, pump a new widget to check that the render object can update its clip behavior.
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: GridView(
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
          clipBehavior: Clip.antiAlias,
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
          children: <Widget>[
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
            Container(height: 2000.0),
          ],
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
        ),
      ),
    );
    expect(renderObject.clipBehavior, equals(Clip.antiAlias));

    // 4th, check that a non-default clip behavior can be sent to the painting context.
    renderObject.paint(context, Offset.zero);
    expect(context.clipBehavior, equals(Clip.antiAlias));
  });

  testWidgets('GridView.builder respects clipBehavior', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: GridView.builder(
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
          itemCount: 10,
          itemBuilder: (BuildContext _, int __) => Container(height: 2000.0),
          clipBehavior: Clip.antiAlias,
        ),
      ),
    );
    final RenderViewport renderObject = tester.allRenderObjects.whereType<RenderViewport>().first;
    expect(renderObject.clipBehavior, equals(Clip.antiAlias));
  });

  testWidgets('GridView.custom respects clipBehavior', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: GridView.custom(
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
          childrenDelegate: SliverChildBuilderDelegate(
                (BuildContext context, int index) => Container(height: 2000.0),
            childCount: 1,
          ),
          clipBehavior: Clip.antiAlias,
        ),
      ),
    );
    final RenderViewport renderObject = tester.allRenderObjects.whereType<RenderViewport>().first;
    expect(renderObject.clipBehavior, equals(Clip.antiAlias));
  });

  testWidgets('GridView.count respects clipBehavior', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: GridView.count(
          crossAxisCount: 3,
          clipBehavior: Clip.antiAlias,
776
          children: <Widget>[Container(height: 2000.0)],
777 778 779 780 781 782 783 784 785 786 787 788 789 790
        ),
      ),
    );
    final RenderViewport renderObject = tester.allRenderObjects.whereType<RenderViewport>().first;
    expect(renderObject.clipBehavior, equals(Clip.antiAlias));
  });

  testWidgets('GridView.extent respects clipBehavior', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: GridView.extent(
          maxCrossAxisExtent: 1000,
          clipBehavior: Clip.antiAlias,
791
          children: <Widget>[Container(height: 2000.0)],
792 793 794 795 796 797
        ),
      ),
    );
    final RenderViewport renderObject = tester.allRenderObjects.whereType<RenderViewport>().first;
    expect(renderObject.clipBehavior, equals(Clip.antiAlias));
  });
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813

  testWidgets('SliverGridDelegateWithFixedCrossAxisCount mainAxisExtent works as expected', (WidgetTester tester) async {
    const int crossAxisCount = 4;
    const double mainAxisExtent = 100.0;

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: GridView(
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: crossAxisCount,
            mainAxisExtent: mainAxisExtent,
          ),
          children: List<Widget>.generate(20, (int i) {
            return Builder(
              builder: (BuildContext context) {
814
                return Text('$i');
815
              },
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
            );
          }),
        ),
      ),
    );

    expect(tester.getSize(find.text('4')), equals(const Size(200.0, mainAxisExtent)));
  });

  testWidgets('SliverGridDelegateWithMaxCrossAxisExtent mainAxisExtent works as expected', (WidgetTester tester) async {
    const double maxCrossAxisExtent = 200.0;
    const double mainAxisExtent = 100.0;

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: GridView(
          gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
            maxCrossAxisExtent: maxCrossAxisExtent,
            mainAxisExtent: mainAxisExtent,
          ),
          children: List<Widget>.generate(20, (int i) {
            return Builder(
              builder: (BuildContext context) {
840
                return Text('$i');
841
              },
842 843 844 845 846 847 848 849
            );
          }),
        ),
      ),
    );

    expect(tester.getSize(find.text('4')), equals(const Size(200.0, mainAxisExtent)));
  });
850 851 852 853 854 855 856 857 858

  testWidgets('SliverGridDelegateWithMaxCrossAxisExtent throws assertion error when maxCrossAxisExtent is 0', (WidgetTester tester) async {
    const double maxCrossAxisExtent = 0;

    expect(() => Directionality(
      textDirection: TextDirection.ltr,
      child: GridView.extent(
        maxCrossAxisExtent: maxCrossAxisExtent,
      ),
859
    ), throwsAssertionError);
860 861

  });
862
}