table_test.dart 32.3 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
Hixie's avatar
Hixie committed
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/material.dart';
6 7
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
Hixie's avatar
Hixie committed
8

9
class TestStatefulWidget extends StatefulWidget {
10
  const TestStatefulWidget({ Key? key }) : super(key: key);
11 12

  @override
13
  TestStatefulWidgetState createState() => TestStatefulWidgetState();
14 15 16 17
}

class TestStatefulWidgetState extends State<TestStatefulWidget> {
  @override
18
  Widget build(BuildContext context) => Container();
19 20
}

21
class TestChildWidget extends StatefulWidget {
22
  const TestChildWidget({ Key? key }) : super(key: key);
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

  @override
  TestChildState createState() => TestChildState();
}

class TestChildState extends State<TestChildWidget> {
  bool toggle = true;

  void toggleMe() {
    setState(() { toggle = !toggle; });
  }

  @override
  Widget build(BuildContext context) => toggle ? const SizedBox() : const Text('CRASHHH');
}

Hixie's avatar
Hixie committed
39
void main() {
40 41
  testWidgets('Table widget - empty', (WidgetTester tester) async {
    await tester.pumpWidget(
42
      Directionality(
43
        textDirection: TextDirection.ltr,
44
        child: Table(),
45 46 47
      ),
    );
  });
48
  testWidgets('Table widget - control test', (WidgetTester tester) async {
49
    Future<void> run(TextDirection textDirection) async {
50
      await tester.pumpWidget(
51
        Directionality(
52
          textDirection: textDirection,
53
          child: Table(
54
            children: const <TableRow>[
55 56 57
              TableRow(
                children: <Widget>[
                  Text('AAAAAA'), Text('B'), Text('C'),
58 59
                ],
              ),
60 61 62
              TableRow(
                children: <Widget>[
                  Text('D'), Text('EEE'), Text('F'),
63 64
                ],
              ),
65 66 67
              TableRow(
                children: <Widget>[
                  Text('G'), Text('H'), Text('III'),
68 69 70
                ],
              ),
            ],
71
          ),
72 73 74 75 76 77 78 79 80 81 82 83
        ),
      );
      final RenderBox boxA = tester.renderObject(find.text('AAAAAA'));
      final RenderBox boxD = tester.renderObject(find.text('D'));
      final RenderBox boxG = tester.renderObject(find.text('G'));
      final RenderBox boxB = tester.renderObject(find.text('B'));
      expect(boxA.size, equals(boxD.size));
      expect(boxA.size, equals(boxG.size));
      expect(boxA.size, equals(boxB.size));
    }

    await run(TextDirection.ltr);
84
    await tester.pumpWidget(Container());
85
    await run(TextDirection.rtl);
Hixie's avatar
Hixie committed
86
  });
87

88 89 90 91 92 93
  testWidgets('Table widget can be detached and re-attached', (WidgetTester tester) async {
    final Widget table = Table(
      key: GlobalKey(),
      children: const <TableRow>[
        TableRow(
          decoration: BoxDecoration(
94
              color: Colors.yellow,
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
          ),
          children: <Widget>[Placeholder()],
        ),
      ],
    );
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Center(
          child: table,
        ),
      ),
    );
    // Move table to a different location to simulate detaching and re-attaching effect.
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Center(
          child: Center(
114
            child: table,
115 116 117 118 119 120 121 122
          ),
        ),
      ),
    );

    expect(tester.takeException(), isNull);
  });

