Mobile

Basics - Mobile Automation

Introduction

This documentation is all about getting started with the Flutter app automation using WebdriverIO. Here you will learn about all the concepts required to automate a flutter app using WebdriverIO and appium.

Locate Elements in Flutter App

To locate the elements in the flutter app, follow the steps mentioned below:

  1. Open the flutter application project in your IDE (VS Code preferred).
  2. Start the emulator.
  3. Select Run & Debug option from the left menu.
  4. Now, click on the play button. If the play button is not visible, follow the steps below; otherwise, go to step 8.
  5. Click on Run & Debug.
  6. Select Dart & Flutter.. option.
  7. Then select Flutter your_application_name.
  8. Now, click on the play button.
  9. Once the application is running on the emulator, click on the devtools option from the toolbar at the top. Refer to the image below:
  10. A Widget Inspector window should have opened. Select the widget mode option. Refer to the image below:
  11. Open the emulator and click on the element you want to locate.
  12. The code snippet relative to the element should be visible in the code editor.
  13. Repeat the same steps to locate all the elements.

Appium Configuration for App.

Before working with the automation script for the Flutter app, we need to understand the different capabilities that Appium offers for mobile testing.

For mobile, we need different capabilities that we need to add to the wdio.conf.js file. Refer to the code snippet given below:

capabilities: [{
        platformName: 'Android',
        'appium:deviceName': 'P7A34',
        'appium:platformVersion': '14',
        'appium:automationName': 'Flutter',
        'appium:app': 'Complete path of your apk/runner app file',
        'appium:autoGrantPermissions': true,
}]

Let's look at each of these capabilities one by one:

  1. platformName: It is used to specify the name of the platform on which you are trying to run your tests. e.g. 'Android' and 'iOS'
  2. appium:deviceName: It is used to specify the name of the device on which you are trying to execute your tests. This should be the exact name of the emulator/simulator device.
  3. appium:platformVersion: This specifies the version of the OS running on your emulator/simulator.
  4. appium:automationName: This specifies the name of the automation you are using to automate the app. If you are using Flutter automationName, you must add appium-flutter-driver to your project's dependencies. Eg. 'UIAutomator2', 'XCUITest'.
  5. appium:app: This is used to specify the path of the apk/app runner file that you are testing.

Apart from the capabilities mentioned above, there are a few important ones available. Let's go through them in brief:

appium:autoGrantPermissions

This capability is used to handle permissions within the app. If this is set to true all the permissions within the app are automatically granted. Accepted values: true or false

'appium:autoGrantPermissions': true

appium:noReset

Setting 'appium:noReset' to false ensures that the application state is not reset between sessions, allowing for continuous testing without reinstalling or clearing app data. Accepted values: true or false

'appium:noReset': false,

appium:fullReset

By setting 'appium:fullReset' to false, you can prevent the application from being completely uninstalled and reinstalled between test sessions, preserving data and configurations for efficient and targeted testing. Accepted values: true or false

'appium:fullReset': false,

appium:appWaitDuration

Setting 'appium:appWaitDuration' defines the duration in milliseconds for which Appium will wait for the app to be ready before timing out, ensuring smoother test execution by allowing sufficient time for the application to load completely. Accepted values: timeout in milliseconds.

'appium:appWaitDuration': 20000,

appium:orientation

Setting 'appium:orientation' specifies the initial orientation (landscape or portrait) of the device or emulator before starting the test session, ensuring consistent testing conditions for applications that rely on specific screen orientations. Accepted values: landscape or portrait

'appium:orientation': 'landscape'

There are many more capabilities under Appium that are available for mobile. Refer to this documentation to learn more.

Selectors

To locate a Flutter element using WebdriverIO, we need a separate package called appium-flutter-finder. This package contains several functions that help us locate a Flutter element within the automation script.

There are 4 locators that are available in package appium-flutter-finder. Let's look at each of them one by one.

1. byValueKey

This is used to locate an element using the key widget added to the element. This is the same as the id we use for web elements.

Flutter Code:

floatingActionButton: FloatingActionButton(
    key: const Key('plus_btn'),
    onPressed: _incrementCounter,
    tooltip: 'Increment',
    child: const Icon(Icons.add),
),

WebdriverIO Code:

import find from 'appium-flutter-finder'
const btn = find.byValueKey('plus_btn');

2. byText

This is used to locate an element using the text in the element.

Flutter Code:

const Text(
    'This is button',
),

WebdriverIO Code:

import find from 'appium-flutter-finder'
const text = find.byText('This is button');

3. byType

This locator strategy is used to locate an element using the type of the element in Flutter code.

Flutter Code:

