Variables

Define test data upfront and extract runtime values to chain multi-step workflows.

Defining variables

Variables are key-value pairs defined at the definition level or test level:

{
  "name": "my-suite",
  "variables": {
    "baseEmail": "test@example.com"
  },
  "tests": [
    {
      "name": "Test 1",
      "variables": {
        "testEmail": "specific@example.com"
      },
      "steps": [ ... ]
    }
  ]
}

Interpolation: {{variableName}}

Reference variables with {{variableName}} anywhere in actions and assertions:

WhereExample
Action URLs"url": "api-gateway/api/users/{{userId}}"
Action headers"Authorization": "Bearer {{token}}"
Action body (string values)"email": "{{email}}"
Database queries"query": "SELECT * FROM users WHERE id = {{userId}}"
Assertion values"value": "{{email}}"
Match block fields"url": "user-service/{{path}}"
Console log messages"value": "User {{userId}} created"

Extraction

Extract values from responses at runtime using JSONPath expressions:

{
  "name": "Create user",
  "action": {
    "type": "httpRequest",
    "method": "POST",
    "url": "api-gateway/api/users",
    "body": { "email": "{{testEmail}}" }
  },
  "extract": {
    "userId": "$.body.id",
    "authToken": "$.headers.x-auth-token",
    "firstName": "$.body.user.profile.name",
    "firstItem": "$.body.items[0].id"
  }
}

Extracted values become variables available in all subsequent steps.

Extract paths

For HTTP responses:

For database query results:

Extract paths vs assertion paths. Extract paths use a flat document ($.body.field). Assertion paths use a nested format (response.body.field). Don't mix them — see Assertions for assertion path syntax.

Extraction in assertion blocks

You can also extract values from within assertion blocks — useful for capturing values from intercepted inter-service traffic:

{
  "match": {
    "origin": "api-gateway",
    "method": "POST",
    "url": "order-service/api/orders"
  },
  "extract": {
    "internalOrderId": "$.response.body.orderId"
  },
  "assertions": [
    { "path": "response.status", "operator": "eq", "value": 201 }
  ]
}

Precedence

Variables come from three sources, in order of increasing precedence:

  1. Definition-level variables — shared across all tests
  2. Test-level variables — per-test overrides
  3. extract on steps — runtime extraction (overwrites all hardcoded values)

Scoping rules

Build-time vs runtime variables

SyntaxResolvedByPurpose
${{VAR}}Build timeDefinition resolverConfig values from config.yaml env
{{VAR}}RuntimeTest agentVariables from variables / extract

You can combine both — use ${{}} inside a variables value to compose runtime variables from config:

{
  "variables": {
    "baseUrl": "${{API_HOST}}/v1"
  }
}