Skip to content

Commit 1a1c501

Browse files
committed
sticky_header test [nfc]: Make "first/last item" finders more robust
The existing `.first` and `.last` versions rely on the order that children appear in the Flutter element tree. As is, that works because the `_Item` widgets are all children of one list sliver, and it manages its children in a nice straightforward order. But when we add multiple list slivers, the order will depend also on the order those appear as children of the viewport; and in particular the items at the edges of the viewport will no longer always be the first or last items in the tree. So introduce a couple of custom finders to keep finding the first or last items in the sense we mean. For examples of using the APIs these finders use, compare the implementation of [FinderBase.first].
1 parent 2e1faed commit 1a1c501

File tree

1 file changed

+61
-2
lines changed

1 file changed

+61
-2
lines changed

test/widgets/sticky_header_test.dart

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,10 @@ Future<void> _checkSequence(
277277

278278
final first = !(reverse ^ reverseHeader ^ reverseGrowth);
279279

280-
final itemFinder = first ? find.byType(_Item).first : find.byType(_Item).last;
280+
final itemFinder = first ? _LeastItemFinder(find.byType(_Item))
281+
: _GreatestItemFinder(find.byType(_Item));
281282

282-
double insetExtent(Finder finder) {
283+
double insetExtent(FinderBase<Element> finder) {
283284
return headerAtCoordinateEnd
284285
? extent - tester.getTopLeft(finder).inDirection(axis.coordinateDirection)
285286
: tester.getBottomRight(finder).inDirection(axis.coordinateDirection);
@@ -330,6 +331,64 @@ Future<void> _checkSequence(
330331
await jumpAndCheck(100);
331332
}
332333

334+
abstract class _SelectItemFinder extends FinderBase<Element> with ChainedFinderMixin<Element> {
335+
bool shouldPrefer(_Item candidate, _Item previous);
336+
337+
@override
338+
Iterable<Element> filter(Iterable<Element> parentCandidates) {
339+
Element? result;
340+
_Item? resultWidget;
341+
for (final candidate in parentCandidates) {
342+
if (candidate is! ComponentElement) continue;
343+
final widget = candidate.widget;
344+
if (widget is! _Item) continue;
345+
if (resultWidget == null || shouldPrefer(widget, resultWidget)) {
346+
result = candidate;
347+
resultWidget = widget;
348+
}
349+
}
350+
return [if (result != null) result];
351+
}
352+
}
353+
354+
/// Finds the [_Item] with least [_Item.index]
355+
/// out of all elements found by the given parent finder.
356+
class _LeastItemFinder extends _SelectItemFinder {
357+
_LeastItemFinder(this.parent);
358+
359+
@override
360+
final FinderBase<Element> parent;
361+
362+
@override
363+
String describeMatch(Plurality plurality) {
364+
return 'least-index _Item from ${parent.describeMatch(plurality)}';
365+
}
366+
367+
@override
368+
bool shouldPrefer(_Item candidate, _Item previous) {
369+
return candidate.index < previous.index;
370+
}
371+
}
372+
373+
/// Finds the [_Item] with greatest [_Item.index]
374+
/// out of all elements found by the given parent finder.
375+
class _GreatestItemFinder extends _SelectItemFinder {
376+
_GreatestItemFinder(this.parent);
377+
378+
@override
379+
final FinderBase<Element> parent;
380+
381+
@override
382+
String describeMatch(Plurality plurality) {
383+
return 'greatest-index _Item from ${parent.describeMatch(plurality)}';
384+
}
385+
386+
@override
387+
bool shouldPrefer(_Item candidate, _Item previous) {
388+
return candidate.index > previous.index;
389+
}
390+
}
391+
333392
Future<void> _drag(WidgetTester tester, Offset offset) async {
334393
await tester.drag(find.byType(StickyHeaderListView), offset);
335394
await tester.pump();

0 commit comments

Comments
 (0)