Added find.ancestor to CommonFinders (#13691)
diff --git a/packages/flutter_test/lib/src/finders.dart b/packages/flutter_test/lib/src/finders.dart index 4e81551..73f8f90 100644 --- a/packages/flutter_test/lib/src/finders.dart +++ b/packages/flutter_test/lib/src/finders.dart
@@ -198,6 +198,29 @@ Finder descendant({ Finder of, Finder matching, bool matchRoot: false, bool skipOffstage: true }) { return new _DescendantFinder(of, matching, matchRoot: matchRoot, skipOffstage: skipOffstage); } + + /// Finds widgets that are ancestors of the [of] parameter and that match + /// the [matching] parameter. + /// + /// Example: + /// + /// // Test if a Text widget that contains 'faded' is the + /// // descendant of an Opacity widget with opacity 0.5: + /// expect( + /// tester.widget<Opacity>( + /// find.ancestor( + /// of: find.text('faded'), + /// matching: find.byType('Opacity'), + /// ) + /// ).opacity, + /// 0.5 + /// ); + /// + /// If the [matchRoot] argument is true then the widget(s) specified by [of] + /// will be matched along with the ancestors. + Finder ancestor({ Finder of, Finder matching, bool matchRoot: false}) { + return new _AncestorFinder(of, matching, matchRoot: matchRoot); + } } /// Searches a widget tree and returns nodes that match a particular @@ -583,3 +606,39 @@ return candidates; } } + +class _AncestorFinder extends Finder { + _AncestorFinder(this.descendant, this.ancestor, { this.matchRoot: false }) : super(skipOffstage: false); + + final Finder ancestor; + final Finder descendant; + final bool matchRoot; + + @override + String get description { + if (matchRoot) + return 'ancestor ${ancestor.description} beginning with ${descendant.description}'; + return '${ancestor.description} which is an ancestor of ${descendant.description}'; + } + + @override + Iterable<Element> apply(Iterable<Element> candidates) { + return candidates.where((Element element) => ancestor.evaluate().contains(element)); + } + + @override + Iterable<Element> get allCandidates { + final List<Element> candidates = <Element>[]; + for (Element root in descendant.evaluate()) { + final List<Element> ancestors = <Element>[]; + if (matchRoot) + ancestors.add(root); + root.visitAncestorElements((Element element) { + ancestors.add(element); + return true; + }); + candidates.addAll(ancestors); + } + return candidates; + } +}
diff --git a/packages/flutter_test/test/widget_tester_test.dart b/packages/flutter_test/test/widget_tester_test.dart index af4903b..85e38005 100644 --- a/packages/flutter_test/test/widget_tester_test.dart +++ b/packages/flutter_test/test/widget_tester_test.dart
@@ -198,6 +198,66 @@ contains('Actual: ?:<zero widgets with text "bar" that has ancestor(s) with type Column with text "foo"') ); }); + }); + + group('find.ancestor', () { + testWidgets('finds one ancestor', (WidgetTester tester) async { + await tester.pumpWidget(new Row( + textDirection: TextDirection.ltr, + children: <Widget>[ + new Column(children: fooBarTexts), + ], + )); + + expect(find.ancestor( + of: find.text('bar'), + matching: find.widgetWithText(Row, 'foo'), + ), findsOneWidget); + }); + + testWidgets('finds two matching ancestors, one descendant', (WidgetTester tester) async { + await tester.pumpWidget( + new Directionality( + textDirection: TextDirection.ltr, + child: new Row( + children: <Widget>[ + new Row(children: fooBarTexts), + ], + ), + ), + ); + + expect(find.ancestor( + of: find.text('bar'), + matching: find.byType(Row), + ), findsNWidgets(2)); + }); + + testWidgets('fails with a descriptive message', (WidgetTester tester) async { + await tester.pumpWidget(new Row( + textDirection: TextDirection.ltr, + children: <Widget>[ + new Column(children: <Text>[const Text('foo', textDirection: TextDirection.ltr)]), + const Text('bar', textDirection: TextDirection.ltr), + ], + )); + + TestFailure failure; + try { + expect(find.ancestor( + of: find.text('bar'), + matching: find.widgetWithText(Column, 'foo'), + ), findsOneWidget); + } catch (e) { + failure = e; + } + + expect(failure, isNotNull); + expect( + failure.message, + contains('Actual: ?:<zero widgets with type Column with text "foo" which is an ancestor of text "bar"'), + ); + }); testWidgets('Root not matched by default', (WidgetTester tester) async { await tester.pumpWidget(new Row( @@ -207,9 +267,9 @@ ], )); - expect(find.descendant( - of: find.widgetWithText(Row, 'foo'), - matching: find.byType(Row), + expect(find.ancestor( + of: find.byType(Column), + matching: find.widgetWithText(Column, 'foo'), ), findsNothing); }); @@ -222,12 +282,11 @@ )); expect(find.descendant( - of: find.widgetWithText(Row, 'foo'), - matching: find.byType(Row), + of: find.byType(Column), + matching: find.widgetWithText(Column, 'foo'), matchRoot: true, ), findsOneWidget); }); - }); testWidgets('hasRunningAnimations control test', (WidgetTester tester) async {