Skip to main content

UI Test Actions Reference

Complete reference for all supported actions in YAML-based UI tests.

Navigate to a URL.

- action: NAVIGATE_TO
value: "{{baseUrl}}/login"

WAIT_FOR_ELEMENT

Wait for an element to appear (seconds).

- action: WAIT_FOR_ELEMENT
selector: "#dashboard"
value: "10"

WAIT_FOR_CLICKABLE

Wait for an element to become enabled and accept clicks. Useful when buttons start disabled and enable after a form is filled.

- action: WAIT_FOR_CLICKABLE
selector: "button[type=submit]"
value: "10"

WAIT_FOR_TEXT

Wait until an element's text matches the expected string (uses contains match).

- action: WAIT_FOR_TEXT
selector: ".job-status"
expectedText: "COMPLETED"
value: "30"

WAIT_FOR_VISIBLE

Wait for an element to become visible.

- action: WAIT_FOR_VISIBLE
selector: ".modal"
value: "5"

Interaction

CLICK

Click an element.

- action: CLICK
selector: "button[type=submit]"

SEND_KEYS

Set an input field to value. Replaces any existing contents (the field is cleared first), and behaves identically on WebDriver and Playwright — so the same YAML gives the same result on both engines. You don't need a separate CLEAR before SEND_KEYS.

- action: SEND_KEYS
selector: "#username"
value: "{{username}}"

CLEAR

Clear the contents of an input field.

- action: CLEAR
selector: "#search-box"

SELECT_BY_TEXT

Select an option from a dropdown by visible text.

- action: SELECT_BY_TEXT
selector: "#country"
value: "United States"

SELECT_BY_VALUE

Select an option from a dropdown by value attribute.

- action: SELECT_BY_VALUE
selector: "#country"
value: "US"

HOVER

Hover over an element.

- action: HOVER
selector: ".dropdown-menu"

DOUBLE_CLICK

Double-click an element.

- action: DOUBLE_CLICK
selector: ".file-row"

RIGHT_CLICK

