A Swift DSL for the Maestro UI testing tool.
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.
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.
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 id
s is knowledge we want to share and not duplicate.
You can do this by creating @Page
s 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()
}
}
}
Original ideas came from mobbing with @adamcarter93, @ebent and @saadzulqarnain-at