123 124
  testWidgets('Table widget - column offset (LTR)', (WidgetTester tester) async {
    await tester.pumpWidget(
125
      Directionality(
126
        textDirection: TextDirection.ltr,
127 128
        child: Center(
          child: Table(
129
            columnWidths: const <int, TableColumnWidth>{
130 131 132
              0: FixedColumnWidth(100.0),
              1: FixedColumnWidth(110.0),
              2: FixedColumnWidth(125.0),
133 134
            },
            defaultColumnWidth: const FixedColumnWidth(333.0),
135
            children: const <TableRow>[
136 137 138
              TableRow(
                children: <Widget>[
                  Text('A1'), Text('B1'), Text('C1'),
139 140
                ],
              ),
141 142 143
              TableRow(
                children: <Widget>[
                  Text('A2'), Text('B2'), Text('C2'),
144 145
                ],
              ),
146 147 148
              TableRow(
                children: <Widget>[
                  Text('A3'), Text('B3'), Text('C3'),
149 150 151
                ],
              ),
            ],
152
          ),
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
        ),
      ),
    );

    final Rect table = tester.getRect(find.byType(Table));
    final Rect a1 = tester.getRect(find.text('A1'));
    final Rect a2 = tester.getRect(find.text('A2'));
    final Rect a3 = tester.getRect(find.text('A3'));
    final Rect b1 = tester.getRect(find.text('B1'));
    final Rect b2 = tester.getRect(find.text('B2'));
    final Rect b3 = tester.getRect(find.text('B3'));
    final Rect c1 = tester.getRect(find.text('C1'));
    final Rect c2 = tester.getRect(find.text('C2'));
    final Rect c3 = tester.getRect(find.text('C3'));

    expect(a1.width, equals(100.0));
    expect(a2.width, equals(100.0));
    expect(a3.width, equals(100.0));
    expect(b1.width, equals(110.0));
    expect(b2.width, equals(110.0));
    expect(b3.width, equals(110.0));
    expect(c1.width, equals(125.0));
    expect(c2.width, equals(125.0));
    expect(c3.width, equals(125.0));

    expect(table.width, equals(335.0));

    expect(a1.left, equals(table.left));
    expect(a2.left, equals(a1.left));
    expect(a3.left, equals(a1.left));

    expect(b1.left, equals(table.left + a1.width));
    expect(b2.left, equals(b1.left));
    expect(b3.left, equals(b1.left));

    expect(c1.left, equals(table.left + a1.width + b1.width));
    expect(c2.left, equals(c1.left));
    expect(c3.left, equals(c1.left));
  });

  testWidgets('Table widget - column offset (RTL)', (WidgetTester tester) async {
    await tester.pumpWidget(
195
      Directionality(
196
        textDirection: TextDirection.rtl,
197 198
        child: Center(
          child: Table(
199
            columnWidths: const <int, TableColumnWidth>{
200 201 202
              0: FixedColumnWidth(100.0),
              1: FixedColumnWidth(110.0),
              2: FixedColumnWidth(125.0),
203 204
            },
            defaultColumnWidth: const FixedColumnWidth(333.0),
205
            children: const <TableRow>[
206 207 208
              TableRow(
                children: <Widget>[
                  Text('A1'), Text('B1'), Text('C1'),
209 210
                ],
              ),
211 212 213
              TableRow(
                children: <Widget>[
                  Text('A2'), Text('B2'), Text('C2'),
214 215
                ],
              ),
216 217 218
              TableRow(
                children: <Widget>[
                  Text('A3'), Text('B3'), Text('C3'),
219 220 221
                ],
              ),
            ],
222
          ),
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
        ),
      ),
    );

    final Rect table = tester.getRect(find.byType(Table));
    final Rect a1 = tester.getRect(find.text('A1'));
    final Rect a2 = tester.getRect(find.text('A2'));
    final Rect a3 = tester.getRect(find.text('A3'));
    final Rect b1 = tester.getRect(find.text('B1'));
    final Rect b2 = tester.getRect(find.text('B2'));
    final Rect b3 = tester.getRect(find.text('B3'));
    final Rect c1 = tester.getRect(find.text('C1'));
    final Rect c2 = tester.getRect(find.text('C2'));
    final Rect c3 = tester.getRect(find.text('C3'));

    expect(a1.width, equals(100.0));
    expect(a2.width, equals(100.0));
    expect(a3.width, equals(100.0));
    expect(b1.width, equals(110.0));
    expect(b2.width, equals(110.0));
    expect(b3.width, equals(110.0));
    expect(c1.width, equals(125.0));
    expect(c2.width, equals(125.0));
    expect(c3.width, equals(125.0));

    expect(table.width, equals(335.0));

    expect(a1.right, equals(table.right));
    expect(a2.right, equals(a1.right));
    expect(a3.right, equals(a1.right));

    expect(b1.right, equals(table.right - a1.width));
    expect(b2.right, equals(b1.right));
    expect(b3.right, equals(b1.right));

    expect(c1.right, equals(table.right - a1.width - b1.width));
    expect(c2.right, equals(c1.right));
    expect(c3.right, equals(c1.right));
  });

  testWidgets('Table border - smoke test', (WidgetTester tester) async {
264
    Future<void> run(TextDirection textDirection) async {
265
      await tester.pumpWidget(
266
        Directionality(
267
          textDirection: textDirection,
268 269
          child: Table(
            border: TableBorder.all(),
270
            children: const <TableRow>[
271 272 273
              TableRow(
                children: <Widget>[
                  Text('AAAAAA'), Text('B'), Text('C'),
274 275
                ],
              ),
276 277 278
              TableRow(
                children: <Widget>[
                  Text('D'), Text('EEE'), Text('F'),
279 280
                ],
              ),
281 282 283
              TableRow(
                children: <Widget>[
                  Text('G'), Text('H'), Text('III'),
284 285 286
                ],
              ),
            ],
287
          ),
288 289 290 291 292
        ),
      );
    }

    await run(TextDirection.ltr);
293
    await tester.pumpWidget(Container());
294 295 296 297 298
    await run(TextDirection.rtl);
  });

  testWidgets('Table widget - changing table dimensions', (WidgetTester tester) async {
    await tester.pumpWidget(
299
      Directionality(
300
        textDirection: TextDirection.ltr,
301
        child: Table(
302
          children: const <TableRow>[
303 304 305
            TableRow(
              children: <Widget>[
                Text('A'), Text('B'), Text('C'),
306 307
              ],
            ),
308 309 310
            TableRow(
              children: <Widget>[
                Text('D'), Text('E'), Text('F'),
311 312
              ],
            ),
313 314 315
            TableRow(
              children: <Widget>[
                Text('G'), Text('H'), Text('I'),
316 317 318 319 320 321
              ],
            ),
          ],
        ),
      ),
    );
322 323
    final RenderBox boxA1 = tester.renderObject(find.text('A'));
    final RenderBox boxG1 = tester.renderObject(find.text('G'));
324 325
    expect(boxA1, isNotNull);
    expect(boxG1, isNotNull);
326
    await tester.pumpWidget(
327
      Directionality(
328
        textDirection: TextDirection.ltr,
329
        child: Table(
330
          children: const <TableRow>[
331 332 333
            TableRow(
              children: <Widget>[
                Text('a'), Text('b'), Text('c'), Text('d'),
334 335
              ],
            ),
336 337 338
            TableRow(
              children: <Widget>[
                Text('e'), Text('f'), Text('g'), Text('h'),
339 340 341 342 343 344
              ],
            ),
          ],
        ),
      ),
    );
345 346
    final RenderBox boxA2 = tester.renderObject(find.text('a'));
    final RenderBox boxG2 = tester.renderObject(find.text('g'));
347 348 349 350
    expect(boxA2, isNotNull);
    expect(boxG2, isNotNull);
    expect(boxA1, equals(boxA2));
    expect(boxG1, isNot(equals(boxG2)));
Hixie's avatar
Hixie committed
351
  });
