stack_test.dart 27.7 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/rendering.dart';
6
import 'package:flutter/widgets.dart';
7
import 'package:flutter_test/flutter_test.dart';
8

9
import '../rendering/rendering_tester.dart' show TestCallbackPainter;
10

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

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

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

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

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

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

    Element container;
    StackParentData parentData;

    container = tester.element(find.byKey(key));
62
    parentData = container.renderObject!.parentData! as StackParentData;
63 64 65 66 67 68 69
    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);

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

    container = tester.element(find.byKey(key));
87
    parentData = container.renderObject!.parentData! as StackParentData;
88 89 90 91 92 93
    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);
94
  });
95

96
  testWidgets('Can remove parent data', (WidgetTester tester) async {
97
    const Key key = Key('container');
98
    const SizedBox sizedBox = SizedBox(key: key, width: 10.0, height: 10.0);
99

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

    StackParentData parentData;
109
    parentData = containerElement.renderObject!.parentData! as StackParentData;
110 111 112 113 114 115 116
    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);

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

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

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

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

153
    final Element child0 = tester.element(find.byKey(child0Key));
154
    final StackParentData child0RenderObjectParentData = child0.renderObject!.parentData! as StackParentData;
155
    expect(child0RenderObjectParentData.offset, equals(Offset.zero));
Hans Muller's avatar
Hans Muller committed
156

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

    await tester.pumpWidget(
162
      Directionality(
163
        textDirection: TextDirection.ltr,
164 165
        child: Center(
          child: Stack(
166
            alignment: AlignmentDirectional.bottomEnd,
167 168 169
            children: const <Widget>[
              SizedBox(key: child0Key, width: 20.0, height: 20.0),
              SizedBox(key: child1Key, width: 10.0, height: 10.0),
170 171 172 173 174 175
            ],
          ),
        ),
      ),
    );

176
    expect(child0RenderObjectParentData.offset, equals(Offset.zero));
177 178 179 180
    expect(child1RenderObjectParentData.offset, equals(const Offset(10.0, 10.0)));
  });

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

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

    final Element child0 = tester.element(find.byKey(child0Key));
200
    final StackParentData child0RenderObjectParentData = child0.renderObject!.parentData! as StackParentData;
201
    expect(child0RenderObjectParentData.offset, equals(Offset.zero));
202 203

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

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

222
    expect(child0RenderObjectParentData.offset, equals(Offset.zero));
223
    expect(child1RenderObjectParentData.offset, equals(const Offset(0.0, 10.0)));
Hans Muller's avatar
Hans Muller committed
224 225
  });

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

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

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

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

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

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

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

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

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

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

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

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

314 315
    const BoxDecoration kBoxDecoration = BoxDecoration(
      color: Color(0xFF00FF00),
316 317
    );

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

    Element box;
    RenderBox renderBox;
    StackParentData parentData;

    box = tester.element(find.byKey(key));
337 338
    renderBox = box.renderObject! as RenderBox;
    parentData = renderBox.parentData! as StackParentData;
339 340 341 342 343 344 345 346 347 348 349
    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));

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

    box = tester.element(find.byKey(key));
365 366
    renderBox = box.renderObject! as RenderBox;
    parentData = renderBox.parentData! as StackParentData;
367 368 369 370 371 372 373 374 375 376
    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));
377 378
  });

379 380 381 382 383
  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));

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

388
  testWidgets('IndexedStack with null index', (WidgetTester tester) async {
389
    bool? tapped;
390 391

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

412
    await tester.tap(find.byType(IndexedStack), warnIfMissed: false);
413
    final RenderBox box = tester.renderObject(find.byType(IndexedStack));
414 415 416 417
    expect(box.size, equals(const Size(200.0, 200.0)));
    expect(tapped, isNull);
  });

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

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

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

    box = tester.renderObject(find.byType(Stack));
474
    context = TestPaintingContext();
475 476 477
    box.paint(context, Offset.zero);
    expect(context.invocations.first.memberName, equals(#paintChild));
  });
