View element - test subject

The View element test subjects represents a piece of the app's UI.


Please note that in case of Android WebView applications, the coordinates and sizes entered by the user are supposed to be in CSS Pixels and not the device pixels. Suitest automatically recalculates the number based on device's screen pixel density.

In Test editor:

Check that the logo is positioned correctly

In the JavaScript API:

await suitest.assert.element('logo').matches([
    PROP.HEIGHT,
    PROP.IMAGE,
    PROP.LEFT,
    PROP.TOP,
    PROP.WIDTH,
]);

Every application consists of many view elements. Suitest provides a way to select a particular element through a set of identifying properties and save it to the Element repository along with a snapshot of their state.

You can then make assertions on the elements from repository (or, in case of JavaScript API, with elements selected on the fly).

Built-in element operations

Following operations are available:

  • exists - checks that element exists.

  • does not exist - checks that the element does not exist.

  • has properties - compares the current properties of the element (such as width, color, background, etc.) with the expected values.

  • matches JS - passes a reference to the view element into a user-defined JavaScript function and expects it to return the comparison result.

  • visible - checks that the element is visible.

  • not visible - checks that the element is not visible.

Validating element existence

  • on all platforms

In Test editor:

Check that the play button exists and the pause button is missing

In JavaScript API:

await suitest.assert.element('logo').exists();
await suitest.assert.element('login').doesNot().exist();

This operation checks for a physical existence of the element inside the application. The element may however be hidden or obscured by other elements in which case you should use the has properties or visible action.

Validating element properties

  • on all platforms

The has properties action can be used to test whether specific properties of the element match the expectations of the test.

In Test editor:

Image width expected to be between 60 and 80 pixels.

In JavaScript API:

const {assert, PROP, COMP} = suitest;
// avoid having to write suitest infront of assert, prop and comp.

await assert.element('logo').matches([
    PROP.IMAGE,
    {
        name: PROP.WIDTH,
        val: 60,
        type: COMP.EQUAL_GREATER,
    },
    {
        name: PROP.WIDTH,
        val: 80,
        type: COMP.EQUAL_LESSER,
    },
]);

To compare property values following operations are available:

  • = - equal
  • != - not equal
  • - is in range (i.e. width between 50 and 100 pixels)
  • > - greater than
  • >= - greater than or equal
  • < - less than
  • <= - less than or equal
  • contains - contains expected string
  • does not contain - does not contain the expected string
  • ends with - ends with the expected string
  • does not end with - does not end with the expected string
  • starts with - starts with the expected string
  • does not start with - does not start with the expected string

Validating element visibility

  • Android
  • Browsers
  • HbbTV / Freeview Play
  • LG webOS
  • NextGen TV / ATSC 3.0
  • PlayStation 4/5
  • Roku
  • Samsung Tizen
  • Sky
  • VIDAA
  • Vizio SmartCast
  • Xbox (One, Series X/S)
  • Xfinity / Xumo TV / XClass TV
  • Xumo (Entertainment OS)
  • Other Smart TVs and STBs - HTML apps

The visible action can be used to test whether the element is visible.

Check if the "logo" element is visible

In JavaScript API:

await assert.element('logo').visible();
await assert.element('logo').not().visible();

not visible assertion makes sure that element is present in the page structure, but is not currently shown. In case element is not present in the page structure, this line would result in assertion failure with corresponding error message.

Comparing properties to the element snapshot

  • on all platforms

You can compare element properties to a static value or to a value currently contained inside the element repository. Comparing against element repository has a lot of advantage, since when the application ever changes only the repository needs to be updated to make the tests work again.

The button width is compared against repository snapshot, but the text contained inside the button is expected to always be equal to "Play now". Clicking on the yellow icon would revert the comparison back to the repository version

The same in JavaScript API:

await suitest.assert.element('login').matches([
    {
        name: suitest.PROP.TEXT_CONTENT,
        val: 'Play now',
    },
    suitest.PROP.WIDTH,
]);

Checking image loading state

You can check the element's image loading state property (on HTML-based platforms). The property is available for elements with the img tag.

Background images: This property is unavailable for any background images (for example in div tags). The unknown state will always be returned in this case.

You can check for the following states:

  • Loaded - image has been fully loaded.
  • Loading - image is currently loading.
  • Error - image was not loaded successfully.
  • Unknown - element image loading state cannot be captured. Due to old device or background image.
  • Empty - no image within this element.

Check that the image has loaded within 5 seconds

In JavaScript API:

await suitest.assert.element('My Element').matches([
    {
        name: PROP.IMAGE_LOAD_STATE,
        val: suitest.IMAGE_LOAD_STATE.LOADED,
    },
    ]).timeout(5000);
}

Running a JavaScript comparison function

If you need to make a very specific comparison use the matchesJS operation.

INFO: The assertion is called every 500 ms.

In Test editor:

Assert image is in 16:9 format (aspect ratio)

In JavaScript API:

await suitest.assert.element('logo').matchesJS("function(img) { return img.offsetWidth / img.offsetHeight  === 16 / 9 }");

You can specify an arbitrary JavaScript code but be careful about the code that produces side effects. For example, consider a silly piece of code like this:

var a = 1;

This code is creating a variable in the global scope. If the application happens to use such variable internally, this code may just have corrupted its runtime and thus the test results can not be considered reliable anymore.

Generally you should use this subject only if you are sure that there is no other way to achieve the desired result. When in doubt on how to structure your JavaScript consult with your development team.

Asynchronous JavaScript comparison

Sometimes you need to run your comparison asynchronously (for example, to perform a network request). There are several options to do that.

Callback function

If your matchesJS function expects second parameter, it must be used as a callback formatted according to Node.js error convention. First argument in callback is an error, second - a result of your assertion (true or false).

// Make sure element's inner text is same as text returned from some network API 
function (testSubject, callback) {
    fetch('https://some.api/some/data')
        .then(function(response) {return response.text()})
        .then(function(text) {callback(null, text === testSubject.innerText)})
        .catch(function(error) {callback(error)});
}

JavaScript Promise

If your matchesJS function returns a Promise A+ compatible object, Suitest will wait for it to resolve and will use that value as the comparison result.

// Make sure element's inner text is same as text returned from some network API 
function (testSubject) {
    return fetch('https://some.api/some/data')
        .then(function(response) {return response.text()})
        .then(function(text) {return text === testSubject.innerText});
}

JavaScript async/await syntax

Since async/await construct is pretty much a syntax sugar over Promise API, you can use async functions same way.

// Make sure element's inner text is same as text returned from some network API
async function (testSubject) {
    const response = await fetch('https://some.api/some/data');
    const text = await response.text();

    return text === testSubject.innerText;
}

A few things to keep in mind when using JavaScript comparison:

  1. Suitest does not include polyfills and does not transpile your code. If you want to use Promise on older devices, you might need to include a polyfill into your application. Async/await syntax would not work on older devices even with Promise polyfill.

  2. Make sure your callback is always called and promises are always resolved, otherwise test line will eventually fail with timeout error.

  3. Use callback errors and promise rejections only for actual JavaScript exceptions. If you want to fail the assertion line, rather call your callback with false as second argument or resolve Promise with false. Otherwise it might get tricky to distinguish assertion failures from JavaScript errors.