Skip to content

Test file format (DSL)

Every AutoTestX test is stored as a JSON document in one fixed format, the DSL. The editor, the server, the CLI and the runner all read and write this format, and nothing else defines what a test is. You can see any test’s DSL in the editor’s DSL tab.

Current version: 1.8.0.

{
"dslVersion": "1.8.0",
"id": "tc_create_po",
"name": "Create Purchase Order",
"description": "Creates a PO with two lines and checks it is approved.",
"engine": "web",
"module": "Purchasing",
"status": "draft",
"tags": ["smoke", "purchase-orders"],
"defaults": { "timeoutMs": 8000, "retry": 1, "onError": "abort" },
"variables": {
"lines": [ { "item": "1234", "qty": "2" }, { "item": "5678", "qty": "1" } ]
},
"steps": [
{ "id": "open", "type": "browser.open", "label": "Open the application",
"params": { "url": "{{baseUrl}}" } },
{ "id": "username", "type": "input", "label": "Enter username",
"target": { "strategies": [ { "kind": "label", "value": "Username" } ] },
"params": { "value": "{{secret.APP_USER}}", "sensitive": true } },
{ "id": "add-lines", "type": "control.forEach", "label": "Add each order line",
"params": { "items": "lines", "as": "line" },
"children": [
{ "id": "line-item", "type": "input",
"target": { "strategies": [ { "kind": "label", "value": "Item" } ] },
"params": { "value": "{{line.item}}" } }
] },
{ "id": "verify-status", "type": "assert.text", "soft": true,
"target": { "strategies": [ { "kind": "testId", "value": "po-status" } ] },
"params": { "expected": "Approved" } }
],
"cleanup": []
}

The full worked example is examples/create-purchase-order.json.

Field Required Type Meaning
dslVersion yes "MAJOR.MINOR.PATCH" Format version the document was written for
id yes text Unique test id. Replaced with a new one on import.
name yes text Test name
description text Free text
engine yes web | android | ios Execution engine
module text Suite name. Absent = Unsorted.
status draft | ready | deprecated Lifecycle. Absent = draft.
tags list of text Free tags, searchable in the test list
defaults yes object timeoutMs (default 30000), retry (0), onError (abort)
variables object Test variables, available as {{name}}
steps yes list of steps The test body
cleanup list of steps Always runs after the body, pass or fail
data object Data-driven binding (since 1.7.0). See below.
Field Required Meaning
id yes Unique within the test
type yes A step type from the step reference
label Name shown in the editor and reports
target per type { scope?, strategies: [...], fingerprint? }. See Element targets.
params per type The step’s parameters
timeoutMs, retry, onError Override the test defaults
soft Soft assertion
disabled Skip this step
children blocks Body of If / For each / Repeat / While / Lookup
orElse If only The otherwise branch
{ "kind": "testId", "value": "save-po" }
{ "kind": "role", "role": "button", "name": "Save", "exact": true }
{ "kind": "label", "value": "Username" }
{ "kind": "placeholder", "value": "Search…" }
{ "kind": "altText", "value": "Logo" }
{ "kind": "title", "value": "Close" }
{ "kind": "text", "value": "Approved", "exact": true, "nth": 0 }
{ "kind": "css", "value": "#btn_save_123" }
{ "kind": "xpath", "value": "//*[@id='po-form']//button" }

Any strategy may carry "confidence": 0.0–1.0 (informational).

"scope": {
"frame": ["iframe#content"],
"within": { "role": "row", "key": "{{poNumber}}" }
}

within also accepts selector (CSS) or testId.

"data": {
"source": { "kind": "dataSet", "id": "tds_…" },
"independent": true,
"maxConcurrency": 3,
"sensitiveColumns": ["password"]
}
source.kind Fields
inline columns: [..], rows: [ { column: value } ]
dataSet id of a project data set
http url, method?, headers?, body?, rowsPath? (expression over response)
pool poolId, count, onFinish?: "consume" | "release"

dslVersion follows semantic versioning:

  • Minor versions add optional features (lookup in 1.4, components in 1.5, HTTP steps in 1.6, data binding and custom code in 1.7, upload in 1.8). An older document is still valid under a newer version.
  • A breaking change always comes with a migration. The only one so far, 0.9.0 → 1.0.0, replaced the single selector string with an ordered strategy list.
  • Migration is forward-only and automatic on import and in the CLI. atx migrate shows or writes the result.
  • A document from a newer version than the server is rejected rather than guessed at.

A step type the test’s engine does not implement fails validation when you save, not at run time. A deprecated step type produces a warning.

atx validate file.json, the editor and the server all apply the same checks:

  • JSON schema (fields, types, unknown fields rejected),
  • every step type exists and is supported by the test’s engine,
  • every step’s parameters match its schema,
  • every template and expression parses,
  • step-specific rules (e.g. a lookup with completion: "ok" needs an OK control).

Problems are reported with a path, e.g. step username.params.value, and a severity: error (blocks saving and running) or warning.