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

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

8 9
import '../rendering/mock_canvas.dart';

10 11 12 13 14 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
enum RadiusType {
  Sharp,
  Shifting,
  Round
}

void matches(BorderRadius borderRadius, RadiusType top, RadiusType bottom) {
  final Radius cardRadius = kMaterialEdges[MaterialType.card].topLeft;

  if (top == RadiusType.Sharp) {
    expect(borderRadius.topLeft, equals(Radius.zero));
    expect(borderRadius.topRight, equals(Radius.zero));
  } else if (top == RadiusType.Shifting) {
    expect(borderRadius.topLeft.x, greaterThan(0.0));
    expect(borderRadius.topLeft.x, lessThan(cardRadius.x));
    expect(borderRadius.topLeft.y, greaterThan(0.0));
    expect(borderRadius.topLeft.y, lessThan(cardRadius.y));
    expect(borderRadius.topRight.x, greaterThan(0.0));
    expect(borderRadius.topRight.x, lessThan(cardRadius.x));
    expect(borderRadius.topRight.y, greaterThan(0.0));
    expect(borderRadius.topRight.y, lessThan(cardRadius.y));
  } else {
    expect(borderRadius.topLeft, equals(cardRadius));
    expect(borderRadius.topRight, equals(cardRadius));
  }

  if (bottom == RadiusType.Sharp) {
    expect(borderRadius.bottomLeft, equals(Radius.zero));
    expect(borderRadius.bottomRight, equals(Radius.zero));
  } else if (bottom == RadiusType.Shifting) {
    expect(borderRadius.bottomLeft.x, greaterThan(0.0));
    expect(borderRadius.bottomLeft.x, lessThan(cardRadius.x));
    expect(borderRadius.bottomLeft.y, greaterThan(0.0));
    expect(borderRadius.bottomLeft.y, lessThan(cardRadius.y));
    expect(borderRadius.bottomRight.x, greaterThan(0.0));
    expect(borderRadius.bottomRight.x, lessThan(cardRadius.x));
    expect(borderRadius.bottomRight.y, greaterThan(0.0));
    expect(borderRadius.bottomRight.y, lessThan(cardRadius.y));
  } else {
    expect(borderRadius.bottomLeft, equals(cardRadius));
    expect(borderRadius.bottomRight, equals(cardRadius));
  }
}

54 55 56
// Returns the border radius decoration of an item within a MergeableMaterial.
// This depends on the exact structure of objects built by the Material and
// MergeableMaterial widgets.
57
BorderRadius getBorderRadius(WidgetTester tester, int index) {
58
  final List<Element> containers = tester.elementList(find.byType(Container))
59 60
                                   .toList();

61
  final Container container = containers[index].widget;
62
  final BoxDecoration boxDecoration = container.decoration;
63 64 65 66 67 68 69

  return boxDecoration.borderRadius;
}

