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:
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:
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:
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 equalcontains
- contains expected stringdoes not contain
- does not contain the expected stringends with
- ends with the expected stringdoes not end with
- does not end with the expected stringstarts with
- starts with the expected stringdoes 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.
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 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). Theunknown
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.
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:
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:
-
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.
-
Make sure your callback is always called and promises are always resolved, otherwise test line will eventually fail with timeout error.
-
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 withfalse
. Otherwise it might get tricky to distinguish assertion failures from JavaScript errors.