352

353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
  testWidgets('Really small deficit double precision error', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/27083
    const SizedBox cell = SizedBox(width: 16, height: 16);
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Table(
          children: const <TableRow>[
            TableRow(
              children: <Widget>[
                cell, cell, cell, cell, cell, cell,
              ],
            ),
            TableRow(
              children: <Widget>[
                cell, cell, cell, cell, cell, cell,
              ],
            ),
          ],
        ),
      ),
    );
    // If the above bug is present this test will never terminate.
  });

378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
  testWidgets('Calculating flex columns with small width deficit', (WidgetTester tester) async {
    const SizedBox cell = SizedBox(width: 1, height: 1);
    // If the error is present, pumpWidget() will fail due to an unsatisfied
    // assertion during the layout phase.
    await tester.pumpWidget(
      ConstrainedBox(
        constraints: BoxConstraints.tight(const Size(600, 800)),
        child: Directionality(
          textDirection: TextDirection.ltr,
          child: Table(
            columnWidths: const <int, TableColumnWidth>{
              0: FlexColumnWidth(1.0),
              1: FlexColumnWidth(0.123),
              2: FlexColumnWidth(0.123),
              3: FlexColumnWidth(0.123),
              4: FlexColumnWidth(0.123),
              5: FlexColumnWidth(0.123),
              6: FlexColumnWidth(0.123),
            },
            children: <TableRow>[
              TableRow(children: List<Widget>.filled(7, cell)),
              TableRow(children: List<Widget>.filled(7, cell)),
            ],
          ),
        ),
      ),
    );
    expect(tester.takeException(), null);
  });

