From c71f1dd76b89b4e56103f3ffe38153bd2b15b9ca Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Wed, 29 Mar 2023 21:58:58 +0200 Subject: [PATCH] Treat hidden `IndexedStack` children as offstage for test finder (#123129) Treat hidden `IndexedStack` children as offstage for test finder --- .../dropdown_button.style.0_test.dart | 6 +- .../widgets/basic/indexed_stack.0_test.dart | 19 ++- packages/flutter/lib/src/widgets/basic.dart | 22 +++ .../flutter/test/material/dropdown_test.dart | 156 +++++++++--------- packages/flutter/test/widgets/stack_test.dart | 52 +++++- packages/flutter_test/test/finders_test.dart | 5 +- 6 files changed, 164 insertions(+), 96 deletions(-) diff --git a/examples/api/test/material/dropdown/dropdown_button.style.0_test.dart b/examples/api/test/material/dropdown/dropdown_button.style.0_test.dart index a7b813549ca..b34e38ac962 100644 --- a/examples/api/test/material/dropdown/dropdown_button.style.0_test.dart +++ b/examples/api/test/material/dropdown/dropdown_button.style.0_test.dart @@ -16,13 +16,15 @@ void main() { ), ); - expect(find.text('One'), findsNWidgets(4)); + expect(find.text('One'), findsOneWidget); + expect(find.text('One', skipOffstage: false), findsNWidgets(4)); await tester.tap(find.text('One').first); await tester.pumpAndSettle(); expect(find.text('Two'), findsOneWidget); await tester.tap(find.text('Two')); await tester.pumpAndSettle(); - expect(find.text('Two'), findsNWidgets(4)); + expect(find.text('Two'), findsOneWidget); + expect(find.text('Two', skipOffstage: false), findsNWidgets(4)); }); } diff --git a/examples/api/test/widgets/basic/indexed_stack.0_test.dart b/examples/api/test/widgets/basic/indexed_stack.0_test.dart index 5f43808459f..c4f797d0a65 100644 --- a/examples/api/test/widgets/basic/indexed_stack.0_test.dart +++ b/examples/api/test/widgets/basic/indexed_stack.0_test.dart @@ -11,11 +11,11 @@ void main() { await tester.pumpWidget(const example.IndexedStackApp()); final Finder gesture2 = find.byKey(const Key('gesture2')); - final Element containerFinder = find.byKey(const Key('Dash')).evaluate().first; + final Element containerFinder = find.byKey(const Key('Dash'), skipOffstage: false).evaluate().first; expect(containerFinder.renderObject!.debugNeedsPaint, false); - final Element containerFinder1 = find.byKey(const Key('John')).evaluate().first; + final Element containerFinder1 = find.byKey(const Key('John'), skipOffstage: false).evaluate().first; expect(containerFinder1.renderObject!.debugNeedsPaint, true); - final Element containerFinder2 = find.byKey(const Key('Mary')).evaluate().first; + final Element containerFinder2 = find.byKey(const Key('Mary'), skipOffstage: false).evaluate().first; expect(containerFinder2.renderObject!.debugNeedsPaint, true); await tester.tap(gesture2); @@ -34,9 +34,9 @@ void main() { await tester.pumpWidget(const example.IndexedStackApp()); final Finder gesture1 = find.byKey(const Key('gesture1')); - final Element containerFinder = find.byKey(const Key('Dash')).evaluate().first; - final Element containerFinder1 = find.byKey(const Key('John')).evaluate().first; - final Element containerFinder2 = find.byKey(const Key('Mary')).evaluate().first; + final Element containerFinder = find.byKey(const Key('Dash'), skipOffstage: false).evaluate().first; + final Element containerFinder1 = find.byKey(const Key('John'), skipOffstage: false).evaluate().first; + final Element containerFinder2 = find.byKey(const Key('Mary'), skipOffstage: false).evaluate().first; await tester.tap(gesture1); await tester.pump(); @@ -53,17 +53,18 @@ void main() { testWidgets('has correct element addition handling', (WidgetTester tester) async { await tester.pumpWidget(const example.IndexedStackApp()); - expect(find.byType(example.PersonTracker), findsNWidgets(3)); + expect(find.byType(example.PersonTracker), findsOneWidget); + expect(find.byType(example.PersonTracker, skipOffstage: false), findsNWidgets(3)); final Finder textField = find.byType(TextField); await tester.enterText(textField, 'hello'); await tester.testTextInput.receiveAction(TextInputAction.done); await tester.pump(); - expect(find.byType(example.PersonTracker), findsNWidgets(4)); + expect(find.byType(example.PersonTracker, skipOffstage: false), findsNWidgets(4)); await tester.enterText(textField, 'hello1'); await tester.testTextInput.receiveAction(TextInputAction.done); await tester.pump(); - expect(find.byType(example.PersonTracker), findsNWidgets(5)); + expect(find.byType(example.PersonTracker, skipOffstage: false), findsNWidgets(5)); }); testWidgets('has state preservation', (WidgetTester tester) async { await tester.pumpWidget(const example.IndexedStackApp()); diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index fb8bc4e22cc..4589a00b324 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -4075,6 +4075,28 @@ class _RawIndexedStack extends Stack { ..alignment = alignment ..textDirection = textDirection ?? Directionality.maybeOf(context); } + + @override + MultiChildRenderObjectElement createElement() { + return _IndexedStackElement(this); + } +} + +class _IndexedStackElement extends MultiChildRenderObjectElement { + _IndexedStackElement(_RawIndexedStack super.widget); + + @override + _RawIndexedStack get widget => super.widget as _RawIndexedStack; + + @override + void debugVisitOnstageChildren(ElementVisitor visitor) { + final int? index = widget.index; + // If the index is null, no child is onstage. Otherwise, only the child at + // the selected index is. + if (index != null && children.isNotEmpty) { + visitor(children.elementAt(index)); + } + } } /// A widget that controls where a child of a [Stack] is positioned. diff --git a/packages/flutter/test/material/dropdown_test.dart b/packages/flutter/test/material/dropdown_test.dart index 35e0911de94..cb53f4a1796 100644 --- a/packages/flutter/test/material/dropdown_test.dart +++ b/packages/flutter/test/material/dropdown_test.dart @@ -380,7 +380,7 @@ void main() { expect(value, equals('three')); - await tester.tap(find.text('three'), warnIfMissed: false); + await tester.tap(find.text('three', skipOffstage: false), warnIfMissed: false); await tester.pump(); await tester.pump(const Duration(seconds: 1)); // finish the menu animation @@ -439,7 +439,7 @@ void main() { expect(value, equals('three')); - await tester.tap(find.text('three'), warnIfMissed: false); + await tester.tap(find.text('three', skipOffstage: false), warnIfMissed: false); await tester.pump(); await tester.pump(const Duration(seconds: 1)); // finish the menu animation @@ -558,7 +558,7 @@ void main() { // Initial value of null displays hint expect(value, equals(null)); expect(getIndex(), 4); - await tester.tap(find.text('Select Value'), warnIfMissed: false); + await tester.tap(find.text('Select Value', skipOffstage: false), warnIfMissed: false); await tester.pumpAndSettle(); await tester.tap(find.text('three').last); await tester.pumpAndSettle(); @@ -645,7 +645,7 @@ void main() { ); await tester.tap(find.text('First Item')); await tester.pump(); - final RenderBox secondItem = tester.renderObjectList(find.text('Second Item')).toList()[1]; + final RenderBox secondItem = tester.renderObjectList(find.text('Second Item', skipOffstage: false)).toList()[1]; expect(secondItem.localToGlobal(Offset.zero).dx, equals(150.0)); expect(secondItem.localToGlobal(Offset.zero).dy, equals(176.0)); }); @@ -683,14 +683,10 @@ void main() { // We should have two copies of item 5, one in the menu and one in the // button itself. - expect(tester.elementList(find.text('5')), hasLength(2)); - - // We should only have one copy of item 19, which is in the button itself. - // The copy in the menu shouldn't be in the tree because it's off-screen. - expect(tester.elementList(find.text('19')), hasLength(1)); + expect(tester.elementList(find.text('5', skipOffstage: false)), hasLength(2)); expect(value, 4); - await tester.tap(find.byWidget(button), warnIfMissed: false); + await tester.tap(find.byWidget(button, skipOffstage: false), warnIfMissed: false); expect(value, 4); // this waits for the route's completer to complete, which calls handleChanged await tester.idle(); @@ -1107,7 +1103,7 @@ void main() { await tester.pump(const Duration(seconds: 1)); // finish the menu animation // Tap on item 'one', which must appear over the button. - await tester.tap(find.byKey(buttonKey), warnIfMissed: false); + await tester.tap(find.byKey(buttonKey, skipOffstage: false), warnIfMissed: false); await tester.pump(); await tester.pump(const Duration(seconds: 1)); // finish the menu animation @@ -1175,7 +1171,7 @@ void main() { await tester.pumpAndSettle(); menuRect = getMenuRect(); buttonRect = getExpandedButtonRect(); - await tester.tap(find.byType(dropdownButtonType), warnIfMissed: false); + await tester.tap(find.byType(dropdownButtonType, skipOffstage: false), warnIfMissed: false); } // Dropdown button is along the top of the app. The top of the menu is @@ -1761,7 +1757,7 @@ void main() { )); final RenderBox dropdownButtonRenderBox = tester.renderObject( - find.widgetWithText(Row, '25'), + find.widgetWithText(Row, '25', skipOffstage: false), ); // DropdownButton should be the height of the largest item (hint inclusive) expect(dropdownButtonRenderBox.size.height, 125); @@ -1835,7 +1831,7 @@ void main() { )); final RenderBox dropdownButtonRenderBox = tester.renderObject( - find.widgetWithText(Row, '25'), + find.widgetWithText(Row, '25', skipOffstage: false), ); // DropdownButton should be the height of the largest item (hint inclusive) expect(dropdownButtonRenderBox.size.height, 125); @@ -2151,7 +2147,7 @@ void main() { // Initially shows the hint text expect(find.text('Please select an item'), findsOneWidget); - await tester.tap(find.text('Please select an item'), warnIfMissed: false); + await tester.tap(find.text('Please select an item', skipOffstage: false), warnIfMissed: false); await tester.pumpAndSettle(); await tester.tap(find.text('1')); await tester.pumpAndSettle(); @@ -2197,10 +2193,10 @@ void main() { } final Finder dropdownIcon = find.byType(Icon); - final Finder item30 = find.byKey(const ValueKey(30)); - final Finder item40 = find.byKey(const ValueKey(40)); - final Finder item50 = find.byKey(const ValueKey(50)); - final Finder item60 = find.byKey(const ValueKey(60)); + final Finder item30 = find.byKey(const ValueKey(30), skipOffstage: false); + final Finder item40 = find.byKey(const ValueKey(40), skipOffstage: false); + final Finder item50 = find.byKey(const ValueKey(50), skipOffstage: false); + final Finder item60 = find.byKey(const ValueKey(60), skipOffstage: false); // Only the DropdownButton is visible. It contains the selected item // and a dropdown arrow icon. @@ -2376,7 +2372,7 @@ void main() { expect(tester.getTopLeft(find.text('-item0-')).dx, 8); // Show the popup menu. - await tester.tap(find.text('-item0-'), warnIfMissed: false); + await tester.tap(find.text('-item0-', skipOffstage: false), warnIfMissed: false); await tester.pumpAndSettle(); expect(tester.getTopLeft(find.text('-item0-')).dx, 8); @@ -2764,7 +2760,7 @@ void main() { // Scrolling to the top again has removed the one the focus was on from the // tree, causing it to lose focus. - expect(Focus.of(tester.element(find.byKey(const ValueKey(91)).last)).hasPrimaryFocus, isFalse); + expect(Focus.of(tester.element(find.byKey(const ValueKey(91), skipOffstage: false).last)).hasPrimaryFocus, isFalse); }); testWidgets('DropdownButton onTap callback can request focus', (WidgetTester tester) async { @@ -2905,7 +2901,7 @@ void main() { expect(dropdownButtonTapCounter, 1); // Should not change. // Tap dropdown button again. - await tester.tap(find.text('three'), warnIfMissed: false); + await tester.tap(find.text('three', skipOffstage: false), warnIfMissed: false); await tester.pumpAndSettle(); expect(value, equals('three')); @@ -2971,7 +2967,7 @@ void main() { expect(menuItemTapCounters, [0, 0, 1, 0]); // Tap dropdown button again. - await tester.tap(find.text('three'), warnIfMissed: false); + await tester.tap(find.text('three', skipOffstage: false), warnIfMissed: false); await tester.pumpAndSettle(); // Should not change. @@ -2987,7 +2983,7 @@ void main() { expect(menuItemTapCounters, [0, 1, 1, 0]); // Tap dropdown button again. - await tester.tap(find.text('two'), warnIfMissed: false); + await tester.tap(find.text('two', skipOffstage: false), warnIfMissed: false); await tester.pumpAndSettle(); // Should not change. @@ -3681,50 +3677,50 @@ void main() { alignment: AlignmentDirectional.centerStart, isExpanded: false, )); - expect(tester.getTopLeft(find.text(hintText)).dx, 348.0); - expect(tester.getTopLeft(find.text(hintText)).dy, 292.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dx, 348.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dy, 292.0); // AlignmentDirectional.topStart await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.topStart, isExpanded: false, )); - expect(tester.getTopLeft(find.text(hintText)).dx, 348.0); - expect(tester.getTopLeft(find.text(hintText)).dy, 250.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dx, 348.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dy, 250.0); // AlignmentDirectional.bottomStart await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.bottomStart, isExpanded: false, )); - expect(tester.getBottomLeft(find.text(hintText)).dx, 348.0); - expect(tester.getBottomLeft(find.text(hintText)).dy, 350.0); + expect(tester.getBottomLeft(find.text(hintText,skipOffstage: false)).dx, 348.0); + expect(tester.getBottomLeft(find.text(hintText,skipOffstage: false)).dy, 350.0); // AlignmentDirectional.center await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.center, isExpanded: false, )); - expect(tester.getCenter(find.text(hintText)).dx, 388.0); - expect(tester.getCenter(find.text(hintText)).dy, 300.0); + expect(tester.getCenter(find.text(hintText,skipOffstage: false)).dx, 388.0); + expect(tester.getCenter(find.text(hintText,skipOffstage: false)).dy, 300.0); // AlignmentDirectional.topEnd await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.topEnd, isExpanded: false, )); - expect(tester.getTopRight(find.text(hintText)).dx, 428.0); - expect(tester.getTopRight(find.text(hintText)).dy, 250.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dx, 428.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dy, 250.0); // AlignmentDirectional.centerEnd await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.centerEnd, isExpanded: false, )); - expect(tester.getTopRight(find.text(hintText)).dx, 428.0); - expect(tester.getTopRight(find.text(hintText)).dy, 292.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dx, 428.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dy, 292.0); // AlignmentDirectional.bottomEnd await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.bottomEnd, isExpanded: false, )); - expect(tester.getTopRight(find.text(hintText)).dx, 428.0); - expect(tester.getTopRight(find.text(hintText)).dy, 334.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dx, 428.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dy, 334.0); // DropdownButton with `isExpanded: true` // AlignmentDirectional.centerStart (default) @@ -3732,50 +3728,50 @@ void main() { alignment: AlignmentDirectional.centerStart, isExpanded: true, )); - expect(tester.getTopLeft(find.text(hintText)).dx, 0.0); - expect(tester.getTopLeft(find.text(hintText)).dy, 292.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dx, 0.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dy, 292.0); // AlignmentDirectional.topStart await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.topStart, isExpanded: true, )); - expect(tester.getTopLeft(find.text(hintText)).dx, 0.0); - expect(tester.getTopLeft(find.text(hintText)).dy, 250.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dx, 0.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dy, 250.0); // AlignmentDirectional.bottomStart await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.bottomStart, isExpanded: true, )); - expect(tester.getBottomLeft(find.text(hintText)).dx, 0.0); - expect(tester.getBottomLeft(find.text(hintText)).dy, 350.0); + expect(tester.getBottomLeft(find.text(hintText,skipOffstage: false)).dx, 0.0); + expect(tester.getBottomLeft(find.text(hintText,skipOffstage: false)).dy, 350.0); // AlignmentDirectional.center await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.center, isExpanded: true, )); - expect(tester.getCenter(find.text(hintText)).dx, 388.0); - expect(tester.getCenter(find.text(hintText)).dy, 300.0); + expect(tester.getCenter(find.text(hintText,skipOffstage: false)).dx, 388.0); + expect(tester.getCenter(find.text(hintText,skipOffstage: false)).dy, 300.0); // AlignmentDirectional.topEnd await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.topEnd, isExpanded: true, )); - expect(tester.getTopRight(find.text(hintText)).dx, 776.0); - expect(tester.getTopRight(find.text(hintText)).dy, 250.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dx, 776.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dy, 250.0); // AlignmentDirectional.centerEnd await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.centerEnd, isExpanded: true, )); - expect(tester.getTopRight(find.text(hintText)).dx, 776.0); - expect(tester.getTopRight(find.text(hintText)).dy, 292.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dx, 776.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dy, 292.0); // AlignmentDirectional.bottomEnd await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.bottomEnd, isExpanded: true, )); - expect(tester.getBottomRight(find.text(hintText)).dx, 776.0); - expect(tester.getBottomRight(find.text(hintText)).dy, 350.0); + expect(tester.getBottomRight(find.text(hintText,skipOffstage: false)).dx, 776.0); + expect(tester.getBottomRight(find.text(hintText,skipOffstage: false)).dy, 350.0); }); testWidgets('DropdownButton hint alignment with selectedItemBuilder', (WidgetTester tester) async { @@ -3787,56 +3783,56 @@ void main() { isExpanded: false, enableSelectedItemBuilder: true, )); - expect(tester.getTopLeft(find.text(hintText)).dx, 348.0); - expect(tester.getTopLeft(find.text(hintText)).dy, 292.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dx, 348.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dy, 292.0); // AlignmentDirectional.topStart await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.topStart, isExpanded: false, enableSelectedItemBuilder: true, )); - expect(tester.getTopLeft(find.text(hintText)).dx, 348.0); - expect(tester.getTopLeft(find.text(hintText)).dy, 250.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dx, 348.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dy, 250.0); // AlignmentDirectional.bottomStart await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.bottomStart, isExpanded: false, enableSelectedItemBuilder: true, )); - expect(tester.getBottomLeft(find.text(hintText)).dx, 348.0); - expect(tester.getBottomLeft(find.text(hintText)).dy, 350.0); + expect(tester.getBottomLeft(find.text(hintText,skipOffstage: false)).dx, 348.0); + expect(tester.getBottomLeft(find.text(hintText,skipOffstage: false)).dy, 350.0); // AlignmentDirectional.center await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.center, isExpanded: false, enableSelectedItemBuilder: true, )); - expect(tester.getCenter(find.text(hintText)).dx, 388.0); - expect(tester.getCenter(find.text(hintText)).dy, 300.0); + expect(tester.getCenter(find.text(hintText,skipOffstage: false)).dx, 388.0); + expect(tester.getCenter(find.text(hintText,skipOffstage: false)).dy, 300.0); // AlignmentDirectional.topEnd await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.topEnd, isExpanded: false, enableSelectedItemBuilder: true, )); - expect(tester.getTopRight(find.text(hintText)).dx, 428.0); - expect(tester.getTopRight(find.text(hintText)).dy, 250.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dx, 428.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dy, 250.0); // AlignmentDirectional.centerEnd await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.centerEnd, isExpanded: false, enableSelectedItemBuilder: true, )); - expect(tester.getTopRight(find.text(hintText)).dx, 428.0); - expect(tester.getTopRight(find.text(hintText)).dy, 292.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dx, 428.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dy, 292.0); // AlignmentDirectional.bottomEnd await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.bottomEnd, isExpanded: false, enableSelectedItemBuilder: true, )); - expect(tester.getTopRight(find.text(hintText)).dx, 428.0); - expect(tester.getTopRight(find.text(hintText)).dy, 334.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dx, 428.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dy, 334.0); // DropdownButton with `isExpanded: true` // AlignmentDirectional.centerStart (default) @@ -3845,56 +3841,56 @@ void main() { isExpanded: true, enableSelectedItemBuilder: true, )); - expect(tester.getTopLeft(find.text(hintText)).dx, 0.0); - expect(tester.getTopLeft(find.text(hintText)).dy, 292.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dx, 0.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dy, 292.0); // AlignmentDirectional.topStart await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.topStart, isExpanded: true, enableSelectedItemBuilder: true, )); - expect(tester.getTopLeft(find.text(hintText)).dx, 0.0); - expect(tester.getTopLeft(find.text(hintText)).dy, 250.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dx, 0.0); + expect(tester.getTopLeft(find.text(hintText,skipOffstage: false)).dy, 250.0); // AlignmentDirectional.bottomStart await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.bottomStart, isExpanded: true, enableSelectedItemBuilder: true, )); - expect(tester.getBottomLeft(find.text(hintText)).dx, 0.0); - expect(tester.getBottomLeft(find.text(hintText)).dy, 350.0); + expect(tester.getBottomLeft(find.text(hintText,skipOffstage: false)).dx, 0.0); + expect(tester.getBottomLeft(find.text(hintText,skipOffstage: false)).dy, 350.0); // AlignmentDirectional.center await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.center, isExpanded: true, enableSelectedItemBuilder: true, )); - expect(tester.getCenter(find.text(hintText)).dx, 388.0); - expect(tester.getCenter(find.text(hintText)).dy, 300.0); + expect(tester.getCenter(find.text(hintText,skipOffstage: false)).dx, 388.0); + expect(tester.getCenter(find.text(hintText,skipOffstage: false)).dy, 300.0); // AlignmentDirectional.topEnd await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.topEnd, isExpanded: true, enableSelectedItemBuilder: true, )); - expect(tester.getTopRight(find.text(hintText)).dx, 776.0); - expect(tester.getTopRight(find.text(hintText)).dy, 250.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dx, 776.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dy, 250.0); // AlignmentDirectional.centerEnd await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.centerEnd, isExpanded: true, enableSelectedItemBuilder: true, )); - expect(tester.getTopRight(find.text(hintText)).dx, 776.0); - expect(tester.getTopRight(find.text(hintText)).dy, 292.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dx, 776.0); + expect(tester.getTopRight(find.text(hintText,skipOffstage: false)).dy, 292.0); // AlignmentDirectional.bottomEnd await tester.pumpWidget(buildDropdownWithHint( alignment: AlignmentDirectional.bottomEnd, isExpanded: true, enableSelectedItemBuilder: true, )); - expect(tester.getBottomRight(find.text(hintText)).dx, 776.0); - expect(tester.getBottomRight(find.text(hintText)).dy, 350.0); + expect(tester.getBottomRight(find.text(hintText,skipOffstage: false)).dx, 776.0); + expect(tester.getBottomRight(find.text(hintText,skipOffstage: false)).dy, 350.0); }); testWidgets('BorderRadius property clips dropdown button and dropdown menu', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/stack_test.dart b/packages/flutter/test/widgets/stack_test.dart index d09ead2ce2a..cd3174f5037 100644 --- a/packages/flutter/test/widgets/stack_test.dart +++ b/packages/flutter/test/widgets/stack_test.dart @@ -264,16 +264,28 @@ void main() { ); } + void expectFindsChild(int n) { + for (int i = 0; i < 3; i++) { + expect(find.text('$i', skipOffstage: false), findsOneWidget); + + if (i == n) { + expect(find.text('$i'), findsOneWidget); + } else { + expect(find.text('$i'), findsNothing); + } + } + } + await tester.pumpWidget(buildFrame(0)); - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsOneWidget); - expect(find.text('2'), findsOneWidget); + expectFindsChild(0); expect(itemsPainted, equals([0])); await tester.pumpWidget(buildFrame(1)); + expectFindsChild(1); expect(itemsPainted, equals([1])); await tester.pumpWidget(buildFrame(2)); + expectFindsChild(2); expect(itemsPainted, equals([2])); }); @@ -473,6 +485,40 @@ void main() { expect(tapped, isNull); }); + testWidgets('IndexedStack reports hidden children as offstage', (WidgetTester tester) async { + final List children = [ + for (int i = 0; i < 5; i++) Text('child $i'), + ]; + + Future pumpIndexedStack(int? activeIndex) async{ + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: IndexedStack( + index: activeIndex, + children: children, + ), + ) + ); + } + + final Finder finder = find.byType(Text); + final Finder finderIncludingOffstage = find.byType(Text, skipOffstage: false); + + await pumpIndexedStack(null); + expect(finder, findsNothing); // IndexedStack with null index shows nothing + expect(finderIncludingOffstage, findsNWidgets(5)); + + for (int i = 0; i < 5; i++) { + await pumpIndexedStack(i); + + expect(finder, findsOneWidget); + expect(finderIncludingOffstage, findsNWidgets(5)); + + expect(find.text('child $i'), findsOneWidget); + } + }); + testWidgets('Stack clip test', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( diff --git a/packages/flutter_test/test/finders_test.dart b/packages/flutter_test/test/finders_test.dart index 82b1141e248..09a482bc29e 100644 --- a/packages/flutter_test/test/finders_test.dart +++ b/packages/flutter_test/test/finders_test.dart @@ -318,8 +318,9 @@ void main() { ], )), ); - expect(find.byType(GestureDetector), findsNWidgets(2)); - final Finder hitTestable = find.byType(GestureDetector).hitTestable(); + expect(find.byType(GestureDetector), findsOneWidget); + expect(find.byType(GestureDetector, skipOffstage: false), findsNWidgets(2)); + final Finder hitTestable = find.byType(GestureDetector, skipOffstage: false).hitTestable(); expect(hitTestable, findsOneWidget); expect(tester.widget(hitTestable).key, const ValueKey(0)); });