Right-click an element (opens the browser's native context menu).

- action: RIGHT_CLICK
selector: ".tree-node"

SUBMIT

Submit a form. Pass the selector of the <form> (or any element inside it).

- action: SUBMIT
selector: "form#checkout"

SELECT_BY_INDEX

Pick a <select> option by zero-based index.

- action: SELECT_BY_INDEX
selector: "select[name=country]"
value: "2"

FILL_FORM

Fill several fields of a form in one step. Point selector at the form (or any container) and give a {fieldName: value} map — each field is matched by its name (or id) within that form. The map can be a JSON string under value or a YAML map under formData.

# value as a JSON object (field names → values)
- action: FILL_FORM
selector: "#login"
value: '{"username":"{{username}}","password":"{{password}}"}'
# or the same map as YAML under formData
- action: FILL_FORM
selector: "#login"
formData:
username: "{{username}}"
password: "{{password}}"

For fields that need explicit per-field locators, use the legacy fields list:

- action: FILL_FORM
fields:
- {selector: "#email", value: "{{username}}"}
- {selector: "#password", value: "{{password}}"}

FILL_FORM fails the step if it can't fill anything (no map and no fields) — it never silently passes. Behaves identically on WebDriver and Playwright.

SCROLL_TO_ELEMENT

Scroll an element into view.

- action: SCROLL_TO_ELEMENT
selector: "#footer"

SCROLL_TO

Alias of SCROLL_TO_ELEMENT — scrolls the element matched by selector into view. (The runtime is element-based; there is no raw x/y-coordinate scroll.)

- action: SCROLL_TO
selector: "#footer"

Validation

All text validations use contains matching (not exact). The assertion passes if the actual text contains the expected text.

VALIDATE_TEXT

Verify an element contains specific text.

- action: VALIDATE_TEXT
selector: ".welcome-message"
expectedText: "Welcome, Admin"

VALIDATE_TITLE

Verify the page title contains text.

- action: VALIDATE_TITLE
expectedText: "Dashboard"

VALIDATE_URL

Verify the current URL contains a string.

- action: VALIDATE_URL
expectedText: "/dashboard"

VALIDATE_VISIBLE

Verify an element is visible on the page.

- action: VALIDATE_VISIBLE
selector: "#dashboard-widget"

VALIDATE_ELEMENT_EXISTS

Verify an element exists in the DOM (may not be visible).

- action: VALIDATE_ELEMENT_EXISTS
selector: "#hidden-input"

VALIDATE_ATTRIBUTE

Verify an element's attribute has a specific value. Uses exact matching.

- action: VALIDATE_ATTRIBUTE
selector: "#status"
attribute: "class"
expectedText: "active"

VALIDATE_ELEMENT_VISIBLE

Alias of VALIDATE_VISIBLE. Both action names dispatch the same code; prefer VALIDATE_VISIBLE for brevity.

Read element state

These actions read from the page rather than acting on it. The captured value lands in the step's output field and is available for assertions in later steps.

GET_TEXT

Read the innerText of an element.

- action: GET_TEXT
selector: ".job-status"

GET_ATTRIBUTE

Read a specific attribute. attribute is required.

- action: GET_ATTRIBUTE
selector: "input#email"
attribute: "value"

GET_VALUE

Read the value property of a form control (input / select / textarea).

- action: GET_VALUE
selector: "input[name=username]"

Utility

TAKE_SCREENSHOT

Capture a screenshot of the current page.

- action: TAKE_SCREENSHOT
filename: "after-login" # optional

MAXIMIZE_WINDOW

Maximize the browser window.

- action: MAXIMIZE_WINDOW

Browser back button. No selector or value needed.

- action: NAVIGATE_BACK

Browser forward button.

- action: NAVIGATE_FORWARD

REFRESH

Reload the current page. Useful after a server-side state change you want the UI to re-read.

- action: REFRESH

SWITCH_FRAME

Switch the test context into an iframe matched by selector. Element lookups in the following steps run inside that frame until you switch back.

- action: SWITCH_FRAME
selector: "#mce_0_ifr"

To return to the main document, pass an empty selector (or selector: "parent" / "default" / "main").

SWITCH_TAB

Switch focus to another browser tab (popups, target=_blank links). index is the zero-based tab index; subsequent steps run against that tab.

- action: CLICK
selector: ".open-new-tab" # opens a second tab
- action: SWITCH_TAB
index: "1" # focus it (the runner waits for the tab to open)

The runner waits for a tab opened by a prior click to register before switching, so you don't need an explicit wait step in between.

EXECUTE_JS

Execute JavaScript in the browser. Accepts either value: or script:.

Single-line:

- action: EXECUTE_JS
value: "document.querySelector('#cookie-banner').remove()"

Multi-line (use YAML's | literal block scalar — newlines and indentation are preserved verbatim, no escaping needed):

- action: EXECUTE_JS
value: |
const token = localStorage.getItem('token');
return fetch('/api/findings/60/status', {
method: 'PUT',
headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token},
body: JSON.stringify({status: 'TRIAGED'})
}).then(function(r) {
if (!r.ok) throw new Error('HTTP ' + r.status);
document.title = 'patent-2-ok';
return 'ok';
});

Engine differences (see yaml-format.md):

  • Selenium: top-level return is legal; does not await Promises returned from executeScript.
  • Playwright: top-level return legal (script is IIFE-wrapped); awaits the returned Promise.

To assert on async results from a later step, write a marker to document.title from inside the .then() and use VALIDATE_TITLE afterwards. For tests that need async behaviour (e.g. chained fetch calls), pin the test's driver to PLAYWRIGHT.

Selectors

selector: "#login-button" # by ID
selector: ".btn-primary" # by class
selector: "button[type=submit]" # by attribute
selector: "div.card > h2" # child combinator
selector: "[data-testid=login]" # by data attribute (best practice)

XPath

xpath: "//button[contains(text(),'Login')]"

Variables

Both {{variable}} and ${variable} syntax are supported. Variable lookup is case-insensitive.

Variables come from:

  • Environment credentials{{username}}, {{password}} (from default credential)
  • Target URL{{baseUrl}} (from environment target configuration)
  • Environment variables{{env.MY_VAR}}
  • Credential prefix{{credential.username}} (explicit)
steps:
- action: NAVIGATE_TO
value: "{{baseUrl}}"
- action: CLEAR
selector: "#username"
- action: SEND_KEYS
selector: "#username"
value: "{{username}}"
- action: CLEAR
selector: "#password"
- action: SEND_KEYS
selector: "#password"
value: "{{password}}"

SEND_KEYS now replaces the field (clears it first) on both engines, so an explicit CLEAR before it is no longer required — it's harmless if present. Use CLEAR on its own when you want to empty a field without typing.

Complete Example

steps:
- action: NAVIGATE_TO
value: "{{baseUrl}}"
- action: WAIT_FOR_ELEMENT
selector: "[data-testid=login-form]"
value: "5"
- action: CLEAR
selector: "[data-testid=login-username]"
- action: SEND_KEYS
selector: "[data-testid=login-username]"
value: "{{username}}"
- action: CLEAR
selector: "[data-testid=login-password]"
- action: SEND_KEYS
selector: "[data-testid=login-password]"
value: "{{password}}"
- action: CLICK
selector: "[data-testid=login-submit]"
- action: WAIT_FOR_ELEMENT
selector: "[data-testid=dashboard]"
value: "5"
- action: TAKE_SCREENSHOT
- action: VALIDATE_TEXT
selector: "body"
expectedText: "Welcome"
- action: VALIDATE_URL
expectedText: "/dashboard"
- action: CLICK
selector: "[data-testid=logout-btn]"
- action: WAIT_FOR_ELEMENT
selector: "[data-testid=login-form]"
value: "3"
- action: TAKE_SCREENSHOT

Best Practices

Use variables for credentials

Never hardcode usernames or passwords in test YAML. Use {{username}} and {{password}} — values are injected from the environment's default credential configuration.

Prefer data-testid selectors

[data-testid=login-btn] is stable and doesn't break when CSS classes or text change. Add data-testid attributes to your app's interactive elements.

Add waits before interactions

Elements may not be visible immediately after navigation or clicks. Use WAIT_FOR_ELEMENT before SEND_KEYS, CLICK, or VALIDATE_TEXT.

- action: WAIT_FOR_ELEMENT
selector: "[data-testid=dashboard]"
value: "5"
- action: VALIDATE_TEXT
selector: ".welcome"
expectedText: "Welcome"
Use baseUrl variable

Always use {{baseUrl}} for navigation — never hardcode URLs. This lets the same test run against dev, QA, staging, and production.

- action: NAVIGATE_TO
value: "{{baseUrl}}/login"
Take screenshots at key checkpoints

Add TAKE_SCREENSHOT after login, after critical actions, and before logout. Screenshots are saved with results for debugging failures.

Keep tests independent

Each test should set up its own state (navigate, login) and not depend on another test's output. This enables parallel execution and prevents cascading failures.