Chain modifiers

Chain modifier are added to manipulate and check for specific aspects of test subjects or change the behavior of test operations.

Subjects can be found in test subjects.


List of chain modifiers:

Modifier + aliases To be used with Explanation
accuracy image Defines how accurate should the image comparison be.
contain, contains any string Evaluates if subject contains an expected string.
endWith, endsWith any string Evaluates if subject ends with an expected string.
equal, equals any string Evaluates if subject is equal to expected value.
exist, exists cookie, element, video Evaluates if subject exists.
getAttributes element Returns a list of attributes with values.
getCssProperties element Returns a list of CSS properties with values.
hasExited application Evaluates if application has exited.
inRegion image Defines the area on screen to compare to the subject.
interval click, press, repeat, send text Sets an interval between chain executions.
isPaused video Evaluates if the state of video is paused
isPlaying video Evaluates if the state of video is playing
isStopped video Evaluates if the state of video is stopped
language ocr Defines language for ocr feature.
match, matches element, video Compares state of an element to defined values.
matchJS, matchesJS cookie, element, location, video Evaluates if subject matches JS expression.
matchRepo, matchesRepo element, video Compares state of element with element repository state.
not, doesNot, isNot contain, endWith, equal, exist, jsExpression, matchJs, starWith, wasMade and willBeMade. Negates the state.
repeat click, interval, press, send text Repeats the execution of a chain.
requestMatches network request Evaluates if network request matches data.
responseMatches network request Evaluates if network response matches data.
startWith, startsWith any string Evaluates if subject starts with an expected string.
timeout any assertion Sets timeout to wait until chain becomes resolved.
until click, tap Executes chain until condition is satisfied.
visible element, image, video Evaluates if an element is visible.
wasMade network request Evaluates if network request was made in entire request log.
willBeMade network request Evaluates if network request will be made (excludes previously matched requests).

accuracy

Defines how accurately should Suitest compare the images. Different levels are useful depending on the image capture device (lower for mobile phones, higher for HDMI capture).

Default value is low. For other options we recommend using corresponding suitest.ACCURACY constants.

// examples
await suitest.assert.image('myImageID').accuracy(suitest.ACCURACY.MEDIUM).visible();
await suitest.assert.image({url: 'https://my.server.com/myImage'}).accuracy(suitest.ACCURACY.HIGH).isNot().visible();

contain

Evaluates if subject (as a string) contains an expected string.

/**
 * @param {string} expectedValue
 * @throws {SuitestError} if subject is unavailable
 * @returns {ChainablePromise.<void|boolean>}
 */
async function contain(expectedValue) {}

await suitest
    .cookie('cookieName')
    .contains('someValue');

endWith

Evaluates if subject (as a string) ends with an expected string.

/**
 * @param {string} expectedValue
 * @throws {SuitestError} if subject is unavailable
 * @returns {ChainablePromise.<void|boolean>}
 */
async function endsWith(expectedValue) {}

await suitest
    .cookie('cookieName')
    .endsWith('someValue');

equal

Evaluates if a subject is equal to an expected value.

/**
 * @param {string} expectedValue
 * @throws {SuitestError} if subject is unavailable
 * @returns {ChainablePromise.<void|boolean>}
 */
async function equal(expectedValue) {}

await suitest
    .cookie('cookieName')
    .equals('Some Value');

exist

Evaluates if a subject exists. Can be used with not to change to "does not exist".

/**
 * @returns {ChainablePromise.<void|boolean>}
 */
async function exists() {}

// Check if element exists
await suitest
    .element('Element name')
    .exists();

// Check if cookie does not exist
await suitest
    .cookie('cookieName')
    .doesNot()
    .exist();

getAttributes

Returns a list of attributes with values.

/**
 * Returns specific list of element attributes / all attributes
 * @param {string[]} [attributes] - listing what attributes should be returned
 * @returns {Promise.<Object>} - returns attributes with their values
 */
async function getAttributes(attributes) {}

// Get all attributes of my logo element
const myElementAttributes = await suitest.element({attributes: 'data-testid="logo"'}).getAttributes();

console.log(myElementAttributes['class']); // printing the class values of given element

getCssProperties

Returns a list of CSS properties with values.

