-
Notifications
You must be signed in to change notification settings - Fork 28.7k
[flutter_test] Add flag to send device pointer events to the framework #108430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -494,9 +494,25 @@ abstract class TestWidgetsFlutterBinding extends BindingBase | |
/// | ||
/// When [handlePointerEvent] is called directly, [pointerEventSource] | ||
/// is [TestBindingEventSource.device]. | ||
/// | ||
/// This means that pointer events triggered by the [WidgetController] (e.g. | ||
/// via [WidgetController.tap]) will result in actual interactions with the | ||
/// UI, but other pointer events such as those from physical taps will be | ||
/// dropped. See also [shouldPropagateDevicePointerEvents] if this is | ||
/// undesired. | ||
TestBindingEventSource get pointerEventSource => _pointerEventSource; | ||
TestBindingEventSource _pointerEventSource = TestBindingEventSource.device; | ||
|
||
/// Whether pointer events from [TestBindingEventSource.device] will be | ||
/// propagated to the framework, or dropped. | ||
/// | ||
/// Setting this can be useful to interact with the app in some other way | ||
/// besides through the [WidgetController], such as with `adb shell input tap` | ||
/// on Android. | ||
/// | ||
/// See also [pointerEventSource]. | ||
bool shouldPropagateDevicePointerEvents = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: maybe drop the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Effective Dart tells us to prefix it with a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do we make sure this setting doesn't leak between tests? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure I understand, can you elaborate more on what you mean by leaking the setting? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Basically if you have several tests in a file, and one test changes the value of this, there should be some validation at the end of the test that makes sure it is unset. If you grep the repo for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, I'll try to add that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
|
||
/// Dispatch an event to the targets found by a hit test on its position, | ||
/// and remember its source as [pointerEventSource]. | ||
/// | ||
|
@@ -836,6 +852,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase | |
final bool autoUpdateGoldensBeforeTest = autoUpdateGoldenFiles && !isBrowser; | ||
final TestExceptionReporter reportTestExceptionBeforeTest = reportTestException; | ||
final ErrorWidgetBuilder errorWidgetBuilderBeforeTest = ErrorWidget.builder; | ||
final bool shouldPropagateDevicePointerEventsBeforeTest = shouldPropagateDevicePointerEvents; | ||
|
||
// run the test | ||
await testBody(); | ||
|
@@ -854,6 +871,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase | |
_verifyAutoUpdateGoldensUnset(autoUpdateGoldensBeforeTest && !isBrowser); | ||
_verifyReportTestExceptionUnset(reportTestExceptionBeforeTest); | ||
_verifyErrorWidgetBuilderUnset(errorWidgetBuilderBeforeTest); | ||
_verifyShouldPropagateDevicePointerEventsUnset(shouldPropagateDevicePointerEventsBeforeTest); | ||
_verifyInvariants(); | ||
} | ||
|
||
|
@@ -943,6 +961,21 @@ abstract class TestWidgetsFlutterBinding extends BindingBase | |
}()); | ||
} | ||
|
||
void _verifyShouldPropagateDevicePointerEventsUnset(bool valueBeforeTest) { | ||
assert(() { | ||
if (shouldPropagateDevicePointerEvents != valueBeforeTest) { | ||
FlutterError.reportError(FlutterErrorDetails( | ||
exception: FlutterError( | ||
'The value of shouldPropagateDevicePointerEvents was changed by the test.', | ||
), | ||
stack: StackTrace.current, | ||
library: 'Flutter test framework', | ||
)); | ||
} | ||
return true; | ||
}()); | ||
} | ||
|
||
/// Called by the [testWidgets] function after a test is executed. | ||
void postTest() { | ||
assert(inTest); | ||
|
@@ -1595,7 +1628,8 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { | |
/// | ||
/// Normally, device events are silently dropped. However, if this property is | ||
/// set to a non-null value, then the events will be routed to its | ||
/// [HitTestDispatcher.dispatchEvent] method instead. | ||
/// [HitTestDispatcher.dispatchEvent] method instead, unless | ||
/// [shouldPropagateDevicePointerEvents] is true. | ||
/// | ||
/// Events dispatched by [TestGesture] are not affected by this. | ||
HitTestDispatcher? deviceEventDispatcher; | ||
|
@@ -1630,6 +1664,10 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { | |
super.handlePointerEvent(event); | ||
break; | ||
case TestBindingEventSource.device: | ||
if (shouldPropagateDevicePointerEvents) { | ||
super.handlePointerEvent(event); | ||
break; | ||
} | ||
if (deviceEventDispatcher != null) { | ||
// The pointer events received with this source has a global position | ||
// (see [handlePointerEventForSource]). Transform it to the local | ||
|
@@ -1651,6 +1689,10 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { | |
break; | ||
case TestBindingEventSource.device: | ||
assert(hitTestResult != null || event is PointerAddedEvent || event is PointerRemovedEvent); | ||
if (shouldPropagateDevicePointerEvents) { | ||
super.dispatchEvent(event, hitTestResult); | ||
break; | ||
} | ||
assert(deviceEventDispatcher != null); | ||
if (hitTestResult != null) { | ||
deviceEventDispatcher!.dispatchEvent(event, hitTestResult); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we land this, we'd need ways to make sure it gets reset after tests.
The frameworks normal solution here would be to subclass the bindings. Is that still not possible in google's testing environment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can subclass the binding in Google3, just that it adds a bit of complexity and I don't think it's necessary if this is more formally supported through a setting like this.
Is it important for us to reset the value though? I think users should be free to change this value wherever as some sort of "global" - whether it is in a
testWidgets()
or at the top of theirmain()
, depending on their use case.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in the other comment below