void main() {
  testWidgets('MergeableMaterial empty', (WidgetTester tester) async {
    await tester.pumpWidget(
70
      const MaterialApp(
71 72
        home: Scaffold(
          body: SingleChildScrollView(
73
            child: MergeableMaterial(),
74 75 76
          ),
        ),
      ),
77 78
    );

79
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
80 81 82 83 84
    expect(box.size.height, equals(0));
  });

  testWidgets('MergeableMaterial update slice', (WidgetTester tester) async {
    await tester.pumpWidget(
85
      const MaterialApp(
86 87
        home: Scaffold(
          body: SingleChildScrollView(
88
            child: MergeableMaterial(
89 90 91 92
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
93
                    width: 100.0,
94
                    height: 100.0,
95 96 97 98 99 100 101
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
102 103 104 105 106 107
    );

    RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
    expect(box.size.height, equals(100.0));

    await tester.pumpWidget(
108
      const MaterialApp(
109 110
        home: Scaffold(
          body: SingleChildScrollView(
111
            child: MergeableMaterial(
112 113 114 115
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
116
                    width: 100.0,
117
                    height: 200.0,
118 119 120 121 122 123 124
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
125 126 127 128 129 130 131 132
    );

    box = tester.renderObject(find.byType(MergeableMaterial));
    expect(box.size.height, equals(200.0));
  });

  testWidgets('MergeableMaterial swap slices', (WidgetTester tester) async {
    await tester.pumpWidget(
133
      const MaterialApp(
134 135
        home: Scaffold(
          body: SingleChildScrollView(
136
            child: MergeableMaterial(
137 138 139 140
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
141
                    width: 100.0,
142 143
                    height: 100.0,
                  ),
144
                ),
145 146 147
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
148
                    width: 100.0,
149
                    height: 100.0,
150 151 152 153 154 155 156
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
157 158 159 160 161 162 163 164
    );

    RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
    expect(box.size.height, equals(200.0));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);

    await tester.pumpWidget(
165
      const MaterialApp(
166 167
        home: Scaffold(
          body: SingleChildScrollView(
168
            child: MergeableMaterial(
169 170 171 172
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
173
                    width: 100.0,
174 175
                    height: 100.0,
                  ),
176
                ),
177 178 179
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
180
                    width: 100.0,
181
                    height: 100.0,
182 183 184 185 186 187 188
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
189 190 191 192 193 194 195 196 197 198 199 200
    );

    box = tester.renderObject(find.byType(MergeableMaterial));
    expect(box.size.height, equals(200.0));

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, equals(200.0));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
  });

  testWidgets('MergeableMaterial paints shadows', (WidgetTester tester) async {
201
    debugDisableShadows = false;
202
    await tester.pumpWidget(
203
      const MaterialApp(
204 205
        home: Scaffold(
          body: SingleChildScrollView(
206
            child: MergeableMaterial(
207 208 209 210
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
211
                    width: 100.0,
212
                    height: 100.0,
213 214 215 216 217 218 219
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
220 221 222 223
    );

    final BoxShadow boxShadow = kElevationToShadow[2][0];
    final RRect rrect = kMaterialEdges[MaterialType.card].toRRect(
224
      Rect.fromLTRB(0.0, 0.0, 800.0, 100.0)
225
    );
226 227 228 229
    expect(
      find.byType(MergeableMaterial),
      paints..rrect(rrect: rrect, color: boxShadow.color, hasMaskFilter: true),
    );
230
    debugDisableShadows = true;
231 232 233 234
  });

  testWidgets('MergeableMaterial merge gap', (WidgetTester tester) async {
    await tester.pumpWidget(
235
      const MaterialApp(
236 237
        home: Scaffold(
          body: SingleChildScrollView(
238
            child: MergeableMaterial(
239 240 241 242
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
243
                    width: 100.0,
244 245
                    height: 100.0,
                  ),
246
                ),
247 248
                MaterialGap(
                  key: ValueKey<String>('x')
249
                ),
250 251 252
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
253
                    width: 100.0,
254
                    height: 100.0,
255 256 257 258 259 260 261
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
262 263
    );

264
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
265 266 267 268 269 270
    expect(box.size.height, equals(216));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round);

    await tester.pumpWidget(
271
      const MaterialApp(
272 273
        home: Scaffold(
          body: SingleChildScrollView(
274
            child: MergeableMaterial(
275 276 277 278
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
279
                    width: 100.0,
280 281
                    height: 100.0,
                  ),
282
                ),
283 284 285
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
286
                    width: 100.0,
287
                    height: 100.0,
288 289 290 291 292 293 294
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    );

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, lessThan(216));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Shifting);
    matches(getBorderRadius(tester, 1), RadiusType.Shifting, RadiusType.Round);

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, equals(200));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Sharp);
    matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round);
  });

  testWidgets('MergeableMaterial separate slices', (WidgetTester tester) async {
    await tester.pumpWidget(
312
      const MaterialApp(
313 314
        home: Scaffold(
          body: SingleChildScrollView(
315
            child: MergeableMaterial(
316 317 318 319
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
320
                    width: 100.0,
321 322
                    height: 100.0,
                  ),
323
                ),
324 325 326
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
327
                    width: 100.0,
328
                    height: 100.0,
329 330 331 332 333 334 335
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
336 337
    );

338
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
339 340 341 342 343
    expect(box.size.height, equals(200));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);

    await tester.pumpWidget(
344
      const MaterialApp(
345 346
        home: Scaffold(
          body: SingleChildScrollView(
347
            child: MergeableMaterial(
348 349 350 351
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
352
                    width: 100.0,
353 354
                    height: 100.0,
                  ),
355
                ),
356 357
                MaterialGap(
                  key: ValueKey<String>('x')
358
                ),
359 360 361
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
362
                    width: 100.0,
363
                    height: 100.0,
364 365 366 367 368 369 370
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
    );

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, lessThan(216));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Shifting);
    matches(getBorderRadius(tester, 1), RadiusType.Shifting, RadiusType.Round);

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, equals(216));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round);
  });

Josh Soref's avatar
Josh Soref committed
386
  testWidgets('MergeableMaterial separate merge separate', (WidgetTester tester) async {
387
    await tester.pumpWidget(
388
      const MaterialApp(
389 390
        home: Scaffold(
          body: SingleChildScrollView(
391
            child: MergeableMaterial(
392 393 394 395
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
396
                    width: 100.0,
397 398
                    height: 100.0,
                  ),
399
                ),
400 401 402
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
403
                    width: 100.0,
404 405 406
                    height: 100.0,
                  ),
                ),
407
              ]
408 409 410
            ),
          ),
        ),
411 412 413
      )
    );

414
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
415 416 417 418 419
    expect(box.size.height, equals(200));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);

    await tester.pumpWidget(
420
      const MaterialApp(
421 422
        home: Scaffold(
          body: SingleChildScrollView(
423
            child: MergeableMaterial(
424 425 426 427
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
428
                    width: 100.0,
429 430
                    height: 100.0,
                  ),
431
                ),
432 433
                MaterialGap(
                  key: ValueKey<String>('x')
434
                ),
435 436 437
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
438
                    width: 100.0,
439 440 441
                    height: 100.0,
                  ),
                ),
442
              ]
443 444 445
            ),
          ),
        ),
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
      )
    );

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, lessThan(216));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Shifting);
    matches(getBorderRadius(tester, 1), RadiusType.Shifting, RadiusType.Round);

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, equals(216));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round);

    await tester.pumpWidget(
462
      const MaterialApp(
463 464
        home: Scaffold(
          body: SingleChildScrollView(
465
            child: MergeableMaterial(
466 467 468 469
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
470
                    width: 100.0,
471 472
                    height: 100.0,
                  ),
473
                ),
474 475 476
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
477
                    width: 100.0,
478 479 480
                    height: 100.0,
                  ),
                ),
481
              ]
