Unverified Commit ea7017d3 authored by voobel's avatar voobel Committed by GitHub

enableFlutterDriverExtension: optionally disable text entry emulation (#71656)

parent d3179f0e
...@@ -32,17 +32,18 @@ const String _extensionMethodName = 'driver'; ...@@ -32,17 +32,18 @@ const String _extensionMethodName = 'driver';
typedef DataHandler = Future<String> Function(String? message); typedef DataHandler = Future<String> Function(String? message);
class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding { class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
_DriverBinding(this._handler, this._silenceErrors, this.finders, this.commands); _DriverBinding(this._handler, this._silenceErrors, this._enableTextEntryEmulation, this.finders, this.commands);
final DataHandler? _handler; final DataHandler? _handler;
final bool _silenceErrors; final bool _silenceErrors;
final bool _enableTextEntryEmulation;
final List<FinderExtension>? finders; final List<FinderExtension>? finders;
final List<CommandExtension>? commands; final List<CommandExtension>? commands;
@override @override
void initServiceExtensions() { void initServiceExtensions() {
super.initServiceExtensions(); super.initServiceExtensions();
final FlutterDriverExtension extension = FlutterDriverExtension(_handler, _silenceErrors, finders: finders ?? const <FinderExtension>[], commands: commands ?? const <CommandExtension>[]); final FlutterDriverExtension extension = FlutterDriverExtension(_handler, _silenceErrors, _enableTextEntryEmulation, finders: finders ?? const <FinderExtension>[], commands: commands ?? const <CommandExtension>[]);
registerServiceExtension( registerServiceExtension(
name: _extensionMethodName, name: _extensionMethodName,
callback: extension.call, callback: extension.call,
...@@ -78,6 +79,12 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, ...@@ -78,6 +79,12 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding,
/// will still be returned in the `response` field of the result JSON along /// will still be returned in the `response` field of the result JSON along
/// with an `isError` boolean. /// with an `isError` boolean.
/// ///
/// The `enableTextEntryEmulation` parameter controls whether the application interacts
/// with the system's text entry methods or a mocked out version used by Flutter Driver.
/// If it is set to false, [FlutterDriver.enterText] will fail,
/// but testing the application with real keyboard input is possible.
/// This value may be updated during a test by calling [FlutterDriver.setTextEntryEmulation].
///
/// The `finders` and `commands` parameters are optional and used to add custom /// The `finders` and `commands` parameters are optional and used to add custom
/// finders or commands, as in the following example. /// finders or commands, as in the following example.
/// ///
...@@ -217,9 +224,9 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, ...@@ -217,9 +224,9 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding,
/// } /// }
/// ``` /// ```
/// ///
void enableFlutterDriverExtension({ DataHandler? handler, bool silenceErrors = false, List<FinderExtension>? finders, List<CommandExtension>? commands}) { void enableFlutterDriverExtension({ DataHandler? handler, bool silenceErrors = false, bool enableTextEntryEmulation = true, List<FinderExtension>? finders, List<CommandExtension>? commands}) {
assert(WidgetsBinding.instance == null); assert(WidgetsBinding.instance == null);
_DriverBinding(handler, silenceErrors, finders ?? <FinderExtension>[], commands ?? <CommandExtension>[]); _DriverBinding(handler, silenceErrors, enableTextEntryEmulation, finders ?? <FinderExtension>[], commands ?? <CommandExtension>[]);
assert(WidgetsBinding.instance is _DriverBinding); assert(WidgetsBinding.instance is _DriverBinding);
} }
...@@ -315,11 +322,14 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory, ...@@ -315,11 +322,14 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory,
/// Creates an object to manage a Flutter Driver connection. /// Creates an object to manage a Flutter Driver connection.
FlutterDriverExtension( FlutterDriverExtension(
this._requestDataHandler, this._requestDataHandler,
this._silenceErrors, { this._silenceErrors,
this._enableTextEntryEmulation, {
List<FinderExtension> finders = const <FinderExtension>[], List<FinderExtension> finders = const <FinderExtension>[],
List<CommandExtension> commands = const <CommandExtension>[], List<CommandExtension> commands = const <CommandExtension>[],
}) : assert(finders != null) { }) : assert(finders != null) {
registerTextInput(); if (_enableTextEntryEmulation) {
registerTextInput();
}
for(final FinderExtension finder in finders) { for(final FinderExtension finder in finders) {
_finderExtensions[finder.finderType] = finder; _finderExtensions[finder.finderType] = finder;
...@@ -336,6 +346,8 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory, ...@@ -336,6 +346,8 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory,
final bool _silenceErrors; final bool _silenceErrors;
final bool _enableTextEntryEmulation;
void _log(String message) { void _log(String message) {
driverLog('FlutterDriverExtension', message); driverLog('FlutterDriverExtension', message);
} }
......
...@@ -44,7 +44,7 @@ void main() { ...@@ -44,7 +44,7 @@ void main() {
setUp(() { setUp(() {
result = null; result = null;
driverExtension = FlutterDriverExtension((String message) async { log.add(message); return (messageId += 1).toString(); }, false); driverExtension = FlutterDriverExtension((String message) async { log.add(message); return (messageId += 1).toString(); }, false, true);
}); });
testWidgets('returns immediately when transient callback queue is empty', (WidgetTester tester) async { testWidgets('returns immediately when transient callback queue is empty', (WidgetTester tester) async {
...@@ -105,7 +105,7 @@ void main() { ...@@ -105,7 +105,7 @@ void main() {
setUp(() { setUp(() {
result = null; result = null;
driverExtension = FlutterDriverExtension((String message) async { log.add(message); return (messageId += 1).toString(); }, false); driverExtension = FlutterDriverExtension((String message) async { log.add(message); return (messageId += 1).toString(); }, false, true);
}); });
testWidgets('waiting for NoTransientCallbacks returns immediately when transient callback queue is empty', (WidgetTester tester) async { testWidgets('waiting for NoTransientCallbacks returns immediately when transient callback queue is empty', (WidgetTester tester) async {
...@@ -471,7 +471,7 @@ void main() { ...@@ -471,7 +471,7 @@ void main() {
group('getSemanticsId', () { group('getSemanticsId', () {
FlutterDriverExtension driverExtension; FlutterDriverExtension driverExtension;
setUp(() { setUp(() {
driverExtension = FlutterDriverExtension((String arg) async => '', true); driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
}); });
testWidgets('works when semantics are enabled', (WidgetTester tester) async { testWidgets('works when semantics are enabled', (WidgetTester tester) async {
...@@ -520,7 +520,7 @@ void main() { ...@@ -520,7 +520,7 @@ void main() {
}); });
testWidgets('getOffset', (WidgetTester tester) async { testWidgets('getOffset', (WidgetTester tester) async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true); final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
Future<Offset> getOffset(OffsetType offset) async { Future<Offset> getOffset(OffsetType offset) async {
final Map<String, String> arguments = GetOffset(ByValueKey(1), offset).serialize(); final Map<String, String> arguments = GetOffset(ByValueKey(1), offset).serialize();
...@@ -552,7 +552,7 @@ void main() { ...@@ -552,7 +552,7 @@ void main() {
testWidgets('getText', (WidgetTester tester) async { testWidgets('getText', (WidgetTester tester) async {
await silenceDriverLogger(() async { await silenceDriverLogger(() async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true); final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
Future<String> getTextInternal(SerializableFinder search) async { Future<String> getTextInternal(SerializableFinder search) async {
final Map<String, String> arguments = GetText(search, timeout: const Duration(seconds: 1)).serialize(); final Map<String, String> arguments = GetText(search, timeout: const Duration(seconds: 1)).serialize();
...@@ -622,7 +622,7 @@ void main() { ...@@ -622,7 +622,7 @@ void main() {
testWidgets('descendant finder', (WidgetTester tester) async { testWidgets('descendant finder', (WidgetTester tester) async {
await silenceDriverLogger(() async { await silenceDriverLogger(() async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true); final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
Future<String> getDescendantText({ String of, bool matchRoot = false}) async { Future<String> getDescendantText({ String of, bool matchRoot = false}) async {
final Map<String, String> arguments = GetText(Descendant( final Map<String, String> arguments = GetText(Descendant(
...@@ -667,7 +667,7 @@ void main() { ...@@ -667,7 +667,7 @@ void main() {
testWidgets('descendant finder firstMatchOnly', (WidgetTester tester) async { testWidgets('descendant finder firstMatchOnly', (WidgetTester tester) async {
await silenceDriverLogger(() async { await silenceDriverLogger(() async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true); final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
Future<String> getDescendantText() async { Future<String> getDescendantText() async {
final Map<String, String> arguments = GetText(Descendant( final Map<String, String> arguments = GetText(Descendant(
...@@ -701,7 +701,7 @@ void main() { ...@@ -701,7 +701,7 @@ void main() {
testWidgets('ancestor finder', (WidgetTester tester) async { testWidgets('ancestor finder', (WidgetTester tester) async {
await silenceDriverLogger(() async { await silenceDriverLogger(() async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true); final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
Future<Offset> getAncestorTopLeft({ String of, String matching, bool matchRoot = false}) async { Future<Offset> getAncestorTopLeft({ String of, String matching, bool matchRoot = false}) async {
final Map<String, String> arguments = GetOffset(Ancestor( final Map<String, String> arguments = GetOffset(Ancestor(
...@@ -771,7 +771,7 @@ void main() { ...@@ -771,7 +771,7 @@ void main() {
testWidgets('ancestor finder firstMatchOnly', (WidgetTester tester) async { testWidgets('ancestor finder firstMatchOnly', (WidgetTester tester) async {
await silenceDriverLogger(() async { await silenceDriverLogger(() async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true); final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
Future<Offset> getAncestorTopLeft() async { Future<Offset> getAncestorTopLeft() async {
final Map<String, String> arguments = GetOffset(Ancestor( final Map<String, String> arguments = GetOffset(Ancestor(
...@@ -819,7 +819,7 @@ void main() { ...@@ -819,7 +819,7 @@ void main() {
}); });
testWidgets('GetDiagnosticsTree', (WidgetTester tester) async { testWidgets('GetDiagnosticsTree', (WidgetTester tester) async {
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true); final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
Future<Map<String, Object>> getDiagnosticsTree(DiagnosticsType type, SerializableFinder finder, { int depth = 0, bool properties = true }) async { Future<Map<String, Object>> getDiagnosticsTree(DiagnosticsType type, SerializableFinder finder, { int depth = 0, bool properties = true }) async {
final Map<String, String> arguments = GetDiagnosticsTree(finder, type, subtreeDepth: depth, includeProperties: properties).serialize(); final Map<String, String> arguments = GetDiagnosticsTree(finder, type, subtreeDepth: depth, includeProperties: properties).serialize();
...@@ -884,6 +884,45 @@ void main() { ...@@ -884,6 +884,45 @@ void main() {
expect(children.single['children'], isEmpty); expect(children.single['children'], isEmpty);
}); });
group('enableTextEntryEmulation', () {
FlutterDriverExtension driverExtension;
Future<Map<String, dynamic>> enterText() async {
final Map<String, String> arguments = const EnterText('foo').serialize();
final Map<String, dynamic> result = await driverExtension.call(arguments);
return result;
}
const Widget testWidget = MaterialApp(
home: Material(
child: Center(
child: TextField(
key: ValueKey<String>('foo'),
autofocus: true,
),
),
),
);
testWidgets('enableTextEntryEmulation false', (WidgetTester tester) async {
driverExtension = FlutterDriverExtension((String arg) async => '', true, false);
await tester.pumpWidget(testWidget);
final Map<String, dynamic> enterTextResult = await enterText();
expect(enterTextResult['isError'], isTrue);
});
testWidgets('enableTextEntryEmulation true', (WidgetTester tester) async {
driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
await tester.pumpWidget(testWidget);
final Map<String, dynamic> enterTextResult = await enterText();
expect(enterTextResult['isError'], isFalse);
});
});
group('extension finders', () { group('extension finders', () {
final Widget debugTree = Directionality( final Widget debugTree = Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -907,6 +946,7 @@ void main() { ...@@ -907,6 +946,7 @@ void main() {
final FlutterDriverExtension driverExtension = FlutterDriverExtension( final FlutterDriverExtension driverExtension = FlutterDriverExtension(
(String arg) async => '', (String arg) async => '',
true, true,
true,
finders: <FinderExtension>[], finders: <FinderExtension>[],
); );
...@@ -927,6 +967,7 @@ void main() { ...@@ -927,6 +967,7 @@ void main() {
final FlutterDriverExtension driverExtension = FlutterDriverExtension( final FlutterDriverExtension driverExtension = FlutterDriverExtension(
(String arg) async => '', (String arg) async => '',
true, true,
true,
finders: <FinderExtension>[ finders: <FinderExtension>[
StubFinderExtension(), StubFinderExtension(),
], ],
...@@ -948,6 +989,7 @@ void main() { ...@@ -948,6 +989,7 @@ void main() {
final FlutterDriverExtension driverExtension = FlutterDriverExtension( final FlutterDriverExtension driverExtension = FlutterDriverExtension(
(String arg) async => '', (String arg) async => '',
true, true,
true,
finders: <FinderExtension>[ finders: <FinderExtension>[
StubFinderExtension(), StubFinderExtension(),
], ],
...@@ -969,6 +1011,7 @@ void main() { ...@@ -969,6 +1011,7 @@ void main() {
final FlutterDriverExtension driverExtension = FlutterDriverExtension( final FlutterDriverExtension driverExtension = FlutterDriverExtension(
(String arg) async => '', (String arg) async => '',
true, true,
true,
finders: <FinderExtension>[ finders: <FinderExtension>[
StubFinderExtension(), StubFinderExtension(),
], ],
...@@ -1013,6 +1056,7 @@ void main() { ...@@ -1013,6 +1056,7 @@ void main() {
final FlutterDriverExtension driverExtension = FlutterDriverExtension( final FlutterDriverExtension driverExtension = FlutterDriverExtension(
(String arg) async => '', (String arg) async => '',
true, true,
true,
commands: <CommandExtension>[], commands: <CommandExtension>[],
); );
...@@ -1033,6 +1077,7 @@ void main() { ...@@ -1033,6 +1077,7 @@ void main() {
final FlutterDriverExtension driverExtension = FlutterDriverExtension( final FlutterDriverExtension driverExtension = FlutterDriverExtension(
(String arg) async => '', (String arg) async => '',
true, true,
true,
commands: <CommandExtension>[ commands: <CommandExtension>[
StubNestedCommandExtension(), StubNestedCommandExtension(),
], ],
...@@ -1058,6 +1103,7 @@ void main() { ...@@ -1058,6 +1103,7 @@ void main() {
final FlutterDriverExtension driverExtension = FlutterDriverExtension( final FlutterDriverExtension driverExtension = FlutterDriverExtension(
(String arg) async => '', (String arg) async => '',
true, true,
true,
commands: <CommandExtension>[ commands: <CommandExtension>[
StubProberCommandExtension(), StubProberCommandExtension(),
], ],
...@@ -1085,7 +1131,7 @@ void main() { ...@@ -1085,7 +1131,7 @@ void main() {
Map<String, dynamic> result; Map<String, dynamic> result;
setUp(() { setUp(() {
driverExtension = FlutterDriverExtension((String arg) async => '', true); driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
result = null; result = null;
}); });
......
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