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
CLIExecutorandWebExecutor. - 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
| Field | Type | Required | Description |
|---|---|---|---|
version | string | no | DSL version (default 1.0) |
meta | object | no | Metadata (for example name, description) |
vars | object | no | Variables used by steps |
define | object | no | Sub-flow definitions (schema only) |
steps | array | yes | Ordered 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
| Field | Type | Description |
|---|---|---|
name | string | Optional display name |
action | string | Action type |
timeout | number or string | Optional timeout |
on_failure | fail | ignore | retry | fallback | Failure policy |
retry | object | Retry config when on_failure: retry |
fallback | array | Fallback steps when on_failure: fallback |
Retry config:
retry:
count: 3
interval: 2.0
backoff: fixed # fixed | exponential
Action Support Matrix
| Action | In Schema | In Cases Validator | In CLI Executor | In Web Executor |
|---|---|---|---|---|
exec | yes | yes | yes | no |
launch | yes | yes | yes | yes |
close | yes | yes | no | yes |
wait | yes | yes | yes | yes |
assert | yes | yes | yes | yes |
navigate | yes | yes | no | yes |
click | yes | yes | no | yes |
type | yes | yes | no | yes |
select | yes | yes | no | yes |
screenshot | yes | yes | no | yes |
if | yes | yes | yes | yes |
loop | yes | yes | yes | yes |
for_each | yes | yes | yes | yes |
call | yes | yes | no | no |
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_codestdout_containsstderr_containsstdout_matchesstderr_empty
Web-specific assertion types:
url_containsurl_equalstitle_containstitle_equalselement_visibleelement_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_containsexit_codevar_equalsvar_not_equalsvar_containsvar_emptyvar_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-selectorREST API orsubmit_ai_selectorMCP tool) - If timeout occurs,
fallback_selectoris used when provided
Failure Policies
fail: stop execution on failure (default)ignore: continue after failed stepretry: retry according to retry configfallback: 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.
callremains schema/validator-level and is not executed by current executors.