408
  testWidgets('Table widget - repump test', (WidgetTester tester) async {
409
    await tester.pumpWidget(
410
      Directionality(
411
        textDirection: TextDirection.ltr,
412
        child: Table(
413
          children: const <TableRow>[
414 415 416
            TableRow(
              children: <Widget>[
                Text('AAAAAA'), Text('B'), Text('C'),
417 418
              ],
            ),
419 420 421
            TableRow(
              children: <Widget>[
                Text('D'), Text('EEE'), Text('F'),
422 423
              ],
            ),
424 425 426
            TableRow(
              children: <Widget>[
                Text('G'), Text('H'), Text('III'),
427 428 429 430 431 432 433
              ],
            ),
          ],
        ),
      ),
    );
    await tester.pumpWidget(
434
      Directionality(
435
        textDirection: TextDirection.ltr,
436
        child: Table(
437
          children: const <TableRow>[
438 439 440
            TableRow(
              children: <Widget>[
                Text('AAA'), Text('B'), Text('C'),
441 442
              ],
            ),
443 444 445
            TableRow(
              children: <Widget>[
                Text('D'), Text('E'), Text('FFFFFF'),
446 447
              ],
            ),
448 449 450
            TableRow(
              children: <Widget>[
                Text('G'), Text('H'), Text('III'),
451 452 453 454 455 456
              ],
            ),
          ],
        ),
      ),
    );
457 458 459 460
    final RenderBox boxA = tester.renderObject(find.text('AAA'));
    final RenderBox boxD = tester.renderObject(find.text('D'));
    final RenderBox boxG = tester.renderObject(find.text('G'));
    final RenderBox boxB = tester.renderObject(find.text('B'));
461 462 463
    expect(boxA.size, equals(boxD.size));
    expect(boxA.size, equals(boxG.size));
    expect(boxA.size, equals(boxB.size));
Hixie's avatar
Hixie committed
464
  });
465

466
  testWidgets('Table widget - intrinsic sizing test', (WidgetTester tester) async {
467
    await tester.pumpWidget(
468
      Directionality(
Ian Hickson's avatar
Ian Hickson committed
469
      textDirection: TextDirection.ltr,
470
        child: Table(
471
          defaultColumnWidth: const IntrinsicColumnWidth(),
472
          children: const <TableRow>[
473 474 475
            TableRow(
              children: <Widget>[
                Text('AAA'), Text('B'), Text('C'),
476 477
              ],
            ),
478 479 480
            TableRow(
              children: <Widget>[
                Text('D'), Text('E'), Text('FFFFFF'),
481 482
              ],
            ),
483 484 485
            TableRow(
              children: <Widget>[
                Text('G'), Text('H'), Text('III'),
486 487 488 489 490 491
              ],
            ),
          ],
        ),
      ),
    );
492 493 494 495
    final RenderBox boxA = tester.renderObject(find.text('AAA'));
    final RenderBox boxD = tester.renderObject(find.text('D'));
    final RenderBox boxG = tester.renderObject(find.text('G'));
    final RenderBox boxB = tester.renderObject(find.text('B'));
496 497 498 499
    expect(boxA.size, equals(boxD.size));
    expect(boxA.size, equals(boxG.size));
    expect(boxA.size.width, greaterThan(boxB.size.width));
    expect(boxA.size.height, equals(boxB.size.height));
Hixie's avatar
Hixie committed
500
  });
501

