Mendix Mobile Test Automation with Appium — Part I

Vinicius Strugata Ambrosio
6 min readJun 4, 2023

--

How can we ensure the quality of our apps without tests? And how can we be efficient in Quality Assurance without automated tests? In my opinion, automated tests are a fundamental prerequisite for any project, mobile or web. This article intends to show how can you achieve this using Appium with a Mendix Native Mobile Application.

ANDRZEJ WOJCICKI/SCIENCE PHOTO LIBRARY — Getty Images
ANDRZEJ WOJCICKI/SCIENCE PHOTO LIBRARY — Getty Images

As a mobile project progresses, ensuring that all requirements remain met becomes increasingly complex. Automated tests help to minimize the associated costs while helping to keep the project challenges under control. But how can we do automated tests in a low-code platform like Mendix? Well, for a Web Application, you can use tools like Selenium or Cypress. And for Native Applications, you can use Appium. The latter is the subject of this article, using a Mendix Native Mobile Application to be automated.

Scenario

Let’s consider you have a Mendix Native Mobile Application Project and plan to ensure and improve the quality of your final application by using automated tests. There are several types of tests, and explaining all of them is beyond the scope of this article. Here we’ll focus only on end-to-end tests using Appium.

Our app is very simple: it takes two numbers and displays the results of their sum.

Use case: the correct sum of two numbers

Procedure

  • [1] Connect your Android physical device to your computer via USB. If you prefer, can use a screen mirror software like ScrCpy. In addition, enable USB debugging on your device. It’s also possible to use an Android Emulator.
    – Since Android Studio Flamingo, you can also mirror your device from the IDE!
  • [2] [Optional] Assuming you already have a Mendix Native Mobile Project created, I recommend building a Custom Developer App specific to your project. It’s possible to use Make it Native 9 for this, but I personally always prefer to create my custom developer app launcher.
  • [3] Get the Application Package Identifier: if you are using a Custom Developer app, this identifier is the one defined in the NBUI tool, followed by .developerapp. The complete value would be like myapp.appiumapp.developerapp. If you are using Make it Native 9, the value is com.mendix.developerapp.mx9.
NBUI showing the App identifier
  • [4] Get the Application Activity Identifier: for the Custom Developer App is com.mendix.nativetemplate.MainActivity. For Make it Native 9, is com.mendix.developerapp.MainActivity.
  • [5] [Hint] You can get both values at once by running the command line below on Windows Power Shell (You must have Android SDK Tools installed):
adb shell dumpsys window windows | findStr 'imeLayeringTarget'
  • For Make it Native 9, the result is:
imeLayeringTarget in display# 0 Window{b871f63 u0 com.mendix.developerapp.mx9/com.mendix.developerapp.MainActivity}
  • Check the pattern appPackage/appActivity at the end of the command line output:
Run the command line while the application is running on the device
  • [6] Install Appium by running the command line below
npm i -g appium@next
  • [7] Install Appium UI Automator 2 driver
appium driver install uiautomator2
  • [8] Install Appium Inspector. It’s possible to use the Appium web app, but for the purposes of this article, and also for security reasons, I prefer using the desktop version
  • [9] Start Appium Server
appium
  • [10] Execute Appium Inspector and configure the Desired Capabilities as shown in the image (you can copy&paste the snippet below):
Appium Inspector: capabilities defined to run the Custom Developer App
{
"platformName": "Android",
"appium:automationName": "UiAutomator2",
"appium:appPackage": "myapp.appiumapp.developerapp",
"appium:appActivity": "com.mendix.nativetemplate.MainActivity",
"appium:noReset": true
}
  • [11] Click the Start Session button. This will launch the application “inside” Appium Inspector, allowing you to inspect the widget structure tree and interact with your app UI:
Appium Inspector: showing the Custom Developer App Launcher widget structure. Click on the desired widget to get details
  • [12] In the Appium Inspector UI, we can record the actions performed in your app, so that is possible to play such actions again afterward. To do that, click on the eye icon