/**
 * Returns specific list of element css properties / all css properties
 * @param {string[]} [properties] - listing what CSS properties should be returned
 * @returns {Promise.<Object>} - CSS properties with their values
 */
async function getCssProperties(properties) {}

// Get size of a logo element
const myElementSize = await suitest.element({attributes: 'data-testid="logo"'}).getCssProperties(['width', 'height']);

console.log("element width: ", myElementSize['width']);
console.log("element height: ", myElementSize['height']);

hasExited

Evaluates if the application has exited.

/**
 * @throws {SuitestError} in case subject is different from application
 * @returns {Promise.<void|boolean>}
 */
async function hasExited() {}

// Wait until application has exited but at most 2s
await suitest
    .application()
    .hasExited();

interval

Sets interval (in ms) between chain executions.

/**
 * @param {number} ms
 * @returns {ChainablePromise.<void|boolean>}
 */
async function interval(ms) {}

// Press OK 10x every 10s
await suitest.press(suitest.VRC.OK)
    .repeat(10)
    .interval(10000);

isPaused

Evaluates the video status.

const isVideoPaused = await suitest.video().isPaused();

await suitest.assert.video().isPaused();

isPlaying

Evaluates the video status.

const isVideoPlaying = await suitest.video().isPlaying();

await suitest.assert.video().isPlaying();

isStopped

Evaluates the video status.

const isVideoStopped = await suitest.video().isStopped();

await suitest.assert.video().isStopped();

language

Defines in which language ocr is supposed to read a text displayed on a screen.

const readText = await suitest.ocr(ocrObjects).language(suitest.LANG.ENGLISH);

await suitest.assert.ocr(ocrObjects).language(suitest.LANG.ENGLISH);

We recommend using corresponding suitest.LANG constants for values.

match

Compares the state of the element with the defined properties set.

For the properties available refer to constant element properties.

For properties with enumerable values (VIDEO_STATE, VISIBILITY_STATE, CONTENT_MODE, ELEMENT_STATE, TEXT_ALIGNMENT, BORDER_STYLE) value must be provided as Suitest constant.

/**
 * @param {Symbol} name - properties to match against
 * @param {string|number|Symbol} [val] - properties to match against. Defaults to VALUE.REPO
 * @param {string} [type] - how to compare property, defaults to COMP.EQUAL
 * @param {string} [deviation] - how accurate type should be, only if value is of type number and type is COMP.APPROX
 * @returns {ChainablePromise.<void|boolean>}
 */
async function match(name, val, type, deviation) {}
async function match({name, val, type, deviation}) {}
async function match([{name, val, type, deviation}/*, ...*/]) {}

// Check if element's width and height match snapshot from element repo, top position as in repo +- 20px and custom background color
const element = suitest.element('repo-id');

await element.matches(suitest.PROP.WIDTH);
await element.matches(suitest.PROP.HEIGHT);
await element.matches(suitest.PROP.TOP, suitest.VALUE.REPO, suitest.COMP.APPROX, 20);
await element.matches(suitest.PROP.BG_COLOR, '#F00');

// Same with object syntax
await suitest.element('repo-id').matches({
    name: suitest.PROP.WIDTH,
});
await suitest.element('repo-id').matches({
    name: suitest.PROP.HEIGHT,
});
await suitest.element('repo-id').matches({
    name: suitest.PROP.TOP,
    val: suitest.VALUE.REPO,
    type: suitest.COMP.APPROX,
    deviation: 20,
});
await suitest.element('repo-id').matches({
    name: suitest.PROP.BG_COLOR,
    val: '#F00',
});
await suitest.element({css: '#repo-id'}).matches({
    [PROP.BG_COLOR]: 'red',
    [PROP.HREF]: 'http://somelink',
    borderWidth: 233,
});

// Preferred syntax as only one command and one server communication request is executed.
await suitest.element('repo-id').matches([
    PROP.WIDTH,
    PROP.HEIGHT,
    {
        name: PROP.TOP,
        val: VALUE.REPO, // could be omitted
        type: COMP.APPROX,
        deviation: 20,
    },
    {
        name: PROP.BG_COLOR,
        val: '#F00',
    },
    {
        [PROP.CLASS]: 'friendlyClass',
        [PROP.TEXT_CONTENT]: 'Lorem ipsum',
    }
]);

.match method can accept objects with name property, conflicts may occur in .match arguments due to the dictionary being able to contain name key as well.