502
  testWidgets('Table widget - intrinsic sizing test, resizing', (WidgetTester tester) async {
503
    await tester.pumpWidget(
504
      Directionality(
505
        textDirection: TextDirection.ltr,
506
        child: Table(
507
          defaultColumnWidth: const IntrinsicColumnWidth(),
508
          children: const <TableRow>[
509 510 511
            TableRow(
              children: <Widget>[
                Text('AAAAAA'), Text('B'), Text('C'),
512 513
              ],
            ),
514 515 516
            TableRow(
              children: <Widget>[
                Text('D'), Text('EEE'), Text('F'),
517 518
              ],
            ),
519 520 521
            TableRow(
              children: <Widget>[
                Text('G'), Text('H'), Text('III'),
522 523 524 525 526 527 528
              ],
            ),
          ],
        ),
      ),
    );
    await tester.pumpWidget(
529
      Directionality(
530
        textDirection: TextDirection.ltr,
531
        child: Table(
532
          defaultColumnWidth: const IntrinsicColumnWidth(),
533
          children: const <TableRow>[
534 535 536
            TableRow(
              children: <Widget>[
                Text('A'), Text('B'), Text('C'),
537 538
              ],
            ),
539 540 541
            TableRow(
              children: <Widget>[
                Text('D'), Text('EEE'), Text('F'),
542 543
              ],
            ),
544 545 546
            TableRow(
              children: <Widget>[
                Text('G'), Text('H'), Text('III'),
547 548 549 550 551 552
              ],
            ),
          ],
        ),
      ),
    );
553 554 555 556
    final RenderBox boxA = tester.renderObject(find.text('A'));
    final RenderBox boxD = tester.renderObject(find.text('D'));
    final RenderBox boxG = tester.renderObject(find.text('G'));
    final RenderBox boxB = tester.renderObject(find.text('B'));
557 558 559 560
    expect(boxA.size, equals(boxD.size));
    expect(boxA.size, equals(boxG.size));
    expect(boxA.size.width, lessThan(boxB.size.width));
    expect(boxA.size.height, equals(boxB.size.height));
Hixie's avatar
Hixie committed
561
  });
562

563
  testWidgets('Table widget - intrinsic sizing test, changing column widths', (WidgetTester tester) async {
564
    await tester.pumpWidget(
565
      Directionality(
566
        textDirection: TextDirection.ltr,
567
        child: Table(
568
          children: const <TableRow>[
569 570 571
            TableRow(
              children: <Widget>[
                Text('AAA'), Text('B'), Text('C'),
572 573
              ],
            ),
574 575 576
            TableRow(
              children: <Widget>[
                Text('D'), Text('E'), Text('FFFFFF'),
577 578
              ],
            ),
579 580 581
            TableRow(
              children: <Widget>[
                Text('G'), Text('H'), Text('III'),
582 583 584 585 586 587 588
              ],
            ),
          ],
        ),
      ),
    );
    await tester.pumpWidget(
589
      Directionality(
590
        textDirection: TextDirection.ltr,
591
        child: Table(
592
          defaultColumnWidth: const IntrinsicColumnWidth(),
593
          children: const <TableRow>[
594 595 596
            TableRow(
              children: <Widget>[
                Text('AAA'), Text('B'), Text('C'),
597 598
              ],
            ),
599 600 601
            TableRow(
              children: <Widget>[
                Text('D'), Text('E'), Text('FFFFFF'),
602 603
              ],
            ),
604 605 606
            TableRow(
              children: <Widget>[
                Text('G'), Text('H'), Text('III'),
607 608 609
              ],
            ),
          ],
610
        ),
611 612
      ),
    );
613 614 615 616
    final RenderBox boxA = tester.renderObject(find.text('AAA'));
    final RenderBox boxD = tester.renderObject(find.text('D'));
    final RenderBox boxG = tester.renderObject(find.text('G'));
    final RenderBox boxB = tester.renderObject(find.text('B'));
617 618 619 620
    expect(boxA.size, equals(boxD.size));
    expect(boxA.size, equals(boxG.size));
    expect(boxA.size.width, greaterThan(boxB.size.width));
    expect(boxA.size.height, equals(boxB.size.height));
Hixie's avatar
Hixie committed
621
  });
622

