mergeable_material_test.dart 39.4 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter 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
enum RadiusType {
  Sharp,
  Shifting,
  Round
}

16 17
void matches(BorderRadius? borderRadius, RadiusType top, RadiusType bottom) {
  final Radius cardRadius = kMaterialEdges[MaterialType.card]!.topLeft;
18 19

  if (top == RadiusType.Sharp) {
20 21
    expect(borderRadius?.topLeft, equals(Radius.zero));
    expect(borderRadius?.topRight, equals(Radius.zero));
22
  } else if (top == RadiusType.Shifting) {
23 24 25 26 27 28 29 30
    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));
31
  } else {
32 33
    expect(borderRadius?.topLeft, equals(cardRadius));
    expect(borderRadius?.topRight, equals(cardRadius));
34 35 36
  }

  if (bottom == RadiusType.Sharp) {
37 38
    expect(borderRadius?.bottomLeft, equals(Radius.zero));
    expect(borderRadius?.bottomRight, equals(Radius.zero));
39
  } else if (bottom == RadiusType.Shifting) {
40 41 42 43 44 45 46 47
    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));
48
  } else {
49 50
    expect(borderRadius?.bottomLeft, equals(cardRadius));
    expect(borderRadius?.bottomRight, equals(cardRadius));
51 52 53
  }
}

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 as Container;
62
  final BoxDecoration? boxDecoration = container.decoration as BoxDecoration?;
63

64
  return boxDecoration!.borderRadius as BorderRadius?;
65 66 67 68 69
}

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
    );

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

162 163
    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Sharp);
    matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round);
164 165

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

    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));

198 199
    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Sharp);
    matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round);
200 201 202
  });

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

224
    final RRect rrect = kMaterialEdges[MaterialType.card]!.toRRect(
225
      const Rect.fromLTRB(0.0, 0.0, 800.0, 100.0),
226
    );
227 228
    expect(
      find.byType(MergeableMaterial),
229 230 231
      paints
        ..shadow(elevation: 2.0)
        ..rrect(rrect: rrect, color: Colors.white, hasMaskFilter: false),
232
    );
233
    debugDisableShadows = true;
234 235 236 237
  });

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

267
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
268 269 270 271 272 273
    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(
274
      const MaterialApp(
275 276
        home: Scaffold(
          body: SingleChildScrollView(
277
            child: MergeableMaterial(
278 279 280 281
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
282
                    width: 100.0,
283 284
                    height: 100.0,
                  ),
285
                ),
286 287 288
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
289
                    width: 100.0,
290
                    height: 100.0,
291 292 293 294 295 296 297
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
    );

    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(
315
      const MaterialApp(
316 317
        home: Scaffold(
          body: SingleChildScrollView(
318
            child: MergeableMaterial(
319 320 321 322
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
323
                    width: 100.0,
324 325
                    height: 100.0,
                  ),
326
                ),
327 328 329
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
330
                    width: 100.0,
331
                    height: 100.0,
332 333 334 335 336 337 338
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
339 340
    );

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

344 345
    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Sharp);
    matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round);
346 347

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

    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
390
  testWidgets('MergeableMaterial separate merge separate', (WidgetTester tester) async {
391
    await tester.pumpWidget(
392
      const MaterialApp(
393 394
        home: Scaffold(
          body: SingleChildScrollView(
395
            child: MergeableMaterial(
396 397 398 399
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
400
                    width: 100.0,
401 402
                    height: 100.0,
                  ),
403
                ),
404 405 406
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
407
                    width: 100.0,
408 409 410
                    height: 100.0,
                  ),
                ),
411
              ],
412 413 414
            ),
          ),
        ),
415
      ),
416 417
    );

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

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

424 425

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

    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(
468
      const MaterialApp(
469 470
        home: Scaffold(
          body: SingleChildScrollView(
471
            child: MergeableMaterial(
472 473 474 475
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
476
                    width: 100.0,
477 478
                    height: 100.0,
                  ),
479
                ),
480 481 482
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
483
                    width: 100.0,
484 485 486
                    height: 100.0,
                  ),
                ),
487
              ],
488 489 490
            ),
          ),
        ),
491
      ),
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
    );

    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(
507
      const MaterialApp(
508 509
        home: Scaffold(
          body: SingleChildScrollView(
510
            child: MergeableMaterial(
511 512 513 514
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
515
                    width: 100.0,
516 517
                    height: 100.0,
                  ),
518
                ),
519
                MaterialGap(
520
                  key: ValueKey<String>('x'),
521
                ),
522 523 524
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
525
                    width: 100.0,
526 527 528
                    height: 100.0,
                  ),
                ),
529
              ],
