From ea8ae8c81bb8b7677718a8ca1e5ebb001a2476fa Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 4 Jun 2024 14:43:06 -0700 Subject: [PATCH] Allow `find.byTooltip` to use a RegEx (#149348) ## Description This adds the ability for `find.byTooltip` to use a `RegEx` to match the tooltip. Also, adds some tests for `byTooltip`, since there weren't any. ## Tests - added tests --- packages/flutter_test/lib/src/finders.dart | 11 +- packages/flutter_test/test/finders_test.dart | 101 ++++++++++++++++++- 2 files changed, 109 insertions(+), 3 deletions(-) diff --git a/packages/flutter_test/lib/src/finders.dart b/packages/flutter_test/lib/src/finders.dart index 98a23c40185..2c83029cc59 100644 --- a/packages/flutter_test/lib/src/finders.dart +++ b/packages/flutter_test/lib/src/finders.dart @@ -365,13 +365,20 @@ class CommonFinders { /// /// ```dart /// expect(find.byTooltip('Back'), findsOneWidget); + /// expect(find.byTooltip(RegExp('Back.*')), findsNWidgets(2)); /// ``` /// /// If the `skipOffstage` argument is true (the default), then this skips /// nodes that are [Offstage] or that are from inactive [Route]s. - Finder byTooltip(String message, { bool skipOffstage = true }) { + Finder byTooltip(Pattern message, {bool skipOffstage = true}) { return byWidgetPredicate( - (Widget widget) => widget is Tooltip && widget.message == message, + (Widget widget) { + return widget is Tooltip && + (message is RegExp + ? ((widget.message != null && message.hasMatch(widget.message!)) || + (widget.richMessage != null && message.hasMatch(widget.richMessage!.toPlainText()))) + : ((widget.message ?? widget.richMessage?.toPlainText()) == message)); + }, skipOffstage: skipOffstage, ); } diff --git a/packages/flutter_test/test/finders_test.dart b/packages/flutter_test/test/finders_test.dart index 67335d68b64..101cd4e2c60 100644 --- a/packages/flutter_test/test/finders_test.dart +++ b/packages/flutter_test/test/finders_test.dart @@ -301,6 +301,98 @@ void main() { }); }); + group('byTooltip', () { + testWidgets('finds widgets by tooltip', (WidgetTester tester) async { + await tester.pumpWidget(_boilerplate( + const Tooltip( + message: 'Tooltip Message', + child: Text('+'), + ), + )); + expect(find.byTooltip('Tooltip Message'), findsOneWidget); + }); + + testWidgets('finds widgets with tooltip by RegExp', (WidgetTester tester) async { + await tester.pumpWidget(_boilerplate( + const Tooltip( + message: 'Tooltip Message', + child: Text('+'), + ), + )); + expect(find.byTooltip('Tooltip'), findsNothing); + expect(find.byTooltip(RegExp(r'^Tooltip')), findsOneWidget); + }); + + testWidgets('finds widgets by rich text tooltip', (WidgetTester tester) async { + await tester.pumpWidget(_boilerplate( + const Tooltip( + richMessage: TextSpan( + children: [ + TextSpan(text: 'Tooltip '), + TextSpan(text: 'Message'), + ]), + child: Text('+'), + ), + )); + expect(find.byTooltip('Tooltip Message'), findsOneWidget); + }); + + testWidgets('finds widgets with rich text tooltip by RegExp', (WidgetTester tester) async { + await tester.pumpWidget(_boilerplate( + const Tooltip( + richMessage: TextSpan( + children: [ + TextSpan(text: 'Tooltip '), + TextSpan(text: 'Message'), + ]), + child: Text('+'), + ), + )); + expect(find.byTooltip('Tooltip M'), findsNothing); + expect(find.byTooltip(RegExp(r'^Tooltip M')), findsOneWidget); + }); + + testWidgets('finds empty string with tooltip', (WidgetTester tester) async { + await tester.pumpWidget(_boilerplate( + const Tooltip( + message: '', + child: Text('+'), + ), + )); + expect(find.byTooltip(''), findsOneWidget); + + await tester.pumpWidget(_boilerplate( + const Tooltip( + richMessage: TextSpan( + children: [ + TextSpan(text: ''), + ]), + child: Text('+'), + ), + )); + expect(find.byTooltip(''), findsOneWidget); + + await tester.pumpWidget(_boilerplate( + const Tooltip( + message: '', + child: Text('+'), + ), + )); + expect(find.byTooltip(RegExp(r'^$')), findsOneWidget); + + await tester.pumpWidget(_boilerplate( + const Tooltip( + richMessage: TextSpan( + children: [ + TextSpan(text: ''), + ]), + child: Text('+'), + ), + )); + expect(find.byTooltip(RegExp(r'^$')), findsOneWidget); + }); + }); + group('hitTestable', () { testWidgets('excludes non-hit-testable widgets', (WidgetTester tester) async { @@ -1356,10 +1448,17 @@ void main() { Widget _boilerplate(Widget child) { return Directionality( textDirection: TextDirection.ltr, - child: child, + child: Navigator( + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + builder: (BuildContext context) => child, + ); + }, + ), ); } + class SimpleCustomSemanticsWidget extends LeafRenderObjectWidget { const SimpleCustomSemanticsWidget(this.label, {super.key});