623
  testWidgets('Table widget - moving test', (WidgetTester tester) async {
624
    final List<BuildContext> contexts = <BuildContext>[];
625
    await tester.pumpWidget(
626
      Directionality(
627
        textDirection: TextDirection.ltr,
628
        child: Table(
629
          children: <TableRow>[
630
            TableRow(
631 632
              key: const ValueKey<int>(1),
              children: <Widget>[
633
                StatefulBuilder(
634 635 636 637 638 639 640
                  builder: (BuildContext context, StateSetter setState) {
                    contexts.add(context);
                    return const Text('A');
                  },
                ),
              ],
            ),
641
            const TableRow(
642 643
              children: <Widget>[
                Text('b'),
644 645 646 647 648 649 650
              ],
            ),
          ],
        ),
      ),
    );
    await tester.pumpWidget(
651
      Directionality(
652
        textDirection: TextDirection.ltr,
653
        child: Table(
654
          children: <TableRow>[
655
            const TableRow(
656 657
              children: <Widget>[
                Text('b'),
658 659
              ],
            ),
660
            TableRow(
661 662
              key: const ValueKey<int>(1),
              children: <Widget>[
663
                StatefulBuilder(
664 665 666 667 668 669 670 671 672 673 674
                  builder: (BuildContext context, StateSetter setState) {
                    contexts.add(context);
                    return const Text('A');
                  },
                ),
              ],
            ),
          ],
        ),
      ),
    );
675 676
    expect(contexts.length, equals(2));
    expect(contexts[0], equals(contexts[1]));
Hixie's avatar
Hixie committed
677
  });
678 679

  testWidgets('Table widget - keyed rows', (WidgetTester tester) async {
680
    await tester.pumpWidget(
681
      Directionality(
682
        textDirection: TextDirection.ltr,
683
        child: Table(
684
          children: const <TableRow>[
685 686 687 688 689
            TableRow(
              key: ValueKey<int>(1),
              children: <Widget>[
                TestStatefulWidget(key: ValueKey<int>(11)),
                TestStatefulWidget(key: ValueKey<int>(12)),
690 691
              ],
            ),
692 693 694 695 696
            TableRow(
              key: ValueKey<int>(2),
              children: <Widget>[
                TestStatefulWidget(key: ValueKey<int>(21)),
                TestStatefulWidget(key: ValueKey<int>(22)),
697 698 699 700 701 702
              ],
            ),
          ],
        ),
      ),
    );
703

704 705 706 707
    final TestStatefulWidgetState state11 = tester.state(find.byKey(const ValueKey<int>(11)));
    final TestStatefulWidgetState state12 = tester.state(find.byKey(const ValueKey<int>(12)));
    final TestStatefulWidgetState state21 = tester.state(find.byKey(const ValueKey<int>(21)));
    final TestStatefulWidgetState state22 = tester.state(find.byKey(const ValueKey<int>(22)));
708 709 710 711 712 713

    expect(state11.mounted, isTrue);
    expect(state12.mounted, isTrue);
    expect(state21.mounted, isTrue);
    expect(state22.mounted, isTrue);

714
    await tester.pumpWidget(
715
      Directionality(
716
        textDirection: TextDirection.ltr,
717
        child: Table(
718
          children: const <TableRow>[
719 720 721 722 723
            TableRow(
              key: ValueKey<int>(2),
              children: <Widget>[
                TestStatefulWidget(key: ValueKey<int>(21)),
                TestStatefulWidget(key: ValueKey<int>(22)),
724 725 726 727 728 729
              ],
            ),
          ],
        ),
      ),
    );
730 731 732 733 734 735 736 737

    expect(state11.mounted, isFalse);
    expect(state12.mounted, isFalse);
    expect(state21.mounted, isTrue);
    expect(state22.mounted, isTrue);
  });

  testWidgets('Table widget - global key reparenting', (WidgetTester tester) async {
738 739
    final GlobalKey key = GlobalKey();
    final Key tableKey = UniqueKey();
740 741

    await tester.pumpWidget(
742
      Directionality(
743
        textDirection: TextDirection.ltr,
744
        child: Column(
745
          children: <Widget> [
746
            Expanded(
747
              key: tableKey,
748
              child: Table(
749
                children: <TableRow>[
750
                  TableRow(
751
                    children: <Widget>[
752 753 754
                      Container(key: const ValueKey<int>(1)),
                      TestStatefulWidget(key: key),
                      Container(key: const ValueKey<int>(2)),
755 756 757 758
                    ],
                  ),
                ],
              ),
759
            ),
760 761
          ],
        ),
762 763 764
      ),
    );

765
    final RenderTable table = tester.renderObject(find.byType(Table));
766 767 768
    expect(table.row(0).length, 3);

    await tester.pumpWidget(
769
      Directionality(
770
        textDirection: TextDirection.ltr,
771
        child: Column(
772
          children: <Widget> [
773 774
            Expanded(child: TestStatefulWidget(key: key)),
            Expanded(
775
              key: tableKey,
776
              child: Table(
777
                children: <TableRow>[
778
                  TableRow(
779
                    children: <Widget>[
780 781
                      Container(key: const ValueKey<int>(1)),
                      Container(key: const ValueKey<int>(2)),
782 783 784 785
                    ],
                  ),
                ],
              ),
786
            ),
787 788
          ],
        ),
789 790 791 792 793 794 795
      ),
    );

    expect(tester.renderObject(find.byType(Table)), equals(table));
    expect(table.row(0).length, 2);

    await tester.pumpWidget(
796
      Directionality(
797
        textDirection: TextDirection.ltr,
798
        child: Column(
799
          children: <Widget> [
800
            Expanded(
801
              key: tableKey,
802
              child: Table(
803
                children: <TableRow>[
804
                  TableRow(
805
                    children: <Widget>[
806 807 808
                      Container(key: const ValueKey<int>(1)),
                      TestStatefulWidget(key: key),
                      Container(key: const ValueKey<int>(2)),
809 810 811 812
                    ],
                  ),
                ],
              ),
813
            ),
814 815
          ],
        ),
816 817 818 819 820 821 822
      ),
    );

    expect(tester.renderObject(find.byType(Table)), equals(table));
    expect(table.row(0).length, 3);

    await tester.pumpWidget(
823
      Directionality(
824
        textDirection: TextDirection.ltr,
825
        child: Column(
826
          children: <Widget> [
827
            Expanded(
828
              key: tableKey,
829
              child: Table(
830
                children: <TableRow>[
831
                  TableRow(
832
                    children: <Widget>[
833 834
                      Container(key: const ValueKey<int>(1)),
                      Container(key: const ValueKey<int>(2)),
835 836 837 838
                    ],
                  ),
                ],
              ),
839
            ),
840
            Expanded(child: TestStatefulWidget(key: key)),
841 842
          ],
        ),
843 844 845 846 847 848 849
      ),
    );

    expect(tester.renderObject(find.byType(Table)), equals(table));
    expect(table.row(0).length, 2);
  });

