Fix scrollUntilVisible in WidgetTester (#159582)
Fixes #143921. The single `moveBy` event may be consumed when `onTap` is present. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
parent
bcd4ecedea
commit
b8de503ded
@ -2312,6 +2312,10 @@ abstract class WidgetController {
|
||||
/// If `scrollable` is `null`, a [Finder] that looks for a [Scrollable] is
|
||||
/// used instead.
|
||||
///
|
||||
/// If `continuous` is `true`, the gesture will be reused to simulate the effect
|
||||
/// of actual finger scrolling, which is useful when used alongside listeners
|
||||
/// like [GestureDetector.onTap]. The default is `false`.
|
||||
///
|
||||
/// Throws a [StateError] if `finder` is not found after `maxScrolls` scrolls.
|
||||
///
|
||||
/// This is different from [ensureVisible] in that this allows looking for
|
||||
@ -2328,6 +2332,7 @@ abstract class WidgetController {
|
||||
finders.FinderBase<Element>? scrollable,
|
||||
int maxScrolls = 50,
|
||||
Duration duration = const Duration(milliseconds: 50),
|
||||
bool continuous = false,
|
||||
}) {
|
||||
assert(maxScrolls > 0);
|
||||
scrollable ??= finders.find.byType(Scrollable);
|
||||
@ -2349,6 +2354,7 @@ abstract class WidgetController {
|
||||
moveStep,
|
||||
maxIteration: maxScrolls,
|
||||
duration: duration,
|
||||
continuous: continuous,
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -2370,13 +2376,21 @@ abstract class WidgetController {
|
||||
Offset moveStep, {
|
||||
int maxIteration = 50,
|
||||
Duration duration = const Duration(milliseconds: 50),
|
||||
bool continuous = false,
|
||||
}) {
|
||||
return TestAsyncUtils.guard<void>(() async {
|
||||
TestGesture? gesture;
|
||||
while (maxIteration > 0 && finder.evaluate().isEmpty) {
|
||||
await drag(view, moveStep);
|
||||
if (continuous) {
|
||||
gesture ??= await startGesture(getCenter(view, warnIfMissed: true));
|
||||
await gesture.moveBy(moveStep);
|
||||
} else {
|
||||
await drag(view, moveStep);
|
||||
}
|
||||
await pump(duration);
|
||||
maxIteration -= 1;
|
||||
}
|
||||
await gesture?.up();
|
||||
await Scrollable.ensureVisible(element(finder));
|
||||
});
|
||||
}
|
||||
|
@ -612,6 +612,44 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/143921.
|
||||
testWidgets('WidgetTester.scrollUntilVisible should work together with onTap', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
const int itemCount = 20;
|
||||
|
||||
Widget buildFrame(bool hasOnTap) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: ListView.builder(
|
||||
key: ValueKey<bool>(hasOnTap), // Trigger a rebuild.
|
||||
itemCount: itemCount,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return ListTile(onTap: hasOnTap ? () {} : null, title: Text('$index'));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final Finder target = find.text('${itemCount - 1}');
|
||||
final Finder scrollable = find.byType(Scrollable);
|
||||
|
||||
// Scroll without onTap.
|
||||
await tester.pumpWidget(buildFrame(false));
|
||||
await tester.pumpAndSettle();
|
||||
expect(target, findsNothing);
|
||||
await tester.scrollUntilVisible(target, 20, scrollable: scrollable, continuous: true);
|
||||
expect(target, findsOneWidget);
|
||||
|
||||
// Scroll with onTap.
|
||||
await tester.pumpWidget(buildFrame(true));
|
||||
await tester.pumpAndSettle();
|
||||
expect(target, findsNothing);
|
||||
await tester.scrollUntilVisible(target, 20, scrollable: scrollable, continuous: true);
|
||||
expect(target, findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('platformDispatcher exposes the platformDispatcher from binding', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
|
Loading…
x
Reference in New Issue
Block a user