Flutter app automate testing with Appium Flutter Driver
Tags: flutter, appium, automation, testing
Published: 2019-11-02 15:24:58

As tech person whom adopted flutter in tech portfolio (got much friction around this). The most question I've got is testing automation engineer did not know dart and appium not officialy support flutter, how can they write test for it, how can they do automate test with it? So I will share context about how we can test flutter application with [appium-flutter-driver](https://www.npmjs.com/package/appium-flutter-driver) with a practical example.

## Project setup

 - Since Flutter did not use native conponents, it's mean you need to define keys in all of your widget to made your widgets visible to appium-flutter-driver (also for normal flutter testing).

Be aware! your testing apk need to be "debug" or "profiling" package.

Example
```
Text(
  'Welcome to Home Page',
  key: Key('homeGreetingLbl'),
)
```

- Add "enableFlutterDriverExtension()" before "runApp()"
```
void main() {
  enableFlutterDriverExtension();
  runApp(MyApp());
}
```

- Add "test" and "flutter-driver" to pubspec.yml
```
dev_dependencies:
  test: any
  flutter_test:
    sdk: flutter
  flutter_driver:
    sdk: flutter
```


My tutorial was extended from TruongSinh Tran-Nguyen's tutorial, Big thank you to him. Installation can follow with his tutorial as below.
{% github truongsinh/appium-flutter-driver %}


#Let's test our app with appium-flutter-driver!
I've created demo application for our appium testing in github you can checkout and try
{% github netfirms/flutter-appium-example %}


Project has flutter app project and "appium" directory for testing. In "appium" directory consist of
- package.json - Package which is required by appium-flutter-driver.
```javascript
{
  "name": "appium",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "appium-flutter-finder": "0.0.13",
    "webdriverio": "^5.15.0"
  },
  "scripts": {
    "start": "node test.js",
    "ios": "APPIUM_OS=ios npm start",
    "android": "APPIUM_OS=android npm start",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "TruongSinh Tran-Nguyen <i@truongsinh.pro",
  "private": true,
  "license": "MIT"
}
```
- test.js - This is main testing file.
```javascript
const wdio = require('webdriverio');
const assert = require('assert');
const find = require('appium-flutter-finder');

const osSpecificOps = process.env.APPIUM_OS === 'android' ? {
  platformName: 'Android',
  deviceName: 'emulator-5554',
  // @todo support non-unix style path
  app: __dirname +  '/../build/app/outputs/apk/debug/app-debug.apk',
}: process.env.APPIUM_OS === 'ios' ? {
  platformName: 'iOS',
  platformVersion: '12.2',
  deviceName: 'iPhone X',
  noReset: true,
  app: __dirname +  '/../ios/Runner.zip',

} : {};

const opts = {
  port: 4723,
  capabilities: {
    ...osSpecificOps,
    automationName: 'Flutter'
  }
};

(async () => {
  console.log('Initial app testing')
  const driver = await wdio.remote(opts);
   assert.strictEqual(await driver.execute('flutter:checkHealth'), 'ok');
  await driver.execute('flutter:clearTimeline');
  await driver.execute('flutter:forceGC');

  //Enter login page
  await driver.execute('flutter:waitFor', find.byValueKey('loginBtn'));
  await driver.elementSendKeys(find.byValueKey('emailTxt'), 'test@gmail.com')
  await driver.elementSendKeys(find.byValueKey('passwordTxt'), '123456')
  await driver.elementClick(find.byValueKey('loginBtn'));

  //Enter home page
  await driver.execute('flutter:waitFor', find.byValueKey('homeGreetingLbl'));
  assert.strictEqual(await driver.getElementText(find.byValueKey('homeGreetingLbl')), 'Welcome to Home Page');

  //Enter Page1
  await driver.elementClick(find.byValueKey('page1Btn'));
  await driver.execute('flutter:waitFor', find.byValueKey('page1GreetingLbl'));
  assert.strictEqual(await driver.getElementText(find.byValueKey('page1GreetingLbl')), 'Page1');
  await driver.elementClick(find.byValueKey('page1BackBtn'));

  //Enter Page2
  await driver.elementClick(find.byValueKey('page2Btn'));
  await driver.execute('flutter:waitFor', find.byValueKey('page2GreetingLbl'));
  assert.strictEqual(await driver.getElementText(find.byValueKey('page2GreetingLbl')), 'Page2');
  await driver.switchContext('NATIVE_APP');
  await driver.back();
  await driver.switchContext('FLUTTER');

  //Logout application
  await driver.elementClick(find.byValueKey('logoutBtn'));
  driver.deleteSession();
})();
```

#Run Appium (Android)
1. Change directory to "appium" folder.
2. Start appium server with command "appium" in console.
3. Start Android emulator (check your emulator address with "adb devices 
```
Taweechais-MBP:~ taweechaimaklay$ adb devices
List of devices attached
emulator-5554	device
```
install required nodejs package
```
npm install
```
and change Android configuration in test.js") and run command 
```
APPIUM_OS=android npm start
```
to start appium automation.

#Testing result
Automated running application with appium-flutter-driver
![Appium run flutter app](https://media.giphy.com/media/MdvgI6B0L0jKO8I39t/giphy.gif)

Console output as below 
{% asciinema 278591 %}


#Others Appium's command which I've tested.
```javascript
//Enter value to tartget TextInput
await driver.elementSendKeys(find.byValueKey('telphoneEditTxt'), '1234567890')

//Wait for element visible
await driver.execute('flutter:waitFor', find.byValueKey('page2Btn'));

//Screen scrolling
await driver.execute('flutter:scrollIntoView', find.byValueKey('bottomSubmitBtn'), {alignment: 0.1});

//Using Native command and switch context back to flutter
await driver.switchContext('NATIVE_APP');
  driver.back();
await driver.switchContext('FLUTTER');

//Tap on widget element
await driver.elementClick(find.byValueKey('backBtn'));

```

#Conclusion
I did not have strong opinion about appium-flutter-driver is the best way to do flutter app automate testing. But it help QA or automation tester to get familiar with flutter app testing since they can reuse their Appium which already mature to start automate flutter app testing and they can lower their guard about flutter which is very new platform and not much test tooling for it. By the way for flutter developer I think flutter-driver is enough for automate testing (since they already know dart :)). That all from me, comment, question and suggestion is welcome.