482 483 484
            ),
          ),
        ),
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
      )
    );

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, lessThan(216));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Shifting);
    matches(getBorderRadius(tester, 1), RadiusType.Shifting, RadiusType.Round);

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, equals(200));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Sharp);
    matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round);

    await tester.pumpWidget(
501
      const MaterialApp(
502 503
        home: Scaffold(
          body: SingleChildScrollView(
504
            child: MergeableMaterial(
505 506 507 508
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
509
                    width: 100.0,
510 511
                    height: 100.0,
                  ),
512
                ),
513 514
                MaterialGap(
                  key: ValueKey<String>('x')
515
                ),
516 517 518
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
519
                    width: 100.0,
520 521 522
                    height: 100.0,
                  ),
                ),
523
              ]
524 525 526
            ),
          ),
        ),
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
      )
    );

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, lessThan(216));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Shifting);
    matches(getBorderRadius(tester, 1), RadiusType.Shifting, RadiusType.Round);

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, equals(216));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round);
  });

  testWidgets('MergeableMaterial insert slice', (WidgetTester tester) async {
    await tester.pumpWidget(
545
      const MaterialApp(
546 547
        home: Scaffold(
          body: SingleChildScrollView(
548
            child: MergeableMaterial(
549 550 551 552
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
553
                    width: 100.0,
554 555
                    height: 100.0,
                  ),
556
                ),
557 558 559
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
560
                    width: 100.0,
561 562 563
                    height: 100.0,
                  ),
                ),
564
              ]
565 566 567
            ),
          ),
        ),
568 569 570
      )
    );

571
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
572 573 574 575 576
    expect(box.size.height, equals(200));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);

    await tester.pumpWidget(
577
      const MaterialApp(
578 579
        home: Scaffold(
          body: SingleChildScrollView(
580
            child: MergeableMaterial(
581 582 583 584
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
585
                    width: 100.0,
586 587
                    height: 100.0,
                  ),
588
                ),
589 590 591
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
592
                    width: 100.0,
593 594
                    height: 100.0,
                  ),
595
                ),
596 597 598
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
599
                    width: 100.0,
600 601 602
                    height: 100.0,
                  ),
                ),
