Suppose you are developing Android and iOS apps and want to write UI tests for both using the Maestro UI testing framework. Maestro is a versatile UI testing framework ideal for Android and iOS applications.
In this blog, we will focus on using Maestro’s key features, such as runFlow
, runScript
, and external parameters, to demonstrate the best practices for cross-platform testing. We will use a NASA wallpaper app built with Jetpack Compose for Android and SwiftUI for iOS as an example. However, the methodology we cover is applicable to any Maestro-supported frameworks, such as Flutter, React Native, UIKit, Android View and more!
The apps will have similar UI with minor differences, we will go through all of them as we UI test!
Prerequisites
If you want to follow along or want to try out running the test commands yourself, please download the code and run it!
Source Code: https://github.com/thekharche/maestro-nasa-wallpaper-kmm
Instructions to run the Android and iOS apps are in the README file of the GitHub code.
Let’s take a closer look at our Android and iOS apps!
Please refer to the app screenshots above when reading the flow files to have a better understanding of the UI being tested!
Setting App ID Using Environment Variables
If you need to run the same flow for apps with different app IDs, you can pass an external parameter for appId
. Provide the APP_ID
parameter to Maestro as follows:
maestro test -e APP_ID=com.wallpapers.androidapp .maestro/wallpapers/ListDetailWallpaper.yaml
In our case for the iOS app, we need to use use com.wallpapers.iosapp
Then, refer to it in your flow by using ${APP_ID}
:
.maestro/wallpapers/ListDetailWallpaper.yaml
appId: ${APP_ID}
---
- launchApp
Handling Different Element IDs with runScript
Consider a scenario where you want to tap an image to enter the details screen, but the element IDs for the image on Android and iOS are different. For instance, Android uses wallpaperImage
and iOS uses imageItem
. To have one Maestro flow file test both IDs without modifying the source code, you can use the runScript
feature.
Conditional runScript
is available from version 1.28.0 of Maestro!
.maestro/wallpapers/ListDetailWallpaper.yaml
- runScript:
when:
platform: iOS
file: ios/init.js
- runScript:
when:
platform: Android
file: android/init.js
- tapOn:
id: ${output.wallpapers.wallpaperItem}
index: 0
.maestro/wallpapers/android/init.js
output.wallpapers = {
wallpaperItem: 'wallpaperImage',
}
.maestro/wallpapers/ios/init.js
output.wallpapers = {
wallpaperItem: 'imageItem',
}
The tapOn
command utilizes the id
from the output of the respective JavaScript file.
Conditional Execution with runFlow
In a scenario where Android does not display a date in the detail view but iOS does, you can use runFlow
to conditionally test the date requirements for the iOS platform.
.maestro/wallpapers/ListDetailWallpaper.yaml
- runFlow:
when:
platform: iOS
file: Date.yaml
The Date.yaml
flow file will only be invoked when the platform is iOS.
.maestro/wallpapers/Date.yaml
appId: ${APP_ID}
---
- assertVisible: ".*2023-.*"
Using Inline Commands with runFlow
Assume the iOS app does not yet support setting a wallpaper image, but the Android app does. You can use runFlow
with inline commands to conditionally test this feature on the Android platform.
.maestro/wallpapers/ListDetailWallpaper.yaml
- runFlow:
when:
platform: Android
commands:
- assertVisible:
id: "setWallpaperIconButton"
- tapOn:
id: "setWallpaperIconButton"
Testing Platform-specific Features using runFlow
Both Android and iOS have different methods for displaying the Share drawer or bottom sheet. Using runFlow
, you can test the behaviour of the share feature on both platforms.
.maestro/wallpapers/ListDetailWallpaper.yaml
- runFlow:
when:
platform: iOS
file: ios/Share.yaml
- runFlow:
when:
platform: Android
file: android/Share.yaml
ios/Share.yaml
appId: ${APP_ID}
---
- tapOn:
id: "shareIconButton"
- assertVisible: ".*Copy.*"
- assertVisible: ".*Print.*"
android/Share.yaml
appId: ${APP_ID}
---
- tapOn:
id: "shareIconButton"
- assertVisible: ".*Nearby.*"
- assertVisible: ".*Edit.*"
Complete Maestro Flow File
.maestro/wallpapers/ListDetailWallpaper.yaml
appId: ${APP_ID}
---
- launchApp
- runFlow: Date.yaml
- runScript:
when:
platform: iOS
file: ios/init.js
- runScript:
when:
platform: Android
file: android/init.js
- tapOn:
id: ${output.wallpapers.wallpaperItem}
index: 0
- assertVisible: ".*alien.*"
- runFlow:
when:
platform: iOS
file: Date.yaml
- runFlow:
when:
platform: Android
commands:
- assertVisible:
id: "setWallpaperIconButton"
- tapOn:
id: "setWallpaperIconButton"
- runFlow:
when:
platform: iOS
file: ios/Share.yaml
- runFlow:
when:
platform: Android
file: android/Share.yaml
Conclusion
By following these best practices, you can effectively test your apps using the Maestro UI testing framework. These cross-platform UI testing techniques ensure that your tests remain maintainable, scalable, and compatible with both Android and iOS platforms.
References
runFlow:
runScript:
external parameters:
NASA Wallpaper App Source Code: