Post

Detecting Process Death issues with Maestro

Maestro playing the flute to a serpent

After explaining what System-initiated Process Death is, showing how to detect it manually and automate detection with Appium, I’d like to demonstrate how to automate detection this time with Maestro, a relatively new Automation tool! πŸŽ‰

What is Maestro?

Maestro is a command line tool that allows us to run end-to-end UI tests, written in a simple YAML format.

Run the following command to install Maestro on Mac OS, Linux or Windows (WSL):

1
curl -Ls "https://get.maestro.mobile.dev" | bash

Using Maestro

Let’s go back to the demo project containing a fragment-based app built with two screens:

  • A first screen to enter a name called EnterNameFragment
  • Second one to show that information called ShowInfoFragment
  • To pass a name value between those screens, a Singleton called DataHolder is used, which will lose its value after System-initiated Process Death.

A file called happy-flow.yaml in a .maestro folder will contain the following maestro commands:

1
2
3
4
5
6
7
8
9
10
11
12
13
appId: dev.galex.process.death.demo
---
- launchApp
- tapOn:
      id: "dev.galex.process.death.demo:id/enter_name"
- inputText: "John Doe"
- tapOn:
      id: "dev.galex.process.death.demo:id/next"
- assertVisible:
      id: "dev.galex.process.death.demo:id/show_name"
      text: "Name = John Doe"
      enabled: true
- stopApp

We’ll run this test with the following command, from the demo project root folder:

1
maestro test .maestro/happy-flow.yaml

The result of running this test will show a successful run for our test:

1
2
3
4
5
6
7
8
9
10
11
12
Running on 41161FDJG002EG                                                                            
                                                                                                     
 β•‘                                                                                                   
 β•‘  > Flow                                                                                           
 β•‘                                                                                                   
 β•‘    βœ…  Launch app "dev.galex.process.death.demo"                                                  
 β•‘    βœ…  Tap on id: dev.galex.process.death.demo:id/enter_name                                      
 β•‘    βœ…  Input text John Doe                                                                        
 β•‘    βœ…  Tap on id: dev.galex.process.death.demo:id/next                                            
 β•‘    βœ…  Assert that "Name = John Doe", id: dev.galex.process.death.demo:id/show_name is visible    
 β•‘    βœ…  Stop dev.galex.process.death.demo                                                          
 β•‘   

Triggering The Issue with Maestro

Since version 1.37.0, which was finally released last week, Maestro offers the ability to trigger System-initiated Process Death using a command called killApp which I was very happy to introduce into to the Maestro project. Yay to Open-Source! πŸŽ‰

We’ll call this file appropriately detect-process-death-issue.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
appId: dev.galex.process.death.demo
---
- launchApp
- tapOn:
    id: "dev.galex.process.death.demo:id/enter_name"
- inputText: "John Doe"
- tapOn:
    id: "dev.galex.process.death.demo:id/next"
- assertVisible:
    id: "dev.galex.process.death.demo:id/show_name"
    text: "Name = John Doe"
    enabled: true
- pressKey: Home
- killApp
- launchApp:
    stopApp: false
- assertVisible:
    id: "dev.galex.process.death.demo:id/show_name"
    text: "Name = John Doe"
    label: "Assert that \"Name = John Doe\" meaning the screen kept its data after System-initiated Process Death"
    enabled: true
- stopApp

Let’s pay attention to the part that helps us reproduce the issue, with explanations in comments:

1
2
3
4
- pressKey: Home # Puts the app into the background
- killApp # Kills the app (adb shell am kill)
- launchApp: # Relaunches the app
    stopApp: false # Without adb shell am stop

We’ll run this test with the following command:

1
maestro test .maestro/detect-process-death-issue.yaml