530 531 532
            ),
          ),
        ),
533
      ),
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
    );

    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(
551
      const MaterialApp(
552 553
        home: Scaffold(
          body: SingleChildScrollView(
554
            child: MergeableMaterial(
555 556 557 558
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
559
                    width: 100.0,
560 561
                    height: 100.0,
                  ),
562
                ),
563 564 565
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
566
                    width: 100.0,
567 568 569
                    height: 100.0,
                  ),
                ),
570
              ],
571 572 573
            ),
          ),
        ),
574
      ),
575 576
    );

577
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
578 579
    expect(box.size.height, equals(200));

580 581
    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Sharp);
    matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round);
582 583

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

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

619 620 621
    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Sharp);
    matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Sharp);
    matches(getBorderRadius(tester, 2), RadiusType.Sharp, RadiusType.Round);
622 623 624 625
  });

  testWidgets('MergeableMaterial remove slice', (WidgetTester tester) async {
    await tester.pumpWidget(
626
      const MaterialApp(
627 628
        home: Scaffold(
          body: SingleChildScrollView(
629
            child: MergeableMaterial(
630 631 632 633
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
634
                    width: 100.0,
635 636
                    height: 100.0,
                  ),
637
                ),
638 639 640
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
641
                    width: 100.0,
642 643
                    height: 100.0,
                  ),
644
                ),
645 646 647
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
648
                    width: 100.0,
649 650 651
                    height: 100.0,
                  ),
                ),
652
              ],
653 654 655
            ),
          ),
        ),
656
      ),
657 658
    );

659
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
660 661
    expect(box.size.height, equals(300));

662 663 664
    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Sharp);
    matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Sharp);
    matches(getBorderRadius(tester, 2), RadiusType.Sharp, RadiusType.Round);
665 666

    await tester.pumpWidget(
667
      const MaterialApp(
668 669
        home: Scaffold(
          body: SingleChildScrollView(
670
            child: MergeableMaterial(
671 672 673 674
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
675
                    width: 100.0,
676 677
                    height: 100.0,
                  ),
678
                ),
679 680 681
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
682
                    width: 100.0,
683 684 685
                    height: 100.0,
                  ),
                ),
686
              ],
687 688 689
            ),
          ),
        ),
690
      ),
691 692 693 694 695
    );

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

696 697
    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Sharp);
    matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round);
698 699 700 701
  });

  testWidgets('MergeableMaterial insert chunk', (WidgetTester tester) async {
    await tester.pumpWidget(
702
      const MaterialApp(
703 704
        home: Scaffold(
          body: SingleChildScrollView(
705
            child: MergeableMaterial(
706 707 708 709
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
710
                    width: 100.0,
711 712
                    height: 100.0,
                  ),
713
                ),
714 715 716
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
717
                    width: 100.0,
718 719 720
                    height: 100.0,
                  ),
                ),
721
              ],
722 723 724
            ),
          ),
        ),
725
      ),
726 727
    );

728
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
729 730
    expect(box.size.height, equals(200));

731 732
    matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Sharp);
    matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round);
733 734

    await tester.pumpWidget(
735
      const MaterialApp(
736 737
        home: Scaffold(
          body: SingleChildScrollView(
738
            child: MergeableMaterial(
739 740 741 742
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
743
                    width: 100.0,
744 745
                    height: 100.0,
                  ),
746
                ),
747
                MaterialGap(
748
                  key: ValueKey<String>('x'),
749
                ),
750 751 752
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
753
                    width: 100.0,
754 755
                    height: 100.0,
                  ),
756
                ),
757
                MaterialGap(
758
                  key: ValueKey<String>('y'),
759
                ),
760 761 762
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
763
                    width: 100.0,
764 765 766
                    height: 100.0,
                  ),
                ),
767
              ],
768 769 770
            ),
          ),
        ),
771
      ),
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
    );

    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(
791
      const MaterialApp(
792 793
        home: Scaffold(
          body: SingleChildScrollView(
794
            child: MergeableMaterial(
795 796 797 798
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
799
                    width: 100.0,
800 801
                    height: 100.0,
                  ),
802
                ),
803
                MaterialGap(
804
                  key: ValueKey<String>('x'),
805
                ),
806 807 808
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
809
                    width: 100.0,
810 811
                    height: 100.0,
                  ),
812
                ),
813
                MaterialGap(
814
                  key: ValueKey<String>('y'),
815
                ),
816 817 818
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
819
                    width: 100.0,
820 821 822
                    height: 100.0,
                  ),
                ),
823
              ],
824 825 826
            ),
          ),
        ),
827
      ),
828 829
    );

