Automating Flutter Apps — Just with Appium & Java

Veera.
4 min readAug 12, 2023

--

Introduction

In recent times, as most of us already know, Flutter is becoming one of the top choices among companies, mainly because of the fact that it enables to build cross platform applications from a single codebase for iOS, Android Web, and whatnot.

Background

Flutter in fact is an ecosystem that offers a variety of libraries to serve different purposes and needs. For an instance, flutter_driver is a library within Flutter SDK which offers a set of API to test Flutter apps that run on real devices and/or emulators, and although testing levels — Unit, Integration or Acceptance testing — may vary, this is the only way to emulate user behaviours/actions on Flutter apps in an automatic fashion. Of course, this is certainly not so simple as it’s said unless someone has a bit of knack to write tests on Dart which is native programming language for Flutter.

Fair enough! what’s the way forward then?

A Way Forward

Like most of us, I always have a strong inclinations towards Appium in mobile automation space, mostly because of its vibrant open source community and also its efforts in maintaining standards in align with Selenium. On the backdrop of Appium 2.0 latest release, including its breaking architectural changes, it’s a definitely a good time to try out Appium Flutter Driver, though this is not one of standard drivers by Appium yet, but it doesn’t disappoint you either since it’s being standardised as we speak.

How To

In summary, Appium Flutter Driver has already done all the heavy liftings and implemented required API’s to interact with a Flutter based app so QA engineers can write tests using any of Appium supported languages, just like any other mobile apps.

While writing tests in Selenium and Appium, we consider and rely on language bindings based on our preferred programming, and as for Appium Flutter Driver, it may not offer a wide range of options yet, but provides support for the essential languages that are listed out here and as for Java, I have written my own binding which offers client codes to find elements on mobile app by different ways which are completely different from Selenium/Appium locating strategies that we would have seen, and also executes custom flutter commands using Java. Okay, let’s get started by following the installation steps in order as listed below.

  1. Install Appium by following the steps mentioned here
  2. Install Appium Flutter Driver from source using this command: appium driver install — source=npm appium-flutter-driver
  3. Flutter app under test needs to be compiled in debug or profile mode and Flutter Driver extension also needs to be enabled by adding this line enableFlutterDriverExtension() before calling app's run method in main.dart
  4. Include flutter_driver from Flutter SDK as a dev dependency

Appium Flutter Java Binding can be added to a project either using Maven or Gradle

<dependency>
<groupId>io.github.5v1988</groupId>
<artifactId>appium-flutter-client</artifactId>
<version>1.0.4</version>
</dependency>
implementation 'io.github.5v1988:appium-flutter-client:1.0.4'

After aforementioned dependency is added, Appium Flutter Driver can be instantiated by passing in necessary mobile capabilities, including AutomationName as Flutter

AppiumDriverLocalService service = new AppiumServiceBuilder()
.usingAnyFreePort().build();
service.start();
if (service == null || !service.isRunning()) {
throw new AppiumServerHasNotBeenStartedLocallyException(
"An appium server node is not started!");
}
BaseOptions options = new BaseOptions()
.setPlatformName("Android")
.setAutomationName("Flutter")
.amend("appium:app", "/path/to/app")
.amend("autoGrantPermissions", "true");
AppiumFlutterDriver driver = new AppiumFlutterDriver(service.getUrl(), options);

As I mentioned earlier, there are many different ways by which the flutter elements can be located, and the most prominent one is ByValueKey, which is like id in web context. If there is none for an element, it's always better to talk with the developers to add Key for it so it’s a bit straightforward. Nevertheless, all the available locating strategies are listed down as below:

VALUE_KEY("ByValueKey"),
TYPE("ByType"),
TOOL_TIP("ByTooltipMessage"),
TEXT("ByText"),
SEMANTICS_LABEL("BySemanticsLabel"),
ANCESTOR("Ancestor"),
DESCENDANT("Descendant"),
PAGE_BACK("PageBack");

The below is code sample to locate elements — the first is find using Key and the second one is using Descendant

//This is located using key
private FlutterElement getEmailTextBox() {
return driver.findElement(FlutterBy.VALUE_KEY, "KEYS.loginTextbox");
}

//This is located using descendant
private FlutterElement getFirstItemFromList() {
return driver.findDescendantElement(
driver.findElement(FlutterBy.TYPE, "DefaultRefreshIndicator"),
driver.findElement(FlutterBy.TYPE, "ListItem"),
false,
true);
}

Using FlutterCommand from this library, you could able to execute them by passing in necessary parameters that each command takes in. Furthermore, the status of all implemented Flutter commands can be referred from here

The below is one such code example to scroll for a flutter element until it’s visible on the screen

protected FlutterCommand command = new FlutterCommand(driver);
command.execute(Command.SCROLL_INFO_VIEW, element, ImmutableMap.of("alignment", 0.1));;

I believe that you find this post insightful and thank you for reading,

Veera.

--

--

Veera.

I'm a Software QE professional with over 14 years of industry experience; https://www.linkedin.com/in/5v1988