stack_test.dart 27.8 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 6
// @dart = 2.8

Adam Barth's avatar
Adam Barth committed
7
import 'package:flutter_test/flutter_test.dart';
8
import 'package:flutter/rendering.dart';
9
import 'package:flutter/widgets.dart';
10

11
import '../rendering/rendering_tester.dart';
12

13 14 15 16
class TestPaintingContext implements PaintingContext {
  final List<Invocation> invocations = <Invocation>[];

  @override
17 18 19
  void noSuchMethod(Invocation invocation) {
    invocations.add(invocation);
  }
20 21
}

22
void main() {
23
  testWidgets('Can construct an empty Stack', (WidgetTester tester) async {
24
    await tester.pumpWidget(
25
      Directionality(
26
        textDirection: TextDirection.ltr,
27
        child: Stack(),
28 29
      ),
    );
Hans Muller's avatar
Hans Muller committed
30 31
  });

32
  testWidgets('Can construct an empty Centered Stack', (WidgetTester tester) async {
33
    await tester.pumpWidget(
34
      Directionality(
35
        textDirection: TextDirection.ltr,
36
        child: Center(child: Stack()),
37 38
      ),
    );
39 40
  });

41
  testWidgets('Can change position data', (WidgetTester tester) async {
42
    const Key key = Key('container');
43

44
    await tester.pumpWidget(
45
      Stack(
46
        alignment: Alignment.topLeft,
47
        children: <Widget>[
48
          Positioned(
49
            left: 10.0,
50
            child: Container(
51 52
              key: key,
              width: 10.0,
53 54 55 56 57
              height: 10.0,
            ),
          ),
        ],
      ),
58 59 60 61 62 63
    );

    Element container;
    StackParentData parentData;

    container = tester.element(find.byKey(key));
64
    parentData = container.renderObject.parentData as StackParentData;
65 66 67 68 69 70 71
    expect(parentData.top, isNull);
    expect(parentData.right, isNull);
    expect(parentData.bottom, isNull);
    expect(parentData.left, equals(10.0));
    expect(parentData.width, isNull);
    expect(parentData.height, isNull);

72
    await tester.pumpWidget(
73
      Stack(
74
        alignment: Alignment.topLeft,
75
        children: <Widget>[
76
          Positioned(
77
            right: 10.0,
78
            child: Container(
79 80
              key: key,
              width: 10.0,
81 82 83 84 85
              height: 10.0,
            ),
          ),
        ],
      ),
86 87 88
    );

    container = tester.element(find.byKey(key));
89
    parentData = container.renderObject.parentData as StackParentData;
90 91 92 93 94 95
    expect(parentData.top, isNull);
    expect(parentData.right, equals(10.0));
    expect(parentData.bottom, isNull);
    expect(parentData.left, isNull);
    expect(parentData.width, isNull);
    expect(parentData.height, isNull);
96
  });
97

98
  testWidgets('Can remove parent data', (WidgetTester tester) async {
99
    const Key key = Key('container');
100
    final Container container = Container(key: key, width: 10.0, height: 10.0);
101

102
    await tester.pumpWidget(
103
      Stack(
104
        textDirection: TextDirection.ltr,
105
        children: <Widget>[ Positioned(left: 10.0, child: container) ],
106 107
      ),
    );
108 109 110
    Element containerElement = tester.element(find.byKey(key));

    StackParentData parentData;
111
    parentData = containerElement.renderObject.parentData as StackParentData;
112 113 114 115 116 117 118
    expect(parentData.top, isNull);
    expect(parentData.right, isNull);
    expect(parentData.bottom, isNull);
    expect(parentData.left, equals(10.0));
    expect(parentData.width, isNull);
    expect(parentData.height, isNull);

119
    await tester.pumpWidget(
120
      Stack(
121 122 123 124
        textDirection: TextDirection.ltr,
        children: <Widget>[ container ],
      ),
    );
125 126
    containerElement = tester.element(find.byKey(key));

127
    parentData = containerElement.renderObject.parentData as StackParentData;
128 129 130 131 132 133
    expect(parentData.top, isNull);
    expect(parentData.right, isNull);
    expect(parentData.bottom, isNull);
    expect(parentData.left, isNull);
    expect(parentData.width, isNull);
    expect(parentData.height, isNull);
134
  });
Hans Muller's avatar
Hans Muller committed
135

136
  testWidgets('Can align non-positioned children (LTR)', (WidgetTester tester) async {
137 138
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
139

140
    await tester.pumpWidget(
141
      Directionality(
142
        textDirection: TextDirection.ltr,
143 144
        child: Center(
          child: Stack(
145
            alignment: Alignment.center,
146
            children: <Widget>[
147 148
              Container(key: child0Key, width: 20.0, height: 20.0),
              Container(key: child1Key, width: 10.0, height: 10.0),
149 150 151 152
            ],
          ),
        ),
      ),
153
    );
Hans Muller's avatar
Hans Muller committed
154

155
    final Element child0 = tester.element(find.byKey(child0Key));
156
    final StackParentData child0RenderObjectParentData = child0.renderObject.parentData as StackParentData;
157
    expect(child0RenderObjectParentData.offset, equals(const Offset(0.0, 0.0)));
Hans Muller's avatar
Hans Muller committed
158

159
    final Element child1 = tester.element(find.byKey(child1Key));
160
    final StackParentData child1RenderObjectParentData = child1.renderObject.parentData as StackParentData;
161
    expect(child1RenderObjectParentData.offset, equals(const Offset(5.0, 5.0)));
162 163

    await tester.pumpWidget(
164
      Directionality(
165
        textDirection: TextDirection.ltr,
166 167
        child: Center(
          child: Stack(
168
            alignment: AlignmentDirectional.bottomEnd,
169
            children: <Widget>[
170 171
              Container(key: child0Key, width: 20.0, height: 20.0),
              Container(key: child1Key, width: 10.0, height: 10.0),
172 173 174 175 176 177 178 179 180 181 182
            ],
          ),
        ),
      ),
    );

    expect(child0RenderObjectParentData.offset, equals(const Offset(0.0, 0.0)));
    expect(child1RenderObjectParentData.offset, equals(const Offset(10.0, 10.0)));
  });

  testWidgets('Can align non-positioned children (RTL)', (WidgetTester tester) async {
183 184
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
185 186

    await tester.pumpWidget(
187
      Directionality(
188
        textDirection: TextDirection.rtl,
189 190
        child: Center(
          child: Stack(
191
            alignment: Alignment.center,
192
            children: <Widget>[
193 194
              Container(key: child0Key, width: 20.0, height: 20.0),
              Container(key: child1Key, width: 10.0, height: 10.0),
195 196 197 198 199 200 201
            ],
          ),
        ),
      ),
    );

    final Element child0 = tester.element(find.byKey(child0Key));
202
    final StackParentData child0RenderObjectParentData = child0.renderObject.parentData as StackParentData;
203 204 205
    expect(child0RenderObjectParentData.offset, equals(const Offset(0.0, 0.0)));

    final Element child1 = tester.element(find.byKey(child1Key));
206
    final StackParentData child1RenderObjectParentData = child1.renderObject.parentData as StackParentData;
207 208 209
    expect(child1RenderObjectParentData.offset, equals(const Offset(5.0, 5.0)));

    await tester.pumpWidget(
210
      Directionality(
211
        textDirection: TextDirection.rtl,
212 213
        child: Center(
          child: Stack(
214
            alignment: AlignmentDirectional.bottomEnd,
215
            children: <Widget>[
216 217
              Container(key: child0Key, width: 20.0, height: 20.0),
              Container(key: child1Key, width: 10.0, height: 10.0),
218 219 220 221 222 223 224 225
            ],
          ),
        ),
      ),
    );

    expect(child0RenderObjectParentData.offset, equals(const Offset(0.0, 0.0)));
    expect(child1RenderObjectParentData.offset, equals(const Offset(0.0, 10.0)));
Hans Muller's avatar
Hans Muller committed
226 227
  });

228
  testWidgets('Can construct an empty IndexedStack', (WidgetTester tester) async {
229
    await tester.pumpWidget(
230
      Directionality(
231
        textDirection: TextDirection.ltr,
232
        child: IndexedStack(),
233 234
      ),
    );
Hans Muller's avatar
Hans Muller committed
235 236
  });

237
  testWidgets('Can construct an empty Centered IndexedStack', (WidgetTester tester) async {
238
    await tester.pumpWidget(
239
      Directionality(
240
        textDirection: TextDirection.ltr,
241
        child: Center(child: IndexedStack()),
242 243
      ),
    );
244 245
  });

246
  testWidgets('Can construct an IndexedStack', (WidgetTester tester) async {
247
    const int itemCount = 3;
248 249 250 251
    List<int> itemsPainted;

    Widget buildFrame(int index) {
      itemsPainted = <int>[];
252 253 254 255
      final List<Widget> items = List<Widget>.generate(itemCount, (int i) {
        return CustomPaint(
          child: Text('$i', textDirection: TextDirection.ltr),
          painter: TestCallbackPainter(
256
            onPaint: () { itemsPainted.add(i); }
257
          ),
258 259
        );
      });
260 261
      return Center(
        child: IndexedStack(
262
          alignment: Alignment.topLeft,
263 264 265 266
          children: items,
          index: index,
        ),
      );
267 268
    }

269
    await tester.pumpWidget(buildFrame(0));
270 271 272
    expect(find.text('0'), findsOneWidget);
    expect(find.text('1'), findsOneWidget);
    expect(find.text('2'), findsOneWidget);
273
    expect(itemsPainted, equals(<int>[0]));
274

275
    await tester.pumpWidget(buildFrame(1));
276
    expect(itemsPainted, equals(<int>[1]));
277

278
    await tester.pumpWidget(buildFrame(2));
279
    expect(itemsPainted, equals(<int>[2]));
Hans Muller's avatar
Hans Muller committed
280 281
  });

282
  testWidgets('Can hit test an IndexedStack', (WidgetTester tester) async {
283
    const Key key = Key('indexedStack');
284
    const int itemCount = 3;
285 286 287 288
    List<int> itemsTapped;

    Widget buildFrame(int index) {
      itemsTapped = <int>[];
289 290
      final List<Widget> items = List<Widget>.generate(itemCount, (int i) {
        return GestureDetector(child: Text('$i', textDirection: TextDirection.ltr), onTap: () { itemsTapped.add(i); });
291
      });
292 293
      return Center(
        child: IndexedStack(
294
          alignment: Alignment.topLeft,
295 296 297 298 299
          children: items,
          key: key,
          index: index,
        ),
      );
300 301
    }

302
    await tester.pumpWidget(buildFrame(0));
303
    expect(itemsTapped, isEmpty);
304
    await tester.tap(find.byKey(key));
305
    expect(itemsTapped, <int>[0]);
306

307
    await tester.pumpWidget(buildFrame(2));
308
    expect(itemsTapped, isEmpty);
309
    await tester.tap(find.byKey(key));
310
    expect(itemsTapped, <int>[2]);
Hans Muller's avatar
Hans Muller committed
311 312
  });

313
  testWidgets('Can set width and height', (WidgetTester tester) async {
314
    const Key key = Key('container');
315

316 317
    const BoxDecoration kBoxDecoration = BoxDecoration(
      color: Color(0xFF00FF00),
318 319
    );

320
    await tester.pumpWidget(
321
      Stack(
322
        textDirection: TextDirection.ltr,
323
        children: const <Widget>[
324
          Positioned(
325 326 327
            left: 10.0,
            width: 11.0,
            height: 12.0,
328
            child: DecoratedBox(key: key, decoration: kBoxDecoration),
329 330 331
          ),
        ],
      ),
332 333 334 335 336 337 338
    );

    Element box;
    RenderBox renderBox;
    StackParentData parentData;

    box = tester.element(find.byKey(key));
339 340
    renderBox = box.renderObject as RenderBox;
    parentData = renderBox.parentData as StackParentData;
341 342 343 344 345 346 347 348 349 350 351
    expect(parentData.top, isNull);
    expect(parentData.right, isNull);
    expect(parentData.bottom, isNull);
    expect(parentData.left, equals(10.0));
    expect(parentData.width, equals(11.0));
    expect(parentData.height, equals(12.0));
    expect(parentData.offset.dx, equals(10.0));
    expect(parentData.offset.dy, equals(0.0));
    expect(renderBox.size.width, equals(11.0));
    expect(renderBox.size.height, equals(12.0));

352
    await tester.pumpWidget(
353
      Stack(
354
        textDirection: TextDirection.ltr,
355
        children: const <Widget>[
356
          Positioned(
357 358 359
            right: 10.0,
            width: 11.0,
            height: 12.0,
360
            child: DecoratedBox(key: key, decoration: kBoxDecoration),
361 362 363
          ),
        ],
      ),
364 365 366
    );

    box = tester.element(find.byKey(key));
367 368
    renderBox = box.renderObject as RenderBox;
    parentData = renderBox.parentData as StackParentData;
369 370 371 372 373 374 375 376 377 378
    expect(parentData.top, isNull);
    expect(parentData.right, equals(10.0));
    expect(parentData.bottom, isNull);
    expect(parentData.left, isNull);
    expect(parentData.width, equals(11.0));
    expect(parentData.height, equals(12.0));
    expect(parentData.offset.dx, equals(779.0));
    expect(parentData.offset.dy, equals(0.0));
    expect(renderBox.size.width, equals(11.0));
    expect(renderBox.size.height, equals(12.0));
379 380
  });

381 382 383 384 385 386 387 388 389
  testWidgets('Can set and update clipBehavior', (WidgetTester tester) async {
    await tester.pumpWidget(Stack(textDirection: TextDirection.ltr));
    final RenderStack renderObject = tester.allRenderObjects.whereType<RenderStack>().first;
    expect(renderObject.clipBehavior, equals(Clip.hardEdge));

    await tester.pumpWidget(Stack(textDirection: TextDirection.ltr, clipBehavior: Clip.hardEdge));
    expect(renderObject.clipBehavior, equals(Clip.hardEdge));
  });

390 391 392 393
  testWidgets('IndexedStack with null index', (WidgetTester tester) async {
    bool tapped;

    await tester.pumpWidget(
394
      Directionality(
395
        textDirection: TextDirection.ltr,
396 397
        child: Center(
          child: IndexedStack(
398 399
            index: null,
            children: <Widget>[
400
              GestureDetector(
401
                behavior: HitTestBehavior.opaque,
Ian Hickson's avatar
Ian Hickson committed
402
                onTap: () { tapped = true; },
403 404 405 406
                child: const SizedBox(
                  width: 200.0,
                  height: 200.0,
                ),
407
              ),
408 409
            ],
          ),
410 411 412 413 414
        ),
      ),
    );

    await tester.tap(find.byType(IndexedStack));
415
    final RenderBox box = tester.renderObject(find.byType(IndexedStack));
416 417 418 419
    expect(box.size, equals(const Size(200.0, 200.0)));
    expect(tapped, isNull);
  });

420 421
  testWidgets('Stack clip test', (WidgetTester tester) async {
    await tester.pumpWidget(
422
      Directionality(
423
        textDirection: TextDirection.ltr,
424 425
        child: Center(
          child: Stack(
426
            clipBehavior: Clip.hardEdge,
427 428
            children: const <Widget>[
              SizedBox(
429 430 431
                width: 100.0,
                height: 100.0,
              ),
432
              Positioned(
433 434
                top: 0.0,
                left: 0.0,
435
                child: SizedBox(
436 437 438 439 440 441 442 443
                  width: 200.0,
                  height: 200.0,
                ),
              ),
            ],
          ),
        ),
      ),
444 445 446
    );

    RenderBox box = tester.renderObject(find.byType(Stack));
447
    TestPaintingContext context = TestPaintingContext();
448 449 450 451
    box.paint(context, Offset.zero);
    expect(context.invocations.first.memberName, equals(#pushClipRect));

    await tester.pumpWidget(
452
      Directionality(
453
        textDirection: TextDirection.ltr,
454 455
        child: Center(
          child: Stack(
456
            overflow: Overflow.visible,
457
            clipBehavior: Clip.none,
458 459
            children: const <Widget>[
              SizedBox(
460 461 462
                width: 100.0,
                height: 100.0,
              ),
463
              Positioned(
464 465
                top: 0.0,
                left: 0.0,
466
                child: SizedBox(
467 468 469 470 471 472 473 474
                  width: 200.0,
                  height: 200.0,
                ),
              ),
            ],
          ),
        ),
      ),
475 476 477
    );

    box = tester.renderObject(find.byType(Stack));
478
    context = TestPaintingContext();
479 480 481
    box.paint(context, Offset.zero);
    expect(context.invocations.first.memberName, equals(#paintChild));
  });
482 483 484 485

  testWidgets('Stack sizing: default', (WidgetTester tester) async {
    final List<String> logs = <String>[];
    await tester.pumpWidget(
486
      Directionality(
487
        textDirection: TextDirection.ltr,
488 489
        child: Center(
          child: ConstrainedBox(
490 491 492 493 494 495
            constraints: const BoxConstraints(
              minWidth: 2.0,
              maxWidth: 3.0,
              minHeight: 5.0,
              maxHeight: 7.0,
            ),
496
            child: Stack(
497
              children: <Widget>[
498
                LayoutBuilder(
499 500 501 502 503 504 505
                  builder: (BuildContext context, BoxConstraints constraints) {
                    logs.add(constraints.toString());
                    return const Placeholder();
                  },
                ),
              ],
            ),
506 507 508 509 510 511 512 513 514 515
          ),
        ),
      ),
    );
    expect(logs, <String>['BoxConstraints(0.0<=w<=3.0, 0.0<=h<=7.0)']);
  });

  testWidgets('Stack sizing: explicit', (WidgetTester tester) async {
    final List<String> logs = <String>[];
    Widget buildStack(StackFit sizing) {
516
      return Directionality(
517
        textDirection: TextDirection.ltr,
518 519
        child: Center(
          child: ConstrainedBox(
520 521 522 523 524 525
            constraints: const BoxConstraints(
              minWidth: 2.0,
              maxWidth: 3.0,
              minHeight: 5.0,
              maxHeight: 7.0,
            ),
526
            child: Stack(
527 528
              fit: sizing,
              children: <Widget>[
529
                LayoutBuilder(
530 531 532 533 534 535 536
                  builder: (BuildContext context, BoxConstraints constraints) {
                    logs.add(constraints.toString());
                    return const Placeholder();
                  },
                ),
              ],
            ),
537 538 539 540 541 542 543 544 545 546 547 548 549 550
          ),
        ),
      );
    }
    await tester.pumpWidget(buildStack(StackFit.loose));
    logs.add('=1=');
    await tester.pumpWidget(buildStack(StackFit.expand));
    logs.add('=2=');
    await tester.pumpWidget(buildStack(StackFit.passthrough));
    expect(logs, <String>[
      'BoxConstraints(0.0<=w<=3.0, 0.0<=h<=7.0)',
      '=1=',
      'BoxConstraints(w=3.0, h=7.0)',
      '=2=',
551
      'BoxConstraints(2.0<=w<=3.0, 5.0<=h<=7.0)',
552 553
    ]);
  });
554 555

  testWidgets('Positioned.directional control test', (WidgetTester tester) async {
556
    final Key key = UniqueKey();
557
    await tester.pumpWidget(
558
      Directionality(
559
        textDirection: TextDirection.ltr,
560
        child: Stack(
561
          children: <Widget>[
562
            Positioned.directional(
563 564
              textDirection: TextDirection.rtl,
              start: 50.0,
565
              child: Container(key: key, width: 75.0, height: 175.0),
566 567
            ),
          ],
568
        ),
569 570
      ),
    );
571 572 573

    expect(tester.getTopLeft(find.byKey(key)), const Offset(675.0, 0.0));

574
    await tester.pumpWidget(
575
      Directionality(
576
        textDirection: TextDirection.ltr,
577
        child: Stack(
578
          children: <Widget>[
579
            Positioned.directional(
580 581
              textDirection: TextDirection.ltr,
              start: 50.0,
582
              child: Container(key: key, width: 75.0, height: 175.0),
583 584
            ),
          ],
585
        ),
586 587
      ),
    );
588 589 590 591 592

    expect(tester.getTopLeft(find.byKey(key)), const Offset(50.0, 0.0));
  });

  testWidgets('PositionedDirectional control test', (WidgetTester tester) async {
593
    final Key key = UniqueKey();
594
    await tester.pumpWidget(
595
      Directionality(
596
        textDirection: TextDirection.rtl,
597
        child: Stack(
598
          children: <Widget>[
599
            PositionedDirectional(
600
              start: 50.0,
601
              child: Container(key: key, width: 75.0, height: 175.0),
602 603 604
            ),
          ],
        ),
605
      ),
606 607 608 609 610
    );

    expect(tester.getTopLeft(find.byKey(key)), const Offset(675.0, 0.0));

    await tester.pumpWidget(
611
      Directionality(
612
        textDirection: TextDirection.ltr,
613
        child: Stack(
614
          children: <Widget>[
615
            PositionedDirectional(
616
              start: 50.0,
617
              child: Container(key: key, width: 75.0, height: 175.0),
618 619 620
            ),
          ],
        ),
621
      ),
622 623 624 625
    );

    expect(tester.getTopLeft(find.byKey(key)), const Offset(50.0, 0.0));
  });
Ian Hickson's avatar
Ian Hickson committed
626 627 628

  testWidgets('Can change the text direction of a Stack', (WidgetTester tester) async {
    await tester.pumpWidget(
629
      Stack(
630
        alignment: Alignment.center,
Ian Hickson's avatar
Ian Hickson committed
631 632 633
      ),
    );
    await tester.pumpWidget(
634
      Stack(
635
        alignment: AlignmentDirectional.topStart,
Ian Hickson's avatar
Ian Hickson committed
636 637 638 639
        textDirection: TextDirection.rtl,
      ),
    );
    await tester.pumpWidget(
640
      Stack(
641
        alignment: Alignment.center,
Ian Hickson's avatar
Ian Hickson committed
642 643 644
      ),
    );
  });
645 646 647

  testWidgets('Alignment with partially-positioned children', (WidgetTester tester) async {
    await tester.pumpWidget(
648
      Directionality(
649
        textDirection: TextDirection.rtl,
650
        child: Stack(
651
          alignment: Alignment.center,
652
          children: const <Widget>[
653 654 655 656 657 658 659 660 661
            SizedBox(width: 100.0, height: 100.0),
            Positioned(left: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            Positioned(right: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            Positioned(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            Positioned(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(start: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(end: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
662 663 664 665
          ],
        ),
      ),
    );
Dan Field's avatar
Dan Field committed
666 667 668 669 670 671 672 673 674
    expect(tester.getRect(find.byType(SizedBox).at(0)), const Rect.fromLTWH(350.0, 250.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(1)), const Rect.fromLTWH(0.0,   250.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(2)), const Rect.fromLTWH(700.0, 250.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(3)), const Rect.fromLTWH(350.0, 0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(4)), const Rect.fromLTWH(350.0, 500.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(5)), const Rect.fromLTWH(700.0, 250.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(6)), const Rect.fromLTWH(0.0,   250.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(7)), const Rect.fromLTWH(350.0, 0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(8)), const Rect.fromLTWH(350.0, 500.0, 100.0, 100.0));
675 676

    await tester.pumpWidget(
677
      Directionality(
678
        textDirection: TextDirection.ltr,
679
        child: Stack(
680
          alignment: Alignment.center,
681
          children: const <Widget>[
682 683 684 685 686 687 688 689 690
            SizedBox(width: 100.0, height: 100.0),
            Positioned(left: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            Positioned(right: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            Positioned(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            Positioned(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(start: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(end: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
691 692 693 694
          ],
        ),
      ),
    );
Dan Field's avatar
Dan Field committed
695 696 697 698 699 700 701 702 703
    expect(tester.getRect(find.byType(SizedBox).at(0)), const Rect.fromLTWH(350.0, 250.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(1)), const Rect.fromLTWH(0.0,   250.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(2)), const Rect.fromLTWH(700.0, 250.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(3)), const Rect.fromLTWH(350.0, 0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(4)), const Rect.fromLTWH(350.0, 500.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(5)), const Rect.fromLTWH(0.0,   250.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(6)), const Rect.fromLTWH(700.0, 250.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(7)), const Rect.fromLTWH(350.0, 0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(8)), const Rect.fromLTWH(350.0, 500.0, 100.0, 100.0));
704 705

    await tester.pumpWidget(
706
      Directionality(
707
        textDirection: TextDirection.ltr,
708
        child: Stack(
709
          alignment: Alignment.bottomRight,
710
          children: const <Widget>[
711 712 713 714 715 716 717 718 719
            SizedBox(width: 100.0, height: 100.0),
            Positioned(left: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            Positioned(right: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            Positioned(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            Positioned(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(start: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(end: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
720 721 722 723
          ],
        ),
      ),
    );
Dan Field's avatar
Dan Field committed
724 725 726 727 728 729 730 731 732
    expect(tester.getRect(find.byType(SizedBox).at(0)), const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(1)), const Rect.fromLTWH(0.0,   500.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(2)), const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(3)), const Rect.fromLTWH(700.0, 0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(4)), const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(5)), const Rect.fromLTWH(0.0,   500.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(6)), const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(7)), const Rect.fromLTWH(700.0, 0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(8)), const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0));
733 734

    await tester.pumpWidget(
735
      Directionality(
736
        textDirection: TextDirection.ltr,
737
        child: Stack(
738
          alignment: Alignment.topLeft,
739
          children: const <Widget>[
740 741 742 743 744 745 746 747 748
            SizedBox(width: 100.0, height: 100.0),
            Positioned(left: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            Positioned(right: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            Positioned(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            Positioned(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(start: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(end: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
            PositionedDirectional(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
749 750 751 752
          ],
        ),
      ),
    );
Dan Field's avatar
Dan Field committed
753 754 755 756 757 758 759 760 761
    expect(tester.getRect(find.byType(SizedBox).at(0)), const Rect.fromLTWH(0.0,   0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(1)), const Rect.fromLTWH(0.0,   0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(2)), const Rect.fromLTWH(700.0, 0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(3)), const Rect.fromLTWH(0.0,   0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(4)), const Rect.fromLTWH(0.0,   500.0, 100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(5)), const Rect.fromLTWH(0.0,   0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(6)), const Rect.fromLTWH(700.0, 0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(7)), const Rect.fromLTWH(0.0,   0.0,   100.0, 100.0));
    expect(tester.getRect(find.byType(SizedBox).at(8)), const Rect.fromLTWH(0.0,   500.0, 100.0, 100.0));
762
  });
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783

  testWidgets('Stack error messages', (WidgetTester tester) async {
    await tester.pumpWidget(
      Stack(),
    );
    expect(
      tester.takeException().toString(),
      'No Directionality widget found.\n'
      'Stack widgets require a Directionality widget ancestor to resolve the \'alignment\' argument.\n'
      'The default value for \'alignment\' is AlignmentDirectional.topStart, which requires a text direction.\n'
      'The specific widget that could not find a Directionality ancestor was:\n'
      '  Stack\n'
      'The ownership chain for the affected widget is: "Stack ← [root]"\n'
      'Typically, the Directionality widget is introduced by the MaterialApp or WidgetsApp widget at the '
      'top of your application widget tree. It determines the ambient reading direction and is used, for '
      'example, to determine how to lay out text, how to interpret "start" and "end" values, and to resolve '
      'EdgeInsetsDirectional, AlignmentDirectional, and other *Directional objects.\n'
      'Instead of providing a Directionality widget, another solution would be passing a non-directional '
      '\'alignment\', or an explicit \'textDirection\', to the Stack.'
    );
  });
784
}