The result of running this test will fail:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Running on 41161FDJG002EG                                                                                        
                                                                                                                 
 β•‘                                                                                                               
 β•‘  > Flow                                                                                                       
 β•‘                                                                                                               
 β•‘    βœ…  Launch app "dev.galex.process.death.demo"                                                              
 β•‘    βœ…  Tap on id: dev.galex.process.death.demo:id/enter_name                                                  
 β•‘    βœ…  Input text John Doe                                                                                    
 β•‘    βœ…  Tap on id: dev.galex.process.death.demo:id/next                                                        
 β•‘    βœ…  Assert that "Name = John Doe", id: dev.galex.process.death.demo:id/show_name is visible                
 β•‘    βœ…  Press Home key                                                                                         
 β•‘    βœ…  Kill dev.galex.process.death.demo                                                                      
 β•‘    βœ…  Launch app "dev.galex.process.death.demo" without stopping app                                         
 β•‘    ❌  Assert that "Name = John Doe" meaning the screen kept its data after System-initiated Process Death    
 β•‘    πŸ”² Stop dev.galex.process.death.demo                                                                       
 β•‘                                                                                                               
                                                                                                                 
Assertion is false: "Name = John Doe", id: dev.galex.process.death.demo:id/show_name is visible

==== Debug output (logs & screenshots) ====

/Users/galex/.maestro/tests/<date>

Perfect! We’ve successfully detected the System-initiated Process Death issue with Maestro! πŸŽ‰

In the generated folder /Users/galex/.maestro/tests/<date> we’ll find the screenshots taken by Maestro, showing the ShowInfoFragment screen with the text Name = null instead of Name = John Doe:

Faulty screen

Improving our Maestro Test

To be able to re-use the commands that allow us to trigger System-initiated Process Death, we can put them in another .yaml file named trigger-process-death.yaml:

1
2
3
4
5
6
appId: dev.galex.process.death.demo
---
- pressKey: Home # Puts the app into the background
- killApp # Kills the app (adb shell am kill)
- launchApp: # Relaunches the app
    stopApp: false # Without adb shell am stop

And use the runFlow command in our original detect-process-death-issue.yaml test to include it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
appId: dev.galex.process.death.demo
---
- launchApp
- tapOn:
    id: "dev.galex.process.death.demo:id/enter_name"
- inputText: "John Doe"
- tapOn:
    id: "dev.galex.process.death.demo:id/next"
- assertVisible:
    id: "dev.galex.process.death.demo:id/show_name"
    text: "Name = John Doe"
    enabled: true
- runFlow: trigger-process-death.yaml
- assertVisible:
    id: "dev.galex.process.death.demo:id/show_name"
    text: "Name = John Doe"
    label: "Assert that \"Name = John Doe\" meaning the screen kept its data after System-initiated Process Death"
    enabled: true
- stopApp

The output of running detect-process-death-issue.yaml will look almost the same as before:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Running on 41161FDJG002EG                                                                                        
                                                                                                                 
 β•‘                                                                                                               
 β•‘  > Flow                                                                                                       
 β•‘                                                                                                               
 β•‘    βœ…  Launch app "dev.galex.process.death.demo"                                                              
 β•‘    βœ…  Tap on id: dev.galex.process.death.demo:id/enter_name                                                  
 β•‘    βœ…  Input text John Doe                                                                                    
 β•‘    βœ…  Tap on id: dev.galex.process.death.demo:id/next                                                        
 β•‘    βœ…  Assert that "Name = John Doe", id: dev.galex.process.death.demo:id/show_name is visible                
 β•‘    βœ…  Run trigger-process-death.yaml                                                                         
 β•‘    ❌  Assert that "Name = John Doe" meaning the screen kept its data after System-initiated Process Death    
 β•‘    πŸ”² Stop dev.galex.process.death.demo                                                                       
 β•‘                                                                                                               
                                                                                                                 
Assertion is false: "Name = John Doe", id: dev.galex.process.death.demo:id/show_name is visible                  
                                                                                                                 
==== Debug output (logs & screenshots) ====                                                                      

/Users/galex/.maestro/tests/<date>

We’ve improved the re-usability of our detecting method!

Conclusion

We’ve successfully detected the System-initiated Process Death issue with Maestro! πŸ’ͺ It makes the whole ordeal so easy I seriously think an E2E Maestro test should be a part of every feature we build to ensure its quality and robustness! πŸš€

Let me know what you think or if you have any questions in the comments! πŸ“

Happy testing! πŸ§ͺ

This post is licensed under CC BY 4.0 by the author.