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:
- Open the flutter application project in your IDE (VS Code preferred).
- Start the emulator.
- Select Run & Debug option from the left menu.
- Now, click on the play button. If the play button is not visible, follow the steps below; otherwise, go to step 8.
- Click on Run & Debug.
- Select Dart & Flutter.. option.
- Then select Flutter your_application_name.
- Now, click on the play button.
- Once the application is running on the emulator, click on the devtools option from the toolbar at the top. Refer to the image below:
- A Widget Inspector window should have opened. Select the widget mode option. Refer to the image below:
- Open the emulator and click on the element you want to locate.
- The code snippet relative to the element should be visible in the code editor.
- 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:
- 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'
- 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.
- appium:platformVersion: This specifies the version of the OS running on your emulator/simulator.
- appium:automationName: This specifies the name of the automation you are using to automate the app. If you are using
Flutter
automationName, you must addappium-flutter-driver
to your project's dependencies. Eg. 'UIAutomator2', 'XCUITest'. - 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')
Note: It is advised to use the 'byValueKey' locator for locating elements as it is more reliable than others.
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:
- Open the Flutter application. (If not present, create a sample app using this documentation)
- Do the configurations added in this documentation to enable automation testing for the app.
These configuration are important for automation testing. The automation script will not work if the configurations are not done properly.
- Locate elements which you want to automate using the Locate Elements in Flutter App section of this documentation.
- Add keys to those elements. Refer to this documentation.
- After making all the changes within the app code, run the app again.
- Setup a automation project for testing. Refer to this documentation.
- Write automation script for the app.
- Run the automation script using the commands mentioned in this documentation.
- For a sample script, refer to this documentation.