In this part of the maestro
series, I’ll try to walk through some commands that we testers, generally use when working with UI tests – these commands are the ones provided by maestro
library by default – you can just use them out of the box in the maestro
flow files.
If you’re looking at this directly, I’d rather suggest you to first take a look at these two earlier posts about the pre-work stuff and the installation before getting started with this.
In this series let’s dive into the assertions first.
Assertions
One of the most important part of a test is to assert something – a test without assertion is not really a test. So a good test has assertions as a part of it. Now this could be anything and there are lot of good libraries like Hamcrest or Chai (for JS/TS) that gives you a lot of meaningful extra assertion capabilities.
In maestro
, there are couple of assertions that comes out of the box – let’s take a look at them
- assertVisible
As the name suggests, this assertion checks that the element is visible or available on the UI – kind of the isVisible
checks that a lot of web based UI automation frameworks offer.
You can simply use this as
- assertVisible : "MyTextLocator"
You can also check if the element is visible and enabled by added an enabled
check in the check
- assertVisible:
text: "MyText"
enabled: true
If either of the two conditions – locator with text “MyText” is not present or the element is present but it is not enabled.
- assertNotVisible
This is just the opposite of the earlier assertVisible
assertion. This assertion checks that the UI element is not visible on the UI
You can simply use this as
- assertVisible : "MyTextLocator"
This assertion will pass if the element with text “MyTextLocator” is not visible on the UI.
Let’s see this working in the action in this small video
In this video – the script that is executed is given below – and apart from the assertions, you can see the use of some commands like back
and home
– which I’ll probably explain later.
# second-flow.yaml
appId: hibernate.v2.testyourandroid
---
- launchApp
- tapOn: "Flashlight"
- assertVisible : "Turn on Flashlight"
- assertNotVisible: "Flaslight"
- tapOn: "Turn on Flashlight"
- back
- pressKey: home
- assertTrue
If you need to check if something is true than you need to use assertTrue
assertion – this is basically checking if something is truthy
in JS terms.
A simple example is that let’s say you want to assert that the added item count in cart is 1 – so you can check that the value of the item is basically true.
The only caveat in the tests that I’ve noticed in maestro
is that if you want to check something like
expect(somevalue).to.eq(1)
then you cannot directly match it to a numerical value. So instead of defining the numerical value directly, I can define this value inside the env
key inside the file. I’ll just post a simple example below
appId: com.appid.someappID
name: test Flow
tags:
- test
- app-functional-tests
env:
CART_COUNT: 1
---
- copyTextFrom:
id: "someidofcart"
- assertTrue: ${maestro.copiedText == CART_COUNT}
Now let me explain what is happening in this test.
I want to validate that the cart count is 1 after I add an item to the cart. So I’ve defined the constant as CART_COUNT
inside the env
key.
Now, what I’ve done in the lines 9-11 is that I’ve used the command copyTextFrom
to get the text from the element with id “someidofcart“, and then I’m asserting that the copied text equals to the one I’ve defined in the CART_COUNT
value.
Waiting
Second thing which I think so is important for a lot of UI automation is the waiting consideration. You might need to wait for an element to finish being loading or being visible on the UI or it could be also true that you want to wait for it to become not visible – lets say a loader.
Even though maestro
or many other UI libraries claim that they have auto waiting
mechanism that waits for an element before performing user defined actions -Playwright calls them actionability checks btw, there are a lot of times, when these waits are simply not enough to make the UI stable enough.
So, libraries provides additional commands for the script to pause execution or wait for some time specific to conditions – if you’re coming from Selenium background, it would be like knowing implicit and explicit waits.
maestro
provides two default waiting statements that you can use in your tests –
- extendedWaitUntil
Very similar to the Explicit wait that you’ve in Selenium. If you want to wait until an element becomes visible or not visible on the UI, then you can use this command. Additionally you can also give a timeout
period until it will wait for the specific condition
- extendedWaitUntil:
visible: "Get Started" # or any other selector
timeout: 5000
In the above command, the UI will wait for 5 seconds for the locator with text Get Started
to appear – if it does appear before 5 seconds, then the next action will be performed – maestro
by default will not wait for all 5 seconds if the element is found within this time frame.
Similarly if you want to wait for an element to be not visible, then you can use notVisible
condition with the wait statement to wait for element to disappear from UI
- extendedWaitUntil:
notVisible: "Get Started" # or any other selector
timeout: 5000
- waitForAnimationToEnd
If your page has some kind of animation, and you want to wait for the animation to finish, before interacting with the UI elements, then you can use this wait for the animation to finish.
It can also be used with a timeout
condition, after which the action will be marked as finished and the flow will start interacting with the elements (irrespective if the animation finished or not)
- waitForAnimationToEnd:
timeout: 5000
A sample test script with the conditional wait could be like this
# betterment-launchapp.yaml
appId: com.betterment
---
- launchApp
- waitForAnimationToEnd:
timeout: 5000
- assertVisible: "Investing made better."
- extendedWaitUntil:
visible: "Get Started" # or any other selector
timeout: 5000
#- takeScreenshot: MainScreen
- tapOn: "Log in"
- inputText: "Hello World"
- inputRandomText
- back
Other Commands
Since we’ve seen the assertions and waits that can be used in tests, lets move on to some other commands that could be useful for the tests that we can write
- back
If you want to simulate a back
command in the app action, then simply type this command in the flow
- back
- pressKey
If you want to simulate a keypress in the app tests, then you can use the pressKey
command . So let’s say we want to test the that if you click on Home, then you’re at home
then you can use this command
- pressKey: home
In this video, you can see that the last two lines of the script simulates both the back
and the pressKey
actions.
- takeScreenshot
If you want to take the screenshot of the UI screen, then you’d need this command – the parameter that you pass is just the name that you’d want to save the screenshot with. For example, if you want the screenshot to be named Homescreen.png
, you can just give like this
- takeScreenshot : Homescreen
But there are a few draw backs that I’ve noticed with this command and how this works
- You cannot specify a directory to keep your screenshots (sad). All images are directly stored in the same directory as code.
- You cannot generate a user generated name for screenshots. You’ve to give it before hand in the test script itself.
- The screenshot will only be a
.png
file – which is lightweight. - You cannot take screenshot of an element – this screenshot command takes screenshot of whole screen.
You can see from the image below that the screenshot resides in the same present directory from where you execute code – it cannot be changed ( or at least I don’t know how to change it).
- clearState
If you want to tests to start from a fresh slate, then you need to clean the state of the app – since a lot of times, app store the state of the user action. So , you’d probably need to do this as either in the start or end of the tests
- clearState
These are some basic commands that I found useful when I was experimenting with maestro
. Off course there are other commands, which you can find in the documentation here.
In the next portion, I’ll try to run a complete flow. and will try to demonstrate how we can re-use flows in different files.