OpenTester DSL Specification

March 8, 2026 ยท View on GitHub

OpenTester DSL is YAML-based and validated by DSLScript in backend/opentester/models/dsl.py.

Overview

  • Current execution runtime supports both CLIExecutor and WebExecutor.
  • DSL schema supports both basic actions and control-flow actions.
  • Some actions are accepted by schema but not fully implemented by the current executor (see support matrix).

Minimal Structure

version: "1.0"
meta:
  name: "Smoke Test"

vars:
  base_url: "http://localhost:3000"
  token: "${env.API_TOKEN}"

steps:
  - name: "Ping"
    action: exec
    command: "curl -s ${vars.base_url}/health"

Top-Level Fields

FieldTypeRequiredDescription
versionstringnoDSL version (default 1.0)
metaobjectnoMetadata (for example name, description)
varsobjectnoVariables used by steps
defineobjectnoSub-flow definitions (schema only)
stepsarrayyesOrdered test steps

Variables

Supported variable interpolation syntax in executor:

  • ${name}
  • ${vars.name}
  • ${env.VAR_NAME}

Notes:

  • Missing variables are left as unresolved placeholders.
  • Default-value syntax like ${vars.timeout:30} is not implemented in current runtime.
  • Extended variables are supported: ${{now}}, ${{random}}, ${{file:path}}.

Step Common Fields

FieldTypeDescription
namestringOptional display name
actionstringAction type
timeoutnumber or stringOptional timeout
on_failurefail | ignore | retry | fallbackFailure policy
retryobjectRetry config when on_failure: retry
fallbackarrayFallback steps when on_failure: fallback

Retry config:

retry:
  count: 3
  interval: 2.0
  backoff: fixed   # fixed | exponential

Action Support Matrix

ActionIn SchemaIn Cases ValidatorIn CLI ExecutorIn Web Executor
execyesyesyesno
launchyesyesyesyes
closeyesyesnoyes
waityesyesyesyes
assertyesyesyesyes
navigateyesyesnoyes
clickyesyesnoyes
typeyesyesnoyes
selectyesyesnoyes
screenshotyesyesnoyes
ifyesyesyesyes
loopyesyesyesyes
for_eachyesyesyesyes
callyesyesnono

Action Details

exec

- action: exec
  command: "pytest -q"
  working_dir: "./backend"
  env:
    PYTHONUNBUFFERED: "1"
  capture: ["stdout", "stderr", "exit_code"]
  timeout: 60

launch

CLI target example:

- action: launch
  command: "python app.py"
  timeout: 5

Web target example:

- action: launch
  browser: "chromium"   # chromium | firefox | webkit
  headless: true
  viewport:
    width: 1280
    height: 720

wait

Direct duration form:

- action: wait
  duration: 2

Condition form:

- action: wait
  condition:
    type: duration
    value: 2

Output wait:

- action: wait
  condition:
    type: output_contains
    pattern: "Ready"
    timeout: 10

Note: output_contains wait is CLI-oriented. Web runtime wait conditions are duration, element_visible, and element_hidden.

assert

- action: assert
  assertion:
    type: stdout_contains
    expected: "ok"

Supported assertion types:

  • exit_code
  • stdout_contains
  • stderr_contains
  • stdout_matches
  • stderr_empty

Web-specific assertion types:

  • url_contains
  • url_equals
  • title_contains
  • title_equals
  • element_visible
  • element_contains_text

if

- action: if
  condition:
    type: var_equals
    variable: env_name
    expected: production
  then:
    - action: exec
      command: "echo prod"
  else:
    - action: exec
      command: "echo non-prod"

Supported condition types:

  • output_contains
  • exit_code
  • var_equals
  • var_not_equals
  • var_contains
  • var_empty
  • var_not_empty

loop

- action: loop
  max_iterations: 5
  loop_interval: 1
  condition:
    type: output_contains
    pattern: "retry"
  body:
    - action: exec
      command: "check-status"

for_each

- action: for_each
  items: ["a", "b", "c"]
  var: item
  body:
    - action: exec
      command: "echo ${vars.item}"

Web actions

Navigate:

- action: navigate
  url: "https://example.com/login"

Click with selector:

- action: click
  selector: "#submit-button"

Type with selector:

- action: type
  selector: "input[name='email']"
  text: "user@example.com"

Select option:

- action: select
  selector: "select[name='region']"
  value: "cn"

Screenshot:

- action: screenshot
  name: "after-login"
  full_page: false

AI-assisted locator (ai_locator)

Web steps like click and type support an ai_locator block.

- action: click
  ai_locator:
    description: "The primary submit button in the form footer"
    context: "Login form bottom-right"
    fallback_selector: "button[type='submit']"
    timeout: 300
    include_screenshot: true
    force_refresh: false

Behavior:

  • Execution may pause in paused_waiting_for_ai
  • System waits for selector submission (submit-selector REST API or submit_ai_selector MCP tool)
  • If timeout occurs, fallback_selector is used when provided

Failure Policies

  • fail: stop execution on failure (default)
  • ignore: continue after failed step
  • retry: retry according to retry config
  • fallback: execute fallback steps

Validation Endpoints

Two REST validators exist:

  • POST /api/cases/validate-dsl (UI-focused with line/column diagnostics)
  • POST /api/parser/validate (schema-focused parser validation)

MCP validation tool:

  • validate_dsl

Runtime Notes

  • Execution manager supports both CLI and Web executors based on TargetType.
  • GUI/TUI execution targets are experimental and disabled by default.
  • call remains schema/validator-level and is not executed by current executors.