How to clear the state of the app in Maestro tests (iOS)
While UI testing may seem straightforward at first glance, it can quickly become complex, especially when dealing with various app states. One of the main challenges is preparing the app for different test scenarios.
The Issue with Clear State
Many developers resort to using -clearState
, but this approach has limitations. It not only removes essential properties that indicate the app's current state (such as showOnboarding
or askUserForRating
) but can also be unreliable. As a result, we must account for numerous scenarios in our UI tests. This method may work for small, simple apps, but it becomes unmanageable as the application grows in complexity.
A More Effective Solution
To address this problem, we can leverage the launchArguments
property. By passing a flag to the app, we can indicate that it's running in UI test mode. This approach allows us to:
- Maintain better control over the app's state during testing
- Avoid clearing crucial state indicators
- Improve test reliability and maintainability
Implementing this solution involves catching the launch argument in the app's initialization process, enabling us to set up the desired state for each test scenario more effectively.
Implementing the Launch Arguments Solution
To address the state management issue in UI testing, we utilize the launchArguments
property. This allows us to pass a flag to the app, indicating that it's running in UI test mode. We can intercept this flag in the app's launch cycle, specifically in the application(_:didFinishLaunchingWithOptions:)
method.
In the YAML File: We define the launch arguments for our UI tests. This configuration tells the testing framework to launch the app with a specific flag:
appId: com.example.staging
---
- launchApp:
appId: com.example.staging
arguments:
isUITestRunning: true
In the App's AppDelegate: We then handle this flag in our app's launch cycle. The app checks for the presence of the isUITestRunning
argument and resets the state accordingly:
func application(
_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
resetStateIfUITestIsRunning()
return true
}
private func isUITestRunning() {
if ProcessInfo.processInfo.arguments.contains("isUITestRunning") {
// Set or delete your settings here
}
}
And that's it.
Happy coding!