matchJS

Evaluates if subject matches a JS expression.

/**
 * @param {string|Function} matcher
 * @throws {SuitestError} if subject is unavailable
 * @throws {TypeError} if matcher produced error
 * @returns {ChainablePromise.<void|boolean>}
 */
async function matchesJS(matcher) {}

// Pass function as parameter
await suitest
    .cookie('cookieName')
    .matchesJS(function(cookieValue) { return /foo|bar/i.test(cookieValue); });

// Pass string as parameter
await suitest
    .cookie('cookieName')
    .matchesJS('function (cookieValue) { return /foo|bar/i.test(cookieValue) }');

matchRepo

Compares the state of the element with the state in the Element repository with the current state within the app.

For the properties available refer to constant element properties.

/**
 * @param {Symbol} name - properties to match against
 * @param {string} [type] - how to compare property, defaults to COMP.EQUAL
 * @param {string} [deviation] - how accurate type should be, only if value is of type number and type is COMP.APPROX
 * @returns {ChainablePromise.<void|boolean>}
 */
async function matchRepo(name, type, deviation) {}
async function matchRepo({name, type, deviation}) {}
async function matchRepo([{name, type, deviation}/*, ...*/]) {}

// Alias for repo-only elements - same syntax as matches, except "value" argument is always omitted
await suitest
    .element('repo-id')
    .matchesRepo([
        {
            name: suitest.PROP.BG_COLOR,
            val: '#F00', // invalid, value is always taken from repo. Use matches for this
        },
        {
            name: suitest.PROP.LEFT,
            type: suitest.COMP.EQUAL,
        },
    ]);

not

Universal negation of other chain commands.

/**
 * @returns {ChainablePromise.<void|boolean>}
 */
async function not() {}

// Wait until cookie does not equal '1', but at most 3s
await suitest
    .cookie('cookieName')
    .doesNot()
    .equal('1')
    .timeout(3000);

repeat

Repeat sets how many times a chain is executed, used in conjunction with press, click, sendText and interval.

/**
 * @param {number} times
 * @returns {ChainablePromise.<void|boolean>}
 */
async function repeat(times) {}

// Press OK 10x every 10s
await suitest.press(suitest.VRC.OK)
    .repeat(10)
    .interval(10000);

requestMatches

requestMatches is used in conjunction with networkRequest.

/**
 * @param {string|Symbol} name - properties to match against (some of names can be found in NETWORK_PROP)
 * @param {string|number} value - properties to match against.
 * @param {string} [type] - how to compare property, defaults to COMP.EQUAL
 * @returns {ChainablePromise.<void|boolean>}
 */
async function requestMatches(name, value, type);
async function requestMatches({name, value, type});
async function requestMatches([{name, val, type}/*, ...*/]);
/**
 * @param {Object.<name, value>} keyValueHash
 * @param {string|Symbol} name - properties to match against (some of names can be found in NETWORK_PROP)
 * @param {string|number} value - properties to match against.
 * @returns {ChainablePromise.<void|boolean>}
 */
async function requestMatches(keyValueHash);
await networkRequest().requestMatches('propName', 'propVal');

await networkRequest().requestMatches('propName', 'propVal', COMP.NOT_CONTAIN);

await networkRequest().requestMatches(NETWORK_PROP.METHOD, NETWORK_METHOD.GET);

await networkRequest().requestMatches({
    name: NETWORK_PROP.BODY,
    val: 'body'
});

await networkRequest().requestMatches({
    name: NETWORK_PROP.BODY,
    val: 'body',
    type: COMP.START
});

await networkRequest().requestMatches({
    [NETWORK_PROP.BODY]: 'some body',
    [NETWORK_PROP.METHOD]: NETWORK_METHOD.GET,
    'Any-Header': 'header-value'
});

await networkRequest().requestMatches([
    {
        name: NETWORK_PROP.METHOD,
        val: NETWORK_METHOD.GET,
    },
    {
        [NETWORK_PROP.BODY]: '{}',
        'Any-Header': 'header-value'
    }
]);

inRegion

inRegion is used with image assertion subject to specify the area on a screen where Suitest should look for a match with a reference image. If this modifier is not used, Suitest searches on the whole screen.

