Skip to content

Expressions and variables

AutoTestX has a small, strict expression language. You use it in two ways.

Field kind Example field How it reads
Template Type → value, Open → url, Text → expected, HTTP → url/headers/body Literal text. Only the parts inside {{ }} are expressions. Order {{poNumber}} for {{vendor}}
Expression If → condition, While → condition, Expression → expression, Set variable → value, For each → items, Poll → until The whole field is one expression. status == 'Approved' AND total > 0

The editor shows which kind a field is under the field.

In an expression field you may also write variables with braces: {{status}} == 'Approved' means the same as status == 'Approved'.

{{name}} is looked up in this order. The first match wins:

Order Source Set by
1 Loop variables For each … as line → {{line.item}}; Repeat … as i; component parameters
2 Runtime variables Steps during the run: Extract, Set variable, HTTP saveAs, Custom code assignTo
3 Test variables Test settings → Test variables (JSON)
4 Environment variables The environment’s Variables (JSON)

Two reserved prefixes are looked up first and never collide with variables:

Prefix Meaning
{{secret.NAME}} A secret from the run’s environment. Masked everywhere.
{{data.column}} The current row in a data-driven run. Reserved only when the test has a data source.

Use dots for object fields and list positions: {{order.body.id}}, {{orders.body.0.id}}, {{line.item}}. Brackets work too: orders.body[0].

{{custmer}} (a typo), or a variable whose setting step did not run, fails the step with Unresolved reference “custmer”. Check the variable name and that an earlier step assigned it. It never becomes an empty string. Silently typing nothing is how tests pass while testing nothing.

Type Literals
text 'single' or "double" quotes, with \n, \t, \' escapes
number 42, 3.14
boolean true, false
null null
list [1, 2, 3], ['a', 'b']

A template that is exactly one placeholder ({{qty}}) keeps the value’s type, e.g. a number. Mixed text (Qty: {{qty}}) is always text.

There is no automatic type conversion:

  • "5" == 5 is an error (Cannot compare string with number. Convert explicitly, for example NUMBER(value).), not false.
  • + is arithmetic only. 1 + "1" is an error. Join text with CONCAT().
  • Only true and false are truthy. count AND … is an error; write count > 0 AND ….

Values read from the page (Extract) are text. Convert with NUMBER() before numeric comparisons.

From lowest to highest precedence:

Operator Meaning
OR, || Logical or (short-circuit)
AND, && Logical and (short-circuit)
NOT, ! Logical not
==, != Strict equality (lists compare item by item)
<, <=, >, >= Two numbers or two texts
+, - Numbers only
*, /, % Numbers only. Dividing by zero is an error.
-x Negation
( ) Grouping

AND, OR, NOT are case-insensitive.

Function names are case-insensitive. Functions cannot reach the page, network, files or secret store. For that, use a step.

Function Result Example
UPPER(t) / LOWER(t) / TRIM(t) Converted text UPPER('po') → 'PO'
LENGTH(t or list) Number of characters or items LENGTH('PO-1') → 4
SUBSTRING(t, start[, length]) Part of the text (0-based) SUBSTRING('PO-1234', 3) → '1234'
REPLACE(t, find, with) Every occurrence replaced REPLACE('a-b-c', '-', '/') → 'a/b/c'
CONCAT(a, b, …) Joined text CONCAT('Vendor ', NOW())
SPLIT(t, separator) List SPLIT('a,b', ',') → ['a','b']
JOIN(list, separator) Text JOIN(['a','b'], ', ') → 'a, b'
CONTAINS(t or list, x) true/false CONTAINS(status, 'Approv')
STARTS_WITH(t, prefix) / ENDS_WITH(t, suffix) true/false STARTS_WITH(poNumber, 'PO-')
PAD_START(t, length[, fill]) Padded text (default fill: space) PAD_START('42', 5, '0') → '00042'
REGEX_MATCH(t, pattern) true/false REGEX_MATCH(poNumber, '^PO-\\d+$')
REGEX_EXTRACT(t, pattern[, group]) Matched text or null REGEX_EXTRACT('Order PO-77 saved', 'PO-(\\d+)', 1) → '77'

Backslashes in expression text. Inside quotes in an expression, \ starts an escape. The only valid escapes are \n (newline), \t (tab), \\ (a backslash), \' and \". A regex therefore needs doubled backslashes: type '^PO-\\d+$'. Any other escape, such as a single \d, is a syntax error that gives its position and suggests \\d. You see it when you save the step. It is never quietly changed into a different pattern. Character classes avoid the issue: '^PO-[0-9]+$'.

This applies only to expressions. In a template field, such as Text → expected with match regex, type the pattern normally: ^PO-\d+$.

Function Result
NUMBER(x) Text → number (error if not a number)
ROUND(n[, decimals]) Rounded number
ABS(n) Absolute value
MIN(a, b, …) / MAX(a, b, …) Smallest / largest
Function Result
COUNT(list) Number of items
FIRST(list) / LAST(list) First / last item, or null if empty

Dates are ISO-8601 text in UTC, e.g. 2026-09-30T21:59:31.000Z.

Function Result
NOW() The current date and time
DATE_ADD(date, amount, unit) Date moved by amount ms, seconds, minutes, hours, days or weeks (negative to go back)
FORMAT_DATE(date, pattern) Text using yyyy, MM, dd, HH, mm, ss (UTC)
FORMAT_DATE(DATE_ADD(NOW(), 7, 'days'), 'dd/MM/yyyy') → '07/10/2026'
Goal Field Write
Unique name per run Set variable → value CONCAT('Vendor ', NOW())
Check a generated number Expression STARTS_WITH(poNumber, 'PO-') AND LENGTH(poNumber) > 3
Compare an extracted amount Expression NUMBER(total) == 49.5
Branch on API status If → condition response.status == 404
Loop over test data For each → items lines
Date in a field Type → value {{FORMAT_DATE(NOW(), 'yyyy-MM-dd')}}
Poll until done Poll → until response.body.state == 'done'