603
              ]
604 605 606
            ),
          ),
        ),
607 608 609 610 611 612 613 614 615 616
      )
    );

    expect(box.size.height, equals(300));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
  });

  testWidgets('MergeableMaterial remove slice', (WidgetTester tester) async {
    await tester.pumpWidget(
617
      const MaterialApp(
618 619
        home: Scaffold(
          body: SingleChildScrollView(
620
            child: MergeableMaterial(
621 622 623 624
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
625
                    width: 100.0,
626 627
                    height: 100.0,
                  ),
628
                ),
629 630 631
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
632
                    width: 100.0,
633 634
                    height: 100.0,
                  ),
635
                ),
636 637 638
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
639
                    width: 100.0,
640 641 642
                    height: 100.0,
                  ),
                ),
643
              ]
644 645 646
            ),
          ),
        ),
647 648 649
      )
    );

650
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
651 652 653 654 655
    expect(box.size.height, equals(300));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);

    await tester.pumpWidget(
656
      const MaterialApp(
657 658
        home: Scaffold(
          body: SingleChildScrollView(
659
            child: MergeableMaterial(
660 661 662 663
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
664
                    width: 100.0,
665 666
                    height: 100.0,
                  ),
667
                ),
668 669 670
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
671
                    width: 100.0,
672 673 674
                    height: 100.0,
                  ),
                ),
675
              ]
676 677 678
            ),
          ),
        ),
679 680 681 682 683 684 685 686 687 688 689
      )
    );

    await tester.pump();
    expect(box.size.height, equals(200));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
  });

  testWidgets('MergeableMaterial insert chunk', (WidgetTester tester) async {
    await tester.pumpWidget(
690
      const MaterialApp(
691 692
        home: Scaffold(
          body: SingleChildScrollView(
693
            child: MergeableMaterial(
694 695 696 697
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
698
                    width: 100.0,
699 700
                    height: 100.0,
                  ),
701
                ),
702 703 704
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
705
                    width: 100.0,
706 707 708
                    height: 100.0,
                  ),
                ),
709
              ]
710 711 712
            ),
          ),
        ),
713 714 715
      )
    );

716
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
717 718 719 720 721
    expect(box.size.height, equals(200));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);

    await tester.pumpWidget(
722
      const MaterialApp(
723 724
        home: Scaffold(
          body: SingleChildScrollView(
725
            child: MergeableMaterial(
726 727 728 729
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
730
                    width: 100.0,
731 732
                    height: 100.0,
                  ),
733
                ),
734 735
                MaterialGap(
                  key: ValueKey<String>('x')
736
                ),
737 738 739
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
740
                    width: 100.0,
741 742
                    height: 100.0,
                  ),
743
                ),
744 745
                MaterialGap(
                  key: ValueKey<String>('y')
746
                ),
747 748 749
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
750
                    width: 100.0,
751 752 753
                    height: 100.0,
                  ),
                ),
754
              ]
755 756 757
            ),
          ),
        ),
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
      )
    );

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, lessThan(332));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Shifting);
    matches(getBorderRadius(tester, 1), RadiusType.Shifting, RadiusType.Shifting);
    matches(getBorderRadius(tester, 2), RadiusType.Shifting, RadiusType.Round);

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, equals(332));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 2), RadiusType.Round, RadiusType.Round);
  });

  testWidgets('MergeableMaterial remove chunk', (WidgetTester tester) async {
    await tester.pumpWidget(
778
      const MaterialApp(
779 780
        home: Scaffold(
          body: SingleChildScrollView(
781
            child: MergeableMaterial(
782 783 784 785
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
786
                    width: 100.0,
787 788
                    height: 100.0,
                  ),
789
                ),
790 791
                MaterialGap(
                  key: ValueKey<String>('x')
792
                ),
793 794 795
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
796
                    width: 100.0,
797 798
                    height: 100.0,
                  ),
799
                ),
800 801
                MaterialGap(
                  key: ValueKey<String>('y')
802
                ),
803 804 805
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
806
                    width: 100.0,
807 808 809
                    height: 100.0,
                  ),
                ),
810
              ]