// Compare reference image stored on my server with the top-left quarter of the screen
await suitest.assert.image({url: 'https://myserver.com/myimage.png'}).inRegion(
    [0, 0, 50, 50] // left, top, width, height values in % of the screen
);

responseMatches

responseMatches is used in conjunction with networkRequest.

/**
 * @param {Object.<name, value>} keyValueHash
 * @param {string|Symbol} name - properties to match against (some of names can be found in NETWORK_PROP)
 * @param {string|number} value - properties to match against.
 * @returns {ChainablePromise.<void|boolean>}
 */
async function responseMatches(keyValueHash);
/**
 * @param {string|Symbol} name - properties to match against (some of names can be found in NETWORK_PROP)
 * @param {string|number} [value] - properties to match against.
 * @param {string} [type] - how to compare property, defaults to COMP.EQUAL
 * @returns {ChainablePromise.<void|boolean>}
 */
async function responseMatches(name, value, type);
async function responseMatches({name, value, type});
async function responseMatches([{name, val, type}/**, ...*/]);
await networkRequest().responseMatches('propName', 'propVal');

await networkRequest().responseMatches(NETWORK_PROP.STATUS, 200);

await networkRequest().responseMatches({
    name: NETWORK_PROP.BODY,
    val: 'body',
});

await networkRequest().responseMatches({
    name: NETWORK_PROP.BODY,
    val: 'body',
    type: COMP.START
});

await networkRequest().responseMatches({
    [NETWORK_PROP.BODY]: 'some body',
    [NETWORK_PROP.STATUS]: 200,
    'Any-Header': 'header-value'
});

await networkRequest().responseMatches([
    {
        name: NETWORK_PROP.STATUS,
        val: 200
    },
    {
        [NETWORK_PROP.BODY]: '{}',
        'Any-Header': 'header-value'
    }
]);

startWith

Checks if subject (as a string) starts with an expected string.

Alias .startsWith().

/**
 * @param {string} expectedValue
 * @throws {SuitestError} if subject is unavailable
 * @returns {ChainablePromise.<void|boolean>}
 */
async function startWith(expectedValue) {}

// Cookie value starts with a certain string
await suitest
    .cookie('cookieName')
    .startsWith('value');

timeout

Set a timeout (in ms) or wait time for the chain to become resolved if it's not resolved an assertion error will be thrown.

Similar to assertion with timeout in Suitest Test editor. By default the timeout is set to 2000 ms, therefore if you do not include .timeout(ms), the chain will implicitly have .timeout(2000).

/**
 * @param {number} ms - time in milliseconds
 * @throws {SuitestError} - something unexpected happened while polling chain
 * @returns {ChainablePromise.<void|boolean>}
 */
async function timeout(ms) {}

// Element exists
await suitest
    .element('Some Element')
    .exists()
    .timeout(0);

// Wait until element exists but at most 10s
await suitest
    .element('Some Element')
    .exists()
    .timeout(10000);

until

Executes the chain with given interval, max count number of repeats until evaluation chain is satisfied. Accepts another chain as only parameter.

Please note that the condition is being evaluated before each run (including the first one). Therefore the application has to be already running before the first evaluation.

/**
 * @param {ChainablePromise} conditionChain - condition chain
 * @returns {ChainablePromise.<void|boolean>}
 */
async function until(conditionChain) {}

// Check if element 'menu' appeared on a page after clicking on 'openMenuButton' element, but at most 5 times with 1 second interval
await suitest.element('openMenuButton').click().until(
    suitest.element('menu').exists()
).interval(1000).repeat(5);

// Check if application has exited after pressing 'power' button several times
await suitest.assert.press(suitest.VRC.POWER).until(
    suitest.application().hasExited()
).repeat(5).interval(2000);

visible

Evaluates if element is visible.

async function visible() {}

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

wasMade

Evaluates if the network request has been made / will be soon made.

/**
 * To be used with networkRequest chain - include previously made Ajax requests
 */
async function wasMade() {}

await suitest.networkRequest()
    .contains('http://suite.st')
    .wasMade();

willBeMade

Evaluates if a network requests will be made (excluding previously matched requests).

/**
 * To be used with networkRequest chain - exclude previously made Ajax requests
 */
async function willBeMade() {}

await suitest.networkRequest()
    .contains('http://suite.st')
    .willBeMade();