child: TextField(
    obscureText: true,
        decoration: InputDecoration(
            border: OutlineInputBorder(),
            labelText: 'Password',
),
),

WebdriverIO Code:

import find from 'appium-flutter-finder'
const textfield = find.byType('TextField');

4. byTooltip

This locator strategy is used to locate an element using the tooltip text added to the input field. Flutter Code:

Tooltip(message: "Hello World", child: new Text("foo"));

WebdriverIO Code:

import find from 'appium-flutter-finder'
const textfield = find.byTooltip('Hello World')

Methods

In this section, we go through different methods available in WebdriverIO that help us automate the Flutter app. For this, we need a separate package called appium-flutter-driver. This package includes all the functions needed to automate a Flutter app. Let's look at them one by one.

elementClick

This method is used to click/tap on an element within the app.

const button = find.byValueKey('key_value');
await driver.elementClick(button);

elementSendKeys

This method is used to input values into an element.

const username = find.byValueKey('username');
await driver.elementSendKeys(username, 'test@gmail.com');

pause

This method is used to add waits/pauses during the test execution.

await driver.pause(3000) //wait duration in milliseconds

elementClear

This method is used to clear the value inside an element.

const username = find.byValueKey('username');
await driver.elementSendKeys(username, 'test@gmail.com');
await driver.elementClear(username);

getElementText

This method is used to fetch the text inside an element.

const heading = find.byValueKey('heading');
const text = await driver.getElementText(heading);

terminateApp

This method is used to terminate the app that is running during the test. It takes app_id as a parameter.

await driver.terminateApp('app_id');

activateApp

This method is used to activate the app using the specific app ID. The app should be installed on the device before performing this.

await driver.activateApp('app_id');

To explore more about the methods available in appium-flutter-driver, refer to this documentation by github.com

Commands

Apart from the methods, there are several commands available for the Flutter app that we can use to add waits, scrolls, etc. using the execute() method.

scroll

Used to scroll to a specific location within the app.

await driver.execute('flutter:scroll', find.byType('ListView'), {dx: 50, dy: -100, durationMilliseconds: 200, frequency: 30})

scrollIntoView

Used to scroll into a view of a specific element within the app.

await driver.execute('flutter:scrollIntoView', find.byType('TextField'), {alignment: 0.1})
await driver.execute('flutter:scrollIntoView', find.byType('TextField'), {alignment: 0.1, timeout: 30000})

waitFor

Used to wait for a specific element within a timeout period.

await driver.execute('flutter:waitFor', buttonFinder, 100)

waitForAbsent

Used to wait for an element to disappear from the viewport.

await driver.execute('flutter:waitForAbsent', buttonFinder)

To know more about the commands available with the execute method, refer to this documentation by github.com.

Assertions

There is no default assertion available in WebdriverIO for mobile applications. To add assertions in our script, we use the chai assertion module.

First, we need to install the package using the following command:

npm i chai --save-dev

After the package is installed, we can import and use the expect method inside the chai module.

Assert using Text

To assert your tests with matching text, use the command given below:

import { expect } from 'chai'

const element = await find.byValueKey('heading');
const text = await driver.getElementText(element);
expect(text).to.equal('expected_value');    //matches the exact expected value with the text.
expect(text).to.include('expected_value');  //matches a part of expected value with the text

Assert if an element is displayed or not.

To assert if an element is displayed on the app or not, we have to use error handling with the flutter:waitFor command.

We have to create a custom function with command the flutter:waitFor and error handling. Refer to the code below:

import { expect } from 'chai' 

async isDisplayed(element, milliSeconds = 1000) {
    try {
        await driver.execute('flutter:waitFor', element, milliSeconds);
        return true;
    } catch (error) {
        return false;
    }
}


const element = await find.byValueKey('heading');
expect(await this.isDisplayed(element)).to.be.true;

There are many more methods available with chai/expect. Refer to this documentation by chaijs.com.

How to Execute Script on Flutter Application

To run the sample automation script of a Flutter app, there are several steps we need to follow to enable automation testing for Flutter application. Refer to the steps given below:

  1. Open the Flutter application. (If not present, create a sample app using this documentation)
  2. Do the configurations added in this documentation to enable automation testing for the app.
  3. Locate elements which you want to automate using the Locate Elements in Flutter App section of this documentation.
  4. Add keys to those elements. Refer to this documentation.
  5. After making all the changes within the app code, run the app again.
  6. Setup a automation project for testing. Refer to this documentation.
  7. Write automation script for the app.
  8. Run the automation script using the commands mentioned in this documentation.
  9. For a sample script, refer to this documentation.

Copyright © 2024