mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Correctly chain finders to ancestor/descendant finders (#20601)
This commit is contained in:
parent
28bc818054
commit
0f4ea504bc
@ -86,7 +86,7 @@ double getHintOpacity(WidgetTester tester) {
|
||||
find.ancestor(
|
||||
of: find.text('hint'),
|
||||
matching: find.byType(FadeTransition),
|
||||
).last
|
||||
).first
|
||||
);
|
||||
return opacityWidget.opacity.value;
|
||||
}
|
||||
|
||||
@ -375,38 +375,55 @@ abstract class Finder {
|
||||
}
|
||||
}
|
||||
|
||||
class _FirstFinder extends Finder {
|
||||
_FirstFinder(this.parent);
|
||||
/// Applies additional filtering against a [parent] [Finder].
|
||||
abstract class ChainedFinder extends Finder {
|
||||
/// Create a Finder chained against the candidates of another [Finder].
|
||||
ChainedFinder(this.parent) : assert(parent != null);
|
||||
|
||||
/// Another [Finder] that will run first.
|
||||
final Finder parent;
|
||||
|
||||
/// Return another [Iterable] when given an [Iterable] of candidates from a
|
||||
/// parent [Finder].
|
||||
///
|
||||
/// This is the method to implement when subclassing [ChainedFinder].
|
||||
Iterable<Element> filter(Iterable<Element> parentCandidates);
|
||||
|
||||
@override
|
||||
Iterable<Element> apply(Iterable<Element> candidates) {
|
||||
return filter(parent.apply(candidates));
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<Element> get allCandidates => parent.allCandidates;
|
||||
}
|
||||
|
||||
class _FirstFinder extends ChainedFinder {
|
||||
_FirstFinder(Finder parent) : super(parent);
|
||||
|
||||
@override
|
||||
String get description => '${parent.description} (ignoring all but first)';
|
||||
|
||||
@override
|
||||
Iterable<Element> apply(Iterable<Element> candidates) sync* {
|
||||
yield parent.apply(candidates).first;
|
||||
Iterable<Element> filter(Iterable<Element> parentCandidates) sync* {
|
||||
yield parentCandidates.first;
|
||||
}
|
||||
}
|
||||
|
||||
class _LastFinder extends Finder {
|
||||
_LastFinder(this.parent);
|
||||
|
||||
final Finder parent;
|
||||
class _LastFinder extends ChainedFinder {
|
||||
_LastFinder(Finder parent) : super(parent);
|
||||
|
||||
@override
|
||||
String get description => '${parent.description} (ignoring all but last)';
|
||||
|
||||
@override
|
||||
Iterable<Element> apply(Iterable<Element> candidates) sync* {
|
||||
yield parent.apply(candidates).last;
|
||||
Iterable<Element> filter(Iterable<Element> parentCandidates) sync* {
|
||||
yield parentCandidates.last;
|
||||
}
|
||||
}
|
||||
|
||||
class _IndexFinder extends Finder {
|
||||
_IndexFinder(this.parent, this.index);
|
||||
|
||||
final Finder parent;
|
||||
class _IndexFinder extends ChainedFinder {
|
||||
_IndexFinder(Finder parent, this.index) : super(parent);
|
||||
|
||||
final int index;
|
||||
|
||||
@ -414,23 +431,22 @@ class _IndexFinder extends Finder {
|
||||
String get description => '${parent.description} (ignoring all but index $index)';
|
||||
|
||||
@override
|
||||
Iterable<Element> apply(Iterable<Element> candidates) sync* {
|
||||
yield parent.apply(candidates).elementAt(index);
|
||||
Iterable<Element> filter(Iterable<Element> parentCandidates) sync* {
|
||||
yield parentCandidates.elementAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
class _HitTestableFinder extends Finder {
|
||||
_HitTestableFinder(this.parent, this.alignment);
|
||||
class _HitTestableFinder extends ChainedFinder {
|
||||
_HitTestableFinder(Finder parent, this.alignment) : super(parent);
|
||||
|
||||
final Finder parent;
|
||||
final Alignment alignment;
|
||||
|
||||
@override
|
||||
String get description => '${parent.description} (considering only hit-testable ones)';
|
||||
|
||||
@override
|
||||
Iterable<Element> apply(Iterable<Element> candidates) sync* {
|
||||
for (final Element candidate in parent.apply(candidates)) {
|
||||
Iterable<Element> filter(Iterable<Element> parentCandidates) sync* {
|
||||
for (final Element candidate in parentCandidates) {
|
||||
final RenderBox box = candidate.renderObject;
|
||||
assert(box != null);
|
||||
final Offset absoluteOffset = box.localToGlobal(alignment.alongSize(box.size));
|
||||
|
||||
@ -56,6 +56,34 @@ void main() {
|
||||
expect(tester.widget(hitTestable).key, const ValueKey<int>(0));
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('ChainedFinders chain properly', (WidgetTester tester) async {
|
||||
final GlobalKey key1 = new GlobalKey();
|
||||
await tester.pumpWidget(
|
||||
_boilerplate(new Column(
|
||||
children: <Widget>[
|
||||
new Container(
|
||||
key: key1,
|
||||
child: const Text('1'),
|
||||
),
|
||||
new Container(
|
||||
child: const Text('2'),
|
||||
)
|
||||
],
|
||||
)),
|
||||
);
|
||||
|
||||
// Get the text back. By correctly chaining the descendant finder's
|
||||
// candidates, it should find 1 instead of 2. If the _LastFinder wasn't
|
||||
// correctly chained after the descendant's candidates, the last element
|
||||
// with a Text widget would have been 2.
|
||||
final Text text = find.descendant(
|
||||
of: find.byKey(key1),
|
||||
matching: find.byType(Text),
|
||||
).last.evaluate().single.widget;
|
||||
|
||||
expect(text.data, '1');
|
||||
});
|
||||
}
|
||||
|
||||
Widget _boilerplate(Widget child) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user