830
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
831 832 833 834 835 836 837
    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(
838
      const MaterialApp(
839 840
        home: Scaffold(
          body: SingleChildScrollView(
841
            child: MergeableMaterial(
842 843 844 845
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
846
                    width: 100.0,
847 848
                    height: 100.0,
                  ),
849
                ),
850 851 852
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
853
                    width: 100.0,
854 855 856
                    height: 100.0,
                  ),
                ),
857
              ],
858 859 860
            ),
          ),
        ),
861
      ),
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
    );

    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(
879
      const MaterialApp(
880 881
        home: Scaffold(
          body: SingleChildScrollView(
882
            child: MergeableMaterial(
883 884 885 886
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
887
                    width: 100.0,
888 889
                    height: 100.0,
                  ),
890
                ),
891
                MaterialGap(
892
                  key: ValueKey<String>('x'),
893
                ),
894 895 896
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
897
                    width: 100.0,
898 899 900
                    height: 100.0,
                  ),
                ),
901
              ],
902 903 904
            ),
          ),
        ),
905
      ),
906 907
    );

908
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
909 910 911 912 913 914
    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(
915
      const MaterialApp(
916 917
        home: Scaffold(
          body: SingleChildScrollView(
918
            child: MergeableMaterial(
919 920 921 922
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
923
                    width: 100.0,
924 925
                    height: 100.0,
                  ),
926
                ),
927
                MaterialGap(
928
                  key: ValueKey<String>('y'),
929
                ),
930 931 932
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
933
                    width: 100.0,
934 935
                    height: 100.0,
                  ),
936
                ),
937
                MaterialGap(
938
                  key: ValueKey<String>('z'),
939
                ),
940 941 942
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
943
                    width: 100.0,
944 945 946
                    height: 100.0,
                  ),
                ),
947
              ],
948 949 950
            ),
          ),
        ),
951
      ),
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970
    );

    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(
971
      const MaterialApp(
972 973
        home: Scaffold(
          body: SingleChildScrollView(
974
            child: MergeableMaterial(
975 976 977 978
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
979
                    width: 100.0,
980 981
                    height: 100.0,
                  ),
982
                ),
983
                MaterialGap(
984
                  key: ValueKey<String>('x'),
985
                ),
986 987 988
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
989
                    width: 100.0,
990 991
                    height: 100.0,
                  ),
992
                ),
993
                MaterialGap(
994
                  key: ValueKey<String>('y'),
995
                ),
996 997 998
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
999
                    width: 100.0,
1000 1001 1002
                    height: 100.0,
                  ),
                ),
1003
              ],
1004 1005 1006
            ),
          ),
        ),
1007
      ),
1008 1009
    );

1010
    final RenderBox box = tester.renderObject(find.byType(MergeableMaterial));
1011 1012 1013 1014 1015 1016 1017
    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(
1018
      const MaterialApp(
1019 1020
        home: Scaffold(
          body: SingleChildScrollView(
1021
            child: MergeableMaterial(
1022 1023 1024 1025
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
1026
                    width: 100.0,
1027 1028
                    height: 100.0,
                  ),
1029
                ),
1030
                MaterialGap(
1031
                  key: ValueKey<String>('z'),
1032
                ),
1033 1034 1035
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
1036
                    width: 100.0,
1037 1038 1039
                    height: 100.0,
                  ),
                ),
1040
              ],
1041 1042 1043
            ),
          ),
        ),
1044
      ),
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
    );

    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);
  });
1059

1060
  bool isDivider(BoxDecoration decoration, bool top, bool bottom) {
1061
    const BorderSide side = BorderSide(color: Color(0x1F000000), width: 0.5);
1062

1063
    return decoration == BoxDecoration(
1064
      border: Border(
1065
        top: top ? side : BorderSide.none,
1066 1067
        bottom: bottom ? side : BorderSide.none,
      ),
1068 1069 1070 1071 1072
    );
  }

  testWidgets('MergeableMaterial dividers', (WidgetTester tester) async {
    await tester.pumpWidget(
1073
      const MaterialApp(
1074 1075
        home: Scaffold(
          body: SingleChildScrollView(
1076
            child: MergeableMaterial(
1077
              hasDividers: true,
1078 1079 1080 1081
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
1082
                    width: 100.0,
1083 1084
                    height: 100.0,
                  ),
1085
                ),
1086 1087 1088
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
1089
                    width: 100.0,
1090 1091
                    height: 100.0,
                  ),
1092
                ),
1093 1094 1095
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
1096
                    width: 100.0,
1097 1098
                    height: 100.0,
                  ),
1099
                ),
1100 1101 1102
                MaterialSlice(
                  key: ValueKey<String>('D'),
                  child: SizedBox(
1103
                    width: 100.0,
1104 1105 1106 1107 1108 1109 1110
                    height: 100.0,
                  ),
                ),
              ],
            ),
          ),
        ),
