Skip to content

Test YAML schema

When you describe a test in plain English, Marriska compiles it into YAML that the executor consumes. You usually never see this format — but if you’re using the export feature, debugging a parser hiccup, or hand-editing a step, here’s the contract.

A test YAML is a list of steps. Each step is a single key/value mapping where the key is an action name:

- navigate: "https://example.com"
- click: "Sign in button"
- type:
target: "email field"
text: "user@example.com"
- verifyVisible: "Welcome back"

That’s it. There’s no top-level name, id, or metadata block — that information lives on the test record in the database, not in the YAML.

The parser accepts (and discards) anything before a --- separator on its own line. This lets exporters prepend a comment header without breaking the executor:

# Test: Sign-in flow
# Generated 2026-04-26
---
- navigate: "https://example.com"
- click: "Sign in button"

Only the section after the last --- is parsed as steps.

A step is one key. The value is either:

  • A string — used as the step’s primary target.
  • A boolean true — for actions with no input (e.g. back: true, refresh: true).
  • An object — when the action needs more than just a target (type needs text, verifyText needs expected, etc.).
# String form
- click: "Sign in button"
# Boolean form
- refresh: true
# Object form
- type:
target: "email field"
text: "user@example.com"

Both forms are accepted for most actions — pick whichever is more readable. See Step actions reference for the shape each action accepts.

These fields appear across many actions. The action page lists which fields are valid per action.

FieldTypeDescription
targetstringPlain-English description of the element (“Sign in button”, “email field”). The locator engine resolves it at run time.
textstringText to type (used by type / inputText).
valuestringValue to select (used by selectOption).
expectedstringExpected value for assertions (verifyText, verifyValue, verifyContainsText, verifyAttribute).
attributestringHTML attribute name (used by verifyAttribute).
countnumberExpected element count (used by verifyCount).
directionstringdown / up / left / right for scroll and swipe.
secondsnumberDuration for wait.
timeoutnumberPer-step timeout in milliseconds (used by waitForElement).
elementTypestringHint to the locator about what kind of element to find. See below.
optionalbooleanIf true, a missing element marks the step skipped instead of failed.

The elementType field narrows what kind of element the locator engine looks for. Accepted values:

elementTypeMatches
button<button>, role=button
link<a>, role=link
input<input>, <textarea>
checkbox<input type=checkbox>, role=checkbox
radio<input type=radio>, role=radio
select<select>, role=combobox
textText content (headings, paragraphs, labels)

The parser also normalizes a number of common aliases — btn, submit, and anchor map to button/link; textbox, field, textarea map to input; dropdown, combobox, picker map to select; toggle, switch map to checkbox; label, heading, paragraph map to text.

Mark any step optional with optional: true. If the target element isn’t found at run time, the step is reported as skipped (with the message “Element not found — step skipped (optional)”) and the run keeps going.

- click:
target: "Cookie banner accept"
optional: true

This works for both regular actions and screenshot steps.

Variables defined on a test (in the UI or via API) get substituted into step target, value, and description fields using {{name}} placeholders:

- type:
target: "email field"
text: "{{email}}"
- type:
target: "password field"
text: "{{password}}"

For each row of variable data on the test, the runner expands the YAML once with that row’s values and runs the resulting test. A test with 5 variable rows runs 5 times — once per row.

If a placeholder doesn’t match any defined variable, the literal {{name}} is left in place. The same regex (\{\{(\w+)\}\}) drives both the CLI runner (packages/cli/packages/core/src/variable-resolver.ts) and the backend (backend/app/domain/services/variable_resolver.py).

The parser uses yaml.safe_load, so all standard YAML rules apply:

  • Wrap any string with special characters in double quotes.
  • For text containing both single and double quotes, prefer YAML block scalars (| or >).
  • Hash signs (#) inside a quoted string are fine; outside, they start a comment.
- type:
target: "comment box"
text: "She said: \"hi!\""
- type:
target: "address"
text: |
123 Main St,
Apt 4B

If the YAML doesn’t parse with yaml.safe_load, the executor falls back to a line-by-line parser that handles the simple - key: value shape. This means most malformed-but-readable YAML still runs. Don’t rely on it — fix the YAML.