850 851
  testWidgets('Table widget diagnostics', (WidgetTester tester) async {
    GlobalKey key0;
852
    final Widget table = Directionality(
Ian Hickson's avatar
Ian Hickson committed
853
      textDirection: TextDirection.ltr,
854 855
      child: Table(
        key: key0 = GlobalKey(),
856
        defaultColumnWidth: const IntrinsicColumnWidth(),
857
        children: const <TableRow>[
858 859 860
          TableRow(
            children: <Widget>[
              Text('A'), Text('B'), Text('C'),
Ian Hickson's avatar
Ian Hickson committed
861
            ],
862
          ),
863 864 865
          TableRow(
            children: <Widget>[
              Text('D'), Text('EEE'), Text('F'),
Ian Hickson's avatar
Ian Hickson committed
866
            ],
867
          ),
868 869 870
          TableRow(
            children: <Widget>[
              Text('G'), Text('H'), Text('III'),
Ian Hickson's avatar
Ian Hickson committed
871
            ],
872
          ),
Ian Hickson's avatar
Ian Hickson committed
873 874 875
        ],
      ),
    );
876
    await tester.pumpWidget(table);
877
    final RenderObjectElement element = key0.currentContext! as RenderObjectElement;
878 879
    expect(element, hasAGoodToStringDeep);
    expect(
880
      element.toStringDeep(minLevel: DiagnosticLevel.info),
881
      equalsIgnoringHashCodes(
882
        'Table-[GlobalKey#00000](dependencies: [Directionality], renderObject: RenderTable#00000)\n'
883
        '├Text("A")\n'
884
        '│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "A", dependencies: [Directionality], renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
885
        '├Text("B")\n'
886
        '│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "B", dependencies: [Directionality], renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
887
        '├Text("C")\n'
888
        '│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "C", dependencies: [Directionality], renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
889
        '├Text("D")\n'
890
        '│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "D", dependencies: [Directionality], renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
891
        '├Text("EEE")\n'
892
        '│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "EEE", dependencies: [Directionality], renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
893
        '├Text("F")\n'
894
        '│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "F", dependencies: [Directionality], renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
895
        '├Text("G")\n'
896
        '│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "G", dependencies: [Directionality], renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
897
        '├Text("H")\n'
898
        '│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "H", dependencies: [Directionality], renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
899
        '└Text("III")\n'
900
        ' └RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "III", dependencies: [Directionality], renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n',
901 902
      ),
    );
903 904
  });

