MaestroDSL

main

paulsamuels/MaestroDSL

A Swift DSL for the Maestro UI testing tool.

Starter Project

If you have Maestro installed in the default location you can open the StarterProject and hit run. Once you've trusted the macro and hit run again you should see the simulator launch and start adding a contact in the contacts app.

Basic Usage

Import the MaestroDSL package and declare a dependency on both MaestroDSL and MaestroDSLMacro (see the StarterProject/Package.swift for an example).

Now you can use the top level maestroRun command to build a flow to execute. A flow that would add a contact to the contacts app might look like this:

import MaestroDSL

try! maestroRun("com.apple.MobileAddressBook") {
    LaunchApp("com.apple.MobileAddressBook")
    
    TapOn(.text("Add"))
    
    TapOn(.id("First name"))
    Input("John")
    
    TapOn(.id("Last name"))
    Input("Appleseed")
    
    TapOn(.text("Done"))
}

Tip

In order to find the selectors to use for picking elements you can run maestro studio and click around to explore your app.

Page Objects

It's common in UI testing to introduce Page Objects to share logic and hide away the details of knowing selectors ids. In the above example knowing that the Add and Done buttons don't have ids but instead need looking up by text and that the text fields have ids is knowledge we want to share and not duplicate. You can do this by creating @Pages to represent the different screens. For the contacts app we have two screens - the HomePage and the EditFormPage so let's create those page objects

import MaestroDSL
import MaestroDSLMacro

@Page
struct HomePage {
    @FlowBuilder<HomePage>
    func tapAdd() -> Flow<HomePage> {
        TapOn(.text("Add"))
    }
}

The EditFormPage is more of the same

import MaestroDSL
import MaestroDSLMacro

@Page
struct EditFormPage {
    @FlowBuilder<EditFormPage>
    func setFirstName(_ name: String) -> Flow<EditFormPage> {
        TapOn(.id("First name"))
        Input(name)
    }

    @FlowBuilder<EditFormPage>
    func setLastName(_ name: String) -> Flow<EditFormPage> {
        TapOn(.id("Last name"))
        Input(name)
    }

    @FlowBuilder<EditFormPage>
    func tapDone() -> Flow<EditFormPage> {
        TapOn(.text("Done"))
    }
}

With these in place the original flow can now be expressed without mentioning identifiers

import MaestroDSL

try! maestroRun("com.apple.MobileAddressBook") {
    LaunchApp("com.apple.MobileAddressBook")
    
    HomePage {
        $0.tapAdd()
        
        EditFormPage {
            $0.setFirstName("John")
            $0.setLastName("Appleseed")
            $0.tapDone()
        }
    }
}

Acknowledgements

Original ideas came from mobbing with @adamcarter93, @ebent and @saadzulqarnain-at

Description

  • Swift Tools 5.9.0
View More Packages from this Author

Dependencies

Last updated: Fri Apr 12 2024 17:31:31 GMT-0900 (Hawaii-Aleutian Daylight Time)