1111
      ),
1112 1113
    );

1114 1115 1116 1117 1118 1119 1120 1121 1122
    List<Widget> animatedContainers = tester.widgetList(
      find.byType(AnimatedContainer),
    ).toList();
    List<BoxDecoration> boxes = <BoxDecoration>[];
    for (final Widget container in animatedContainers) {
      boxes.add((container as AnimatedContainer).decoration! as BoxDecoration);
    }

    int offset = 0;
1123

1124 1125 1126 1127
    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);
1128 1129

    await tester.pumpWidget(
1130
      const MaterialApp(
1131 1132
        home: Scaffold(
          body: SingleChildScrollView(
1133
            child: MergeableMaterial(
1134
              hasDividers: true,
1135 1136 1137 1138
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
1139
                    width: 100.0,
1140 1141
                    height: 100.0,
                  ),
1142
                ),
1143 1144 1145
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
1146
                    width: 100.0,
1147 1148
                    height: 100.0,
                  ),
1149
                ),
1150
                MaterialGap(
1151
                  key: ValueKey<String>('x'),
1152
                ),
1153 1154 1155
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
1156
                    width: 100.0,
1157 1158
                    height: 100.0,
                  ),
1159
                ),
1160 1161 1162
                MaterialSlice(
                  key: ValueKey<String>('D'),
                  child: SizedBox(
1163
                    width: 100.0,
1164 1165 1166 1167 1168 1169 1170
                    height: 100.0,
                  ),
                ),
              ],
            ),
          ),
        ),
1171
      ),
1172 1173
    );

1174 1175 1176
    // Wait for dividers to shrink.
    await tester.pump(const Duration(milliseconds: 200));

1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
    animatedContainers = tester.widgetList(
      find.byType(AnimatedContainer),
    ).toList();
    boxes = <BoxDecoration>[];

    for (final Widget container in animatedContainers) {
      boxes.add((container as AnimatedContainer).decoration! as BoxDecoration);
    }

    offset = 0;
1187

1188 1189
    expect(isDivider(boxes[offset], false, true), isTrue);
    expect(isDivider(boxes[offset + 1], true, false), isTrue);
1190 1191
    expect(isDivider(boxes[offset + 2], false, true), isTrue);
    expect(isDivider(boxes[offset + 3], true, false), isTrue);
1192
  });
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227

  testWidgets('MergeableMaterial respects dividerColor', (WidgetTester tester) async {
    const Color dividerColor = Colors.red;
    await tester.pumpWidget(
      const MaterialApp(
        home: Scaffold(
          body: SingleChildScrollView(
            child: MergeableMaterial(
              hasDividers: true,
              dividerColor: dividerColor,
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  child: SizedBox(
                    width: 100.0,
                    height: 100.0,
                  ),
                ),
                MaterialSlice(
                  key: ValueKey<String>('B'),
                  child: SizedBox(
                    width: 100.0,
                    height: 100.0,
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );

    final DecoratedBox decoratedBox = tester.widget(find.byType(DecoratedBox).last);
    final BoxDecoration decoration = decoratedBox.decoration as BoxDecoration;
    // Since we are getting the last DecoratedBox, it will have a Border.top.
1228
    expect(decoration.border!.top.color, dividerColor);
1229
  });
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274

  testWidgets('MergeableMaterial respects MaterialSlice.color', (WidgetTester tester) async {
    const Color themeCardColor = Colors.red;
    const Color materialSliceColor = Colors.green;

    await tester.pumpWidget(
      MaterialApp(
        theme: ThemeData(
          cardColor: themeCardColor,
        ),
        home: const Scaffold(
          body: SingleChildScrollView(
            child: MergeableMaterial(
              children: <MergeableMaterialItem>[
                MaterialSlice(
                  key: ValueKey<String>('A'),
                  color: materialSliceColor,
                  child: SizedBox(
                    height: 100,
                    width: 100,
                  ),
                ),
                MaterialGap(
                  key: ValueKey<String>('B'),
                ),
                MaterialSlice(
                  key: ValueKey<String>('C'),
                  child: SizedBox(
                    height: 100,
                    width: 100,
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );

    BoxDecoration boxDecoration = tester.widget<Container>(find.byType(Container).first).decoration! as BoxDecoration;
    expect(boxDecoration.color, materialSliceColor);

    boxDecoration = tester.widget<Container>(find.byType(Container).last).decoration! as BoxDecoration;
    expect(boxDecoration.color, themeCardColor);
  });
1275
}