UI Test Actions Reference
Complete reference for all supported actions in YAML-based UI tests.
Navigation
NAVIGATE_TO
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
NAVIGATE_BACK
Browser back button. No selector or value needed.
- action: NAVIGATE_BACK
NAVIGATE_FORWARD
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
returnis legal; does not await Promises returned fromexecuteScript. - Playwright: top-level
returnlegal (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
CSS Selectors (recommended)
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_KEYSnow replaces the field (clears it first) on both engines, so an explicitCLEARbefore it is no longer required — it's harmless if present. UseCLEARon 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
Never hardcode usernames or passwords in test YAML. Use {{username}} and {{password}} — values are injected from the environment's default credential configuration.
[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.
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"
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"
Add TAKE_SCREENSHOT after login, after critical actions, and before logout. Screenshots are saved with results for debugging failures.
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.