Skip to content

Expression variables

Tales exposes a handful of well-known variables and helper functions inside HCL expressions. They tell the runtime where to read configuration, captured values, the current step’s request and response, and host details.

The top-level config { ... } block of the suite, exposed as a free-form map.

config {
base_url = env("BASE_URL", "http://localhost:1337")
webhook_secret = env("WEBHOOK_SECRET")
}
// elsewhere
url = "${config.base_url}/users"
sig = hmac_sha256_hex(config.webhook_secret, vars.body)

Visible in every scenario, every step, every keyword.

Captures from earlier steps, namespaced by step name. result.<step>.<key> resolves to whatever the upstream step’s capture { key = ... } evaluated to.

step "http" "create_user" {
// ...
capture { id = response.json.id, email = response.json.email }
}
step "http" "fetch_user" {
request {
url = "${config.base_url}/users/${result.create_user.id}"
}
}
  • Visible only in steps after the captured step’s source position.
  • Forward references and unknown step names are rejected at load time (exit code 2).
  • Captures don’t cross scenario boundaries, each scenario starts with an empty result.

For keywords, result.<call_name>.<output_name> exposes the keyword’s outputs, not its internal captures.

Inside the current step’s expect and capture blocks, request is bound to the request payload Tales is about to send.

step "http" "post_payload" {
request {
method = "POST"
url = "${config.base_url}/users"
body { json = { email = "[email protected]" } }
}
expect {
json = {
// Assert the server echoes back what we sent
email = request.body.json.email
}
}
}
FieldAvailable for
request.methodHTTP
request.urlHTTP
request.headersHTTP
request.body.jsonHTTP (json body)
request.body.formHTTP (form body)
request.body.rawHTTP (raw body)
request.actions[i]mobile (per-action record, including masked value)
request.sqlSQL
request.argsSQL
request.connectionSQL

The provider’s response, bound after the step’s request fires. Available inside expect and capture on the same step.

FieldNotes
response.status_codeHTTP status as integer.
response.headersMap of strings (HTTP).
response.jsonParsed JSON body when the body is JSON; SQL result shape; mobile expects don’t expose response.json.
response.bodyRaw body string (HTTP).
expect {
status = 200
json = {
id = is_string()
}
}
capture {
id = response.json.id
trace_id = response.headers["X-Trace-Id"]
}

Inside a keyword’s steps, input holds the bound input values from the call site.

keyword "authenticate" {
inputs {
email = string
password = string
}
step "http" "login" {
request {
body { json = { email = input.email, password = input.password } }
}
}
}

Equivalent access pattern: input.inputs.<name>, both forms work.

Step-local variables declared via the vars { ... } block. Scoped to the current step only; not visible to other steps, to when, to skip_if, or to skip_unless.

step "http" "signed" {
vars {
ts = now_unix()
sig = hmac_sha256_hex(config.secret, "${vars.ts}.payload")
}
request {
headers = { X-Signature = "t=${vars.ts},v1=${vars.sig}" }
}
}

See Step-local vars for evaluation order and scope rules.

A small object describing the runtime host. Useful in skip_if / skip_unless rules.

FieldEquivalentExample values
host.osGo’s runtime.GOOS"darwin", "linux", "windows"
host.archGo’s runtime.GOARCH"amd64", "arm64"
skip_unless {
condition = host.os == "darwin"
reason = "iOS tests require macOS"
}

For mobile steps, the runtime injects two extra functions into expression scope that close over the current accessibility hierarchy:

Reads the value attribute of an element by accessibility identifier.

capture {
current_email = value("login.email")
}

Reads the label (visible text) of an element.

capture {
greeting = text("home.welcome")
}

Both functions error if the element is missing. Wrap in can(...) if you want a soft probe.

Variable / functionScope
configwhole file
resultsteps after the captured step (same scenario)
requestcurrent step’s expect / capture
responsecurrent step’s expect / capture
inputkeyword body
varscurrent step’s request / expect / capture
hostanywhere
value("id")mobile step’s capture / expect
text("id")mobile step’s capture / expect