811 812 813
            ),
          ),
        ),
814 815 816
      )
    );

817
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
818 819 820 821 822 823 824
    expect(box.size.height, equals(332));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 2), RadiusType.Round, RadiusType.Round);

    await tester.pumpWidget(
825
      const MaterialApp(
826 827
        home: Scaffold(
          body: SingleChildScrollView(
828
            child: MergeableMaterial(
829 830 831 832
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
833
                    width: 100.0,
834 835
                    height: 100.0,
                  ),
836
                ),
837 838 839
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
840
                    width: 100.0,
841 842 843
                    height: 100.0,
                  ),
                ),
844
              ]
845 846 847
            ),
          ),
        ),
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
      )
    );

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, lessThan(332));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Shifting);
    matches(getBorderRadius(tester, 1), RadiusType.Shifting, RadiusType.Round);

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, equals(200));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Sharp);
    matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round);
  });

  testWidgets('MergeableMaterial replace gap with chunk', (WidgetTester tester) async {
    await tester.pumpWidget(
866
      const MaterialApp(
867 868
        home: Scaffold(
          body: SingleChildScrollView(
869
            child: MergeableMaterial(
870 871 872 873
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
874
                    width: 100.0,
875 876
                    height: 100.0,
                  ),
877
                ),
878 879
                MaterialGap(
                  key: ValueKey<String>('x')
880
                ),
881 882 883
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
884
                    width: 100.0,
885 886 887
                    height: 100.0,
                  ),
                ),
888
              ]
889 890 891
            ),
          ),
        ),
892 893 894
      )
    );

895
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
896 897 898 899 900 901
    expect(box.size.height, equals(216));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round);

    await tester.pumpWidget(
902
      const MaterialApp(
903 904
        home: Scaffold(
          body: SingleChildScrollView(
905
            child: MergeableMaterial(
906 907 908 909
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
910
                    width: 100.0,
911 912
                    height: 100.0,
                  ),
913
                ),
914 915
                MaterialGap(
                  key: ValueKey<String>('y')
916
                ),
917 918 919
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
920
                    width: 100.0,
921 922
                    height: 100.0,
                  ),
923
                ),
924 925
                MaterialGap(
                  key: ValueKey<String>('z')
926
                ),
927 928 929
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
930
                    width: 100.0,
931 932 933
                    height: 100.0,
                  ),
                ),
934
              ]
935 936 937
            ),
          ),
        ),
938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
      )
    );

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, lessThan(332));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Shifting);
    matches(getBorderRadius(tester, 1), RadiusType.Shifting, RadiusType.Shifting);
    matches(getBorderRadius(tester, 2), RadiusType.Shifting, RadiusType.Round);

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, equals(332));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 2), RadiusType.Round, RadiusType.Round);
  });

  testWidgets('MergeableMaterial replace chunk with gap', (WidgetTester tester) async {
    await tester.pumpWidget(
958
      const MaterialApp(
959 960
        home: Scaffold(
          body: SingleChildScrollView(
961
            child: MergeableMaterial(
962 963 964 965
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
966
                    width: 100.0,
967 968
                    height: 100.0,
                  ),
969
                ),
970 971
                MaterialGap(
                  key: ValueKey<String>('x')
972
                ),
973 974 975
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
976
                    width: 100.0,
977 978
                    height: 100.0,
                  ),
979
                ),
980 981
                MaterialGap(
                  key: ValueKey<String>('y')
982
                ),
983 984 985
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
986
                    width: 100.0,
987 988 989
                    height: 100.0,
                  ),
                ),
990
              ]
991 992 993
            ),
          ),
        ),
994 995 996
      )
    );

997
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
998 999 1000 1001 1002 1003 1004
    expect(box.size.height, equals(332));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 2), RadiusType.Round, RadiusType.Round);

    await tester.pumpWidget(
1005
      const MaterialApp(
1006 1007
        home: Scaffold(
          body: SingleChildScrollView(
1008
            child: MergeableMaterial(
1009 1010 1011 1012
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
1013
                    width: 100.0,
1014 1015
                    height: 100.0,
                  ),
1016
                ),
1017 1018
                MaterialGap(
                  key: ValueKey<String>('z')
1019
                ),
1020 1021 1022
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
1023
                    width: 100.0,
1024 1025 1026
                    height: 100.0,
                  ),
                ),
1027
              ]
