TESTEROPS

A pragmatic approach to QA and OPS

Assertions, Waiting and other commands

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.

  • Maestro – pre work stuff : Link
  • Installation and first script : Link

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

  1. You cannot specify a directory to keep your screenshots (sad). All images are directly stored in the same directory as code.
  2. You cannot generate a user generated name for screenshots. You’ve to give it before hand in the test script itself.
  3. The screenshot will only be a .png file – which is lightweight.
  4. 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.