enableFlutterDriverExtension function
- DataHandler? handler,
- bool silenceErrors = false,
- bool enableTextEntryEmulation = true,
- List<
FinderExtension> ? finders, - List<
CommandExtension> ? commands,
Enables Flutter Driver VM service extension.
This extension is required for tests that use package:flutter_driver
to
drive applications from a separate process. In order to allow the driver
to interact with the application, this method changes the behavior of the
framework in several ways - including keyboard interaction and text
editing. Applications intended for release should never include this
method.
Call this function prior to running your application, e.g. before you call
runApp
.
Optionally you can pass a DataHandler callback. It will be called if the test calls FlutterDriver.requestData.
silenceErrors
will prevent exceptions from being logged. This is useful
for tests where exceptions are expected. Defaults to false. Any errors
will still be returned in the response
field of the result JSON along
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
finders or commands, as in the following example.
void main() {
enableFlutterDriverExtension(
finders: <FinderExtension>[ SomeFinderExtension() ],
commands: <CommandExtension>[ SomeCommandExtension() ],
);
runApp(const MyHomeWidget());
}
class SomeFinderExtension extends FinderExtension {
@override
String get finderType => 'SomeFinder';
@override
SerializableFinder deserialize(Map<String, String> params, DeserializeFinderFactory finderFactory) {
return SomeFinder(params['title']!);
}
@override
Finder createFinder(SerializableFinder finder, CreateFinderFactory finderFactory) {
final SomeFinder someFinder = finder as SomeFinder;
return flutter_test.find.byElementPredicate((Element element) {
final Widget widget = element.widget;
if (widget is SomeWidget) {
return widget.title == someFinder.title;
}
return false;
});
}
}
// Use this class in a test anywhere where a SerializableFinder is expected.
class SomeFinder extends SerializableFinder {
const SomeFinder(this.title);
final String title;
@override
String get finderType => 'SomeFinder';
@override
Map<String, String> serialize() => super.serialize()..addAll(<String, String>{
'title': title,
});
}
class SomeCommandExtension extends CommandExtension {
@override
String get commandKind => 'SomeCommand';
@override
Future<Result> call(Command command, WidgetController prober, CreateFinderFactory finderFactory, CommandHandlerFactory handlerFactory) async {
final SomeCommand someCommand = command as SomeCommand;
// Deserialize [Finder]:
final Finder finder = finderFactory.createFinder(someCommand.finder);
// Wait for [Element]:
handlerFactory.waitForElement(finder);
// Alternatively, wait for [Element] absence:
handlerFactory.waitForAbsentElement(finder);
// Submit known [Command]s:
for (int i = 0; i < someCommand.times; i++) {
await handlerFactory.handleCommand(Tap(someCommand.finder), prober, finderFactory);
}
// Alternatively, use [WidgetController]:
for (int i = 0; i < someCommand.times; i++) {
await prober.tap(finder);
}
return const SomeCommandResult('foo bar');
}
@override
Command deserialize(Map<String, String> params, DeserializeFinderFactory finderFactory, DeserializeCommandFactory commandFactory) {
return SomeCommand.deserialize(params, finderFactory);
}
}
// Pass an instance of this class to `FlutterDriver.sendCommand` to invoke
// the custom command during a test.
class SomeCommand extends CommandWithTarget {
SomeCommand(super.finder, this.times, {super.timeout});
SomeCommand.deserialize(super.json, super.finderFactory)
: times = int.parse(json['times']!),
super.deserialize();
@override
Map<String, String> serialize() {
return super.serialize()..addAll(<String, String>{'times': '$times'});
}
@override
String get kind => 'SomeCommand';
final int times;
}
class SomeCommandResult extends Result {
const SomeCommandResult(this.resultParam);
final String resultParam;
@override
Map<String, dynamic> toJson() {
return <String, dynamic>{
'resultParam': resultParam,
};
}
}
Implementation
void enableFlutterDriverExtension({ DataHandler? handler, bool silenceErrors = false, bool enableTextEntryEmulation = true, List<FinderExtension>? finders, List<CommandExtension>? commands}) {
_DriverBinding(handler, silenceErrors, enableTextEntryEmulation, finders ?? <FinderExtension>[], commands ?? <CommandExtension>[]);
assert(WidgetsBinding.instance is _DriverBinding);
}