1028 1029 1030
            ),
          ),
        ),
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
      )
    );

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, lessThan(332));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Shifting);
    matches(getBorderRadius(tester, 1), RadiusType.Shifting, RadiusType.Round);

    await tester.pump(const Duration(milliseconds: 100));
    expect(box.size.height, equals(216));

    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
    matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round);
  });
1046

1047
  bool isDivider(Widget widget, bool top, bool bottom) {
1048
    final DecoratedBox box = widget;
1049
    const BorderSide side = BorderSide(color: Color(0x1F000000), width: 0.5);
1050

1051 1052
    return box.decoration == BoxDecoration(
      border: Border(
1053
        top: top ? side : BorderSide.none,
1054 1055
        bottom: bottom ? side : BorderSide.none,
      ),
1056 1057 1058 1059 1060
    );
  }

  testWidgets('MergeableMaterial dividers', (WidgetTester tester) async {
    await tester.pumpWidget(
1061
      const MaterialApp(
1062 1063
        home: Scaffold(
          body: SingleChildScrollView(
1064
            child: MergeableMaterial(
1065
              hasDividers: true,
1066 1067 1068 1069
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
1070
                    width: 100.0,
1071 1072
                    height: 100.0,
                  ),
1073
                ),
1074 1075 1076
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
1077
                    width: 100.0,
1078 1079
                    height: 100.0,
                  ),
1080
                ),
1081 1082 1083
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
1084
                    width: 100.0,
1085 1086
                    height: 100.0,
                  ),
1087
                ),
1088 1089 1090
                MaterialSlice(
                  key: ValueKey<String>('D'),
                  child: SizedBox(
1091
                    width: 100.0,
1092 1093 1094 1095 1096 1097 1098
                    height: 100.0,
                  ),
                ),
              ],
            ),
          ),
        ),
1099 1100 1101 1102
      )
    );

    List<Widget> boxes = tester.widgetList(find.byType(DecoratedBox)).toList();
1103
    int offset = 1;
1104

1105 1106 1107 1108
    expect(isDivider(boxes[offset], false, true), isTrue);
    expect(isDivider(boxes[offset + 1], true, true), isTrue);
    expect(isDivider(boxes[offset + 2], true, true), isTrue);
    expect(isDivider(boxes[offset + 3], true, false), isTrue);
1109 1110

    await tester.pumpWidget(
1111
      const MaterialApp(
1112 1113
        home: Scaffold(
          body: SingleChildScrollView(
1114
            child: MergeableMaterial(
1115
              hasDividers: true,
1116 1117 1118 1119
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
1120
                    width: 100.0,
1121 1122
                    height: 100.0,
                  ),
1123
                ),
1124 1125 1126
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
1127
                    width: 100.0,
1128 1129
                    height: 100.0,
                  ),
1130
                ),
1131 1132
                MaterialGap(
                  key: ValueKey<String>('x')
1133
                ),
1134 1135 1136
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
1137
                    width: 100.0,
1138 1139
                    height: 100.0,
                  ),
1140
                ),
1141 1142 1143
                MaterialSlice(
                  key: ValueKey<String>('D'),
                  child: SizedBox(
1144
                    width: 100.0,
1145 1146 1147 1148 1149 1150 1151
                    height: 100.0,
                  ),
                ),
              ],
            ),
          ),
        ),
1152 1153 1154
      )
    );

1155 1156 1157
    // Wait for dividers to shrink.
    await tester.pump(const Duration(milliseconds: 200));

1158
    boxes = tester.widgetList(find.byType(DecoratedBox)).toList();
1159
    offset = 1;
1160

1161 1162
    expect(isDivider(boxes[offset], false, true), isTrue);
    expect(isDivider(boxes[offset + 1], true, false), isTrue);
1163
    // offset + 2 is gap
1164 1165
    expect(isDivider(boxes[offset + 3], false, true), isTrue);
    expect(isDivider(boxes[offset + 4], true, false), isTrue);
1166
  });
1167
}