905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
  // Regression test for https://github.com/flutter/flutter/issues/31473.
  testWidgets(
    'Does not crash if a child RenderObject is replaced by another RenderObject of a different type',
    (WidgetTester tester) async {
      await tester.pumpWidget(
        Directionality(
          textDirection: TextDirection.ltr,
          child: Table(children: const <TableRow>[TableRow(children: <Widget>[TestChildWidget()])]),
        ),
      );
      expect(find.text('CRASHHH'), findsNothing);

      final TestChildState state = tester.state(find.byType(TestChildWidget));
      state.toggleMe();

      await tester.pumpWidget(
        Directionality(
          textDirection: TextDirection.ltr,
          child: Table(children: const <TableRow>[TableRow(children: <Widget>[TestChildWidget()])]),
        ),
      );

      // Should not crash.
      expect(find.text('CRASHHH'), findsOneWidget);
929
    },
930 931
  );

932 933 934 935 936 937 938 939 940
  testWidgets('Table widget - Default textBaseline is null', (WidgetTester tester) async {
    expect(
      () => Table(defaultVerticalAlignment: TableCellVerticalAlignment.baseline),
      throwsA(
        isAssertionError
          .having((AssertionError error) => error.message, 'exception message', contains('baseline')),
      ),
    );
  });
941

942 943 944
  testWidgets(
    'Table widget requires all TableRows to have non-null children',
    (WidgetTester tester) async {
945
      FlutterError? error;
946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961
      try {
        await tester.pumpWidget(
          Directionality(
            textDirection: TextDirection.ltr,
            child: Table(
              children: const <TableRow>[
                TableRow(children: <Widget>[Text('Some Text')]),
                TableRow(),
              ],
            ),
          ),
        );
      } on FlutterError catch (e) {
        error = e;
      } finally {
        expect(error, isNotNull);
962
        expect(error!.toStringDeep(), contains('The children property of TableRow must not be null.'));
963
      }
964 965
    },
  );
966

967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
  testWidgets('Can replace child with a different RenderObject type', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/69395.
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Table(children: const <TableRow>[
          TableRow(children: <Widget>[
            TestChildWidget(),
            TestChildWidget(),
            TestChildWidget(),
          ]),
          TableRow(children: <Widget>[
            TestChildWidget(),
            TestChildWidget(),
            TestChildWidget(),
          ]),
        ]),
      ),
    );
    final RenderTable table = tester.renderObject(find.byType(Table));

    expect(find.text('CRASHHH'), findsNothing);
    expect(find.byType(SizedBox), findsNWidgets(3 * 2));
    final Type toBeReplaced = table.column(2).last.runtimeType;

    final TestChildState state = tester.state(find.byType(TestChildWidget).last);
    state.toggleMe();
    await tester.pump();

    expect(find.byType(SizedBox), findsNWidgets(5));
    expect(find.text('CRASHHH'), findsOneWidget);

    // The RenderObject got replaced by a different type.
    expect(table.column(2).last.runtimeType, isNot(toBeReplaced));
  });

1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
  testWidgets('Do not crash if a child that has not been layed out in a previous build is removed', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/60488.
    Widget buildTable(Key key) {
      return Directionality(
        textDirection: TextDirection.ltr,
        child: Table(
          children: <TableRow>[
            TableRow(
              children: <Widget>[
                KeyedSubtree(
                  key: key,
                  child: const Text('Hello'),
                ),
              ],
            ),
          ],
        ),
      );
    }

    await tester.pumpWidget(
      buildTable(const ValueKey<int>(1)),
      null, EnginePhase.build, // Children are not layed out!
    );

    await tester.pumpWidget(
      buildTable(const ValueKey<int>(2)),
    );

    expect(tester.takeException(), isNull);
    expect(find.text('Hello'), findsOneWidget);
  });

Hixie's avatar
Hixie committed
1036 1037
  // TODO(ianh): Test handling of TableCell object
}