Commit 995fcdc9 authored by Yegor's avatar Yegor Committed by GitHub

add description to by-predicate finders (#6362)

Add an option to provide a custom description to predicate
finders. Without a custom description we default to printing the
predicate function's signature, which is not all that useful.

Use this new option in the driver extension to print the text of the
sought after tooltip.
parent 08ba8dc4
...@@ -163,7 +163,7 @@ class FlutterDriverExtension { ...@@ -163,7 +163,7 @@ class FlutterDriverExtension {
if (widget is Tooltip) if (widget is Tooltip)
return widget.message == arguments.text; return widget.message == arguments.text;
return false; return false;
}); }, description: 'widget with text tooltip "${arguments.text}"');
} }
Finder _createByValueKeyFinder(ByValueKey arguments) { Finder _createByValueKeyFinder(ByValueKey arguments) {
......
...@@ -110,18 +110,24 @@ class CommonFinders { ...@@ -110,18 +110,24 @@ class CommonFinders {
/// nodes that are [Offstage] or that are from inactive [Route]s. /// nodes that are [Offstage] or that are from inactive [Route]s.
Finder byConfig(Widget config, { bool skipOffstage: true }) => new _ConfigFinder(config, skipOffstage: skipOffstage); Finder byConfig(Widget config, { bool skipOffstage: true }) => new _ConfigFinder(config, skipOffstage: skipOffstage);
/// Finds widgets using a widget predicate. /// Finds widgets using a widget [predicate].
/// ///
/// Example: /// Example:
/// ///
/// expect(tester, hasWidget(find.byWidgetPredicate( /// expect(tester, hasWidget(find.byWidgetPredicate(
/// (Widget widget) => widget is Tooltip && widget.message == 'Back' /// (Widget widget) => widget is Tooltip && widget.message == 'Back',
/// description: 'widget with tooltip "Back"',
/// ))); /// )));
/// ///
/// If [description] is provided, then this uses it as the description of the
/// [Finder] and appears, for example, in the error message when the finder
/// fails to locate the desired widget. Otherwise, the description prints the
/// signature of the predicate function.
///
/// If the `skipOffstage` argument is true (the default), then this skips /// If the `skipOffstage` argument is true (the default), then this skips
/// nodes that are [Offstage] or that are from inactive [Route]s. /// nodes that are [Offstage] or that are from inactive [Route]s.
Finder byWidgetPredicate(WidgetPredicate predicate, { bool skipOffstage: true }) { Finder byWidgetPredicate(WidgetPredicate predicate, { String description, bool skipOffstage: true }) {
return new _WidgetPredicateFinder(predicate, skipOffstage: skipOffstage); return new _WidgetPredicateFinder(predicate, description: description, skipOffstage: skipOffstage);
} }
/// Finds Tooltip widgets with the given message. /// Finds Tooltip widgets with the given message.
...@@ -139,7 +145,7 @@ class CommonFinders { ...@@ -139,7 +145,7 @@ class CommonFinders {
); );
} }
/// Finds widgets using an element predicate. /// Finds widgets using an element [predicate].
/// ///
/// Example: /// Example:
/// ///
...@@ -147,13 +153,19 @@ class CommonFinders { ...@@ -147,13 +153,19 @@ class CommonFinders {
/// // finds elements of type SingleChildRenderObjectElement, including /// // finds elements of type SingleChildRenderObjectElement, including
/// // those that are actually subclasses of that type. /// // those that are actually subclasses of that type.
/// // (contrast with byElementType, which only returns exact matches) /// // (contrast with byElementType, which only returns exact matches)
/// (Element element) => element is SingleChildRenderObjectElement /// (Element element) => element is SingleChildRenderObjectElement,
/// description: '$SingleChildRenderObjectElement element',
/// ))); /// )));
/// ///
/// If [description] is provided, then this uses it as the description of the
/// [Finder] and appears, for example, in the error message when the finder
/// fails to locate the desired widget. Otherwise, the description prints the
/// signature of the predicate function.
///
/// If the `skipOffstage` argument is true (the default), then this skips /// If the `skipOffstage` argument is true (the default), then this skips
/// nodes that are [Offstage] or that are from inactive [Route]s. /// nodes that are [Offstage] or that are from inactive [Route]s.
Finder byElementPredicate(ElementPredicate predicate, { bool skipOffstage: true }) { Finder byElementPredicate(ElementPredicate predicate, { String description, bool skipOffstage: true }) {
return new _ElementPredicateFinder(predicate, skipOffstage: skipOffstage); return new _ElementPredicateFinder(predicate, description: description, skipOffstage: skipOffstage);
} }
} }
...@@ -397,12 +409,15 @@ class _ConfigFinder extends MatchFinder { ...@@ -397,12 +409,15 @@ class _ConfigFinder extends MatchFinder {
} }
class _WidgetPredicateFinder extends MatchFinder { class _WidgetPredicateFinder extends MatchFinder {
_WidgetPredicateFinder(this.predicate, { bool skipOffstage: true }) : super(skipOffstage: skipOffstage); _WidgetPredicateFinder(this.predicate, { String description, bool skipOffstage: true })
: _description = description,
super(skipOffstage: skipOffstage);
final WidgetPredicate predicate; final WidgetPredicate predicate;
final String _description;
@override @override
String get description => 'widget matching predicate ($predicate)'; String get description => _description ?? 'widget matching predicate ($predicate)';
@override @override
bool matches(Element candidate) { bool matches(Element candidate) {
...@@ -411,12 +426,15 @@ class _WidgetPredicateFinder extends MatchFinder { ...@@ -411,12 +426,15 @@ class _WidgetPredicateFinder extends MatchFinder {
} }
class _ElementPredicateFinder extends MatchFinder { class _ElementPredicateFinder extends MatchFinder {
_ElementPredicateFinder(this.predicate, { bool skipOffstage: true }) : super(skipOffstage: skipOffstage); _ElementPredicateFinder(this.predicate, { String description, bool skipOffstage: true })
: _description = description,
super(skipOffstage: skipOffstage);
final ElementPredicate predicate; final ElementPredicate predicate;
final String _description;
@override @override
String get description => 'element matching predicate ($predicate)'; String get description => _description ?? 'element matching predicate ($predicate)';
@override @override
bool matches(Element candidate) { bool matches(Element candidate) {
......
...@@ -104,4 +104,37 @@ void main() { ...@@ -104,4 +104,37 @@ void main() {
}); });
}); });
group('find.byElementPredicate', () {
testWidgets('fails with a custom description in the message', (WidgetTester tester) async {
await tester.pumpWidget(new Text('foo'));
String customDescription = 'custom description';
TestFailure failure;
try {
expect(find.byElementPredicate((_) => false, description: customDescription), findsOneWidget);
} catch(e) {
failure = e;
}
expect(failure, isNotNull);
expect(failure.message, contains('Actual: ?:<zero widgets with $customDescription'));
});
});
group('find.byWidgetPredicate', () {
testWidgets('fails with a custom description in the message', (WidgetTester tester) async {
await tester.pumpWidget(new Text('foo'));
String customDescription = 'custom description';
TestFailure failure;
try {
expect(find.byWidgetPredicate((_) => false, description: customDescription), findsOneWidget);
} catch(e) {
failure = e;
}
expect(failure, isNotNull);
expect(failure.message, contains('Actual: ?:<zero widgets with $customDescription'));
});
});
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment