Restarting a Flutter App with Flutter Driver

Wednesday, Mar 11, 2020| Tags: flutter

Flutter Driver is a neat way of testing Flutter applications perfoming integration tests. It allows you to run your Flutter application in an emulator and to control the app from your test code, performing taps and asserting that the app works as expected.

One problem I faced when using Flutter Driver is that the app won’t restart between tests.

For example, I would run a test in which the user performs a login, then a test in which the user performs a registration, but after the login test, the test left the app logged in. An alternative would be to always logout and leave the app after every single test, but sometimes we just want to clear everything up and go back to the start.

Restarting a Flutter app

Restarting Flutter applications can be confusing for newcomers but the solution is indeed simple and smart: We need to recreate the root Widget.

In my case, my root widget is a StatefulWidget called App, which accepts a Key as parameter like all other Widgets:

class App extends StatefulWidget {
  App({
    Key key,
  })  : super(key: key);

  @override
  _AppState createState() => _AppState();
}

When we recreate this Widget with a different Key, Flutter will completely rebuild the subtree, throwing away the existing Widget tree and creating a new one from scratch.

For example, you can create the App Widget passing a UniqueKey:

runApp(
  App(
    key: UniqueKey(),
  ),
);

But this is a bit unpractical, because we can’t call to runApp from within our application. That’s what packages like flutter_phoenix do for you:

runApp(
  Phoenix(
    child: App(),
  ),
);

Then you can call to Phoenix.rebirth(context) to force the Phoenix Widget to be recreated.

Restarting a Flutter app from Flutter Driver tests

The same concept can be applied from Flutter Driver. For it, you need to implement a handler to communicate from the Flutter Driver to the application, to force recreating the root Widget.

You can do that by passing a handler to the enableFlutterDriverExtension method when starting your tests:

enableFlutterDriverExtension(handler: (command) async {
  switch (command) {
    case 'restart':
      _startApp();
      return 'ok';
  }
  throw Exception('Unknown command');
});

This allows you to call await driver.requestData('restart') from your tests, running the _startApp() method again.

In _startApp(), you need to call to runApp like in the previous example, and like before, pass a UniqueKey:

void _startApp() {
  runApp(
    App(
      key: UniqueKey(),
    ),
  );
}

Then, in your tests, when you want to restart your application, call to the requestData method with the restart command, this will call runApp again, but because App will have a different key, the App Widget will be recreated, allowing you to test different parts of the app like if it was run for the first time.

INTERESTED IN WORKING TOGETHER?

Contact with me