Enabling the Recording feature
  • [13] Using the commands available after you select an element, proceed with the usual actions you would do if having the device in your hands. Many languages are available for recording the commands, but I prefer Python. For example, the first interaction to be recorded would be: i) Type the URL to http://192.168.0.71:8080/ in the textEdit — using the Send Keys command — and then ii) Hit the LAUNCH button — using the Tap command.
Appium Inspector: showing the recorded actions on the app
Tap and Send Keys: commands you can perform on the selected element
  • [14] At this point, Appium Inspector should be showing the application’s main page with our simplified calculator. We can continue recording the actions: iii) Select the first textBox, tap on it, clear its contents, and type 5. iv) Select the second textBox, tap on it, clear its contents, and type 2. v) Tap on any area outside the widgets, to hide the keyboard. vi) Finally, select the Calculate button and tap on it. All commands will be recorded, as shown below:
Appium Inspector: the recorded JS script with the sequence of actions performed on the app
  • [15] The full code can be copied to the clipboard. Click Show/Hide boilerplate code and then click Copy code to clipboard.
Action buttons to show and copy the code
# This sample code uses the Appium python client v2
# pip install Appium-Python-Client
# Then you can paste this into a file and simply run with Python

from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy

# For W3C actions
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.actions import interaction
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.actions.pointer_input import PointerInput

caps = {}
caps["platformName"] = "Android"
caps["appium:automationName"] = "UiAutomator2"
caps["appium:appPackage"] = "myapp.appiumapp.developerapp"
caps["appium:appActivity"] = "com.mendix.nativetemplate.MainActivity"
caps["appium:noReset"] = True
caps["appium:ensureWebviewsHavePages"] = True
caps["appium:nativeWebScreenshot"] = True
caps["appium:newCommandTimeout"] = 3600
caps["appium:connectHardwareKeyboard"] = True

driver = webdriver.Remote("http://127.0.0.1:4723", caps)

el1 = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="appUrl")
el1.send_keys("http://192.168.0.71:8080/")
el2 = driver.find_element(by=AppiumBy.ID, value="myapp.appiumapp.developerapp:id/launch_app_button")
el2.click()
el3 = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="Value1")
el3.click()
el3.clear()
el3.send_keys("5")
el4 = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="Value2")
el4.click()
el4.clear()
el4.send_keys("2")
el5 = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="Result, Result")
el5.click()
el6 = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="Calculate, ")
el6.click()

driver.quit()
  • [16] Since we chose to use Python a scripting language, you must first install the Appium dependencies
pip install Appium-Python-Client
  • [17] Finally, after copying the code into a file called script.py, we can run the command and cross our fingers to see if it runs successfully:
python .\script.py
  • [18] And to our disappointment, the result is an ERROR!
...
Traceback (most recent call last):
File "D:\coe\projetos\appium\AppiumApp\tests\script.py", line 32, in <module>
el3 = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="Value1")
...
selenium.common.exceptions.NoSuchElementException: Message: An element could not be located on the page using the given search parameters.
Stacktrace:
NoSuchElementError: An element could not be located on the page using the given search parameters.
...

Going to Fast …

The reason for the above error is that the Custom Developer App has not yet had time to load the package with Mendix Code. We must instruct the script to wait a little while the code is still loading. Add the code driver.implicitly_wait as below:

...
driver = webdriver.Remote("http://127.0.0.1:4723", caps)
driver.implicitly_wait(5000)
...

It’s like magic!

After this small correction in the generated code, finally, we can run the code without errors:

Appium controlling our Mendix Application!

Conclusions & Next Steps

As you can see, automation is a valuable tool during code development. In this simple example, this is not so evident, but imagine a complex flow with many steps to reach a given page … This script can be useful either for the developer or for the testing guy reaching that page.

But the script generated by the Appium Inspector is not yet the code we can use for testing. It is just a snippet we can use to write the definitive code, with the AAA Test Pattern (Arrange, Act & Assert).

This will be the subject of Part II of this article, so stay tuned!

Let’s go Making (with quality)!

References

--

--