478 479 480 481

  testWidgets('Stack sizing: default', (WidgetTester tester) async {
    final List<String> logs = <String>[];
    await tester.pumpWidget(
482
      Directionality(
483
        textDirection: TextDirection.ltr,
484 485
        child: Center(
          child: ConstrainedBox(
486 487 488 489 490 491
            constraints: const BoxConstraints(
              minWidth: 2.0,
              maxWidth: 3.0,
              minHeight: 5.0,
              maxHeight: 7.0,
            ),
492
            child: Stack(
493
              children: <Widget>[
494
                LayoutBuilder(
495 496 497 498 499 500 501
                  builder: (BuildContext context, BoxConstraints constraints) {
                    logs.add(constraints.toString());
                    return const Placeholder();
                  },
                ),
              ],
            ),
502 503 504 505 506 507 508 509 510 511
          ),
        ),
      ),
    );
    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) {
512
      return Directionality(
513
        textDirection: TextDirection.ltr,
514 515
        child: Center(
          child: ConstrainedBox(
516 517 518 519 520 521
            constraints: const BoxConstraints(
              minWidth: 2.0,
              maxWidth: 3.0,
              minHeight: 5.0,
              maxHeight: 7.0,
            ),
522
            child: Stack(
523 524
              fit: sizing,
              children: <Widget>[
525
                LayoutBuilder(
526 527 528 529 530 531 532
                  builder: (BuildContext context, BoxConstraints constraints) {
                    logs.add(constraints.toString());
                    return const Placeholder();
                  },
                ),
              ],
            ),
533 534 535 536 537 538 539 540 541 542 543 544 545 546
          ),
        ),
      );
    }
    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=',
547
      'BoxConstraints(2.0<=w<=3.0, 5.0<=h<=7.0)',
548 549
    ]);
  });
550 551

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

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

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

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

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

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

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

    expect(tester.getTopLeft(find.byKey(key)), const Offset(50.0, 0.0));
  });
Ian Hickson's avatar
Ian Hickson committed
622 623 624

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

  testWidgets('Alignment with partially-positioned children', (WidgetTester tester) async {
    await tester.pumpWidget(
643
      Directionality(
644
        textDirection: TextDirection.rtl,
645
        child: Stack(
646
          alignment: Alignment.center,
647
          children: const <Widget>[
648 649 650 651 652 653 654 655 656
            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)),
657 658 659 660
          ],
        ),
      ),
    );
Dan Field's avatar
Dan Field committed
661 662 663 664 665 666 667 668 669
    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));
670 671

    await tester.pumpWidget(
672
      Directionality(
673
        textDirection: TextDirection.ltr,
674
        child: Stack(
675
          alignment: Alignment.center,
676
          children: const <Widget>[
677 678 679 680 681 682 683 684 685
            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)),
686 687 688 689
          ],
        ),
      ),
    );
Dan Field's avatar
Dan Field committed
690 691 692 693 694 695 696 697 698
    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));
699 700

    await tester.pumpWidget(
701
      Directionality(
702
        textDirection: TextDirection.ltr,
703
        child: Stack(
704
          alignment: Alignment.bottomRight,
705
          children: const <Widget>[
706 707 708 709 710 711 712 713 714
            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)),
715 716 717 718
          ],
        ),
      ),
    );
Dan Field's avatar
Dan Field committed
719 720 721 722 723 724 725 726 727
    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));
728 729

    await tester.pumpWidget(
730
      Directionality(
731
        textDirection: TextDirection.ltr,
732
        child: Stack(
733
          alignment: Alignment.topLeft,
734
          children: const <Widget>[
735 736 737 738 739 740 741 742 743
            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)),
744 745 746 747
          ],
        ),
      ),
    );
Dan Field's avatar
Dan Field committed
748 749 750 751 752 753 754 755 756
    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));
757
  });
758 759 760 761 762 763 764 765

  testWidgets('Stack error messages', (WidgetTester tester) async {
    await tester.pumpWidget(
      Stack(),
    );
    expect(
      tester.takeException().toString(),
      'No Directionality widget found.\n'
766 767
      "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"
768 769 770 771 772 773 774 775
      '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 '
776
      "'alignment', or an explicit 'textDirection', to the Stack.",
777 778
    );
  });
779
}