How to write a good test
msg.ZenTestAI turns natural-language descriptions into executable test steps, so the quality of a test is largely the quality of the prompts you write. Keep them clear, concise and built around one supported action per step.
When the runner executes your test, an AI classifier maps each step description to one of the supported actions. The better your prompt aligns with an action — and the clearer your description of the target element — the more reliably the step runs.
Write test cases so that a person who has never seen the application could follow them step by step. The closer your prompt is to a "click-by-click" instruction, the easier it is for the AI agent to understand and execute.
Guidelines
You will get the best results when you follow these guidelines:
- Think in terms of the DOM, not the screenshot. Actions run against the technical DOM tree (elements, labels, attributes), not pixels. The page should be reasonably accessible for automation — at least labels, roles, IDs or stable class names. Pure-image UIs (canvas, custom-rendered) are hard to drive.
- Align prompts with the supported actions. Each action is classified into exactly one of the supported actions. You may combine several in one step (e.g. "click 'Apply' and then expect the counter to update") — the classifier splits them into separate execution steps automatically. Keeping a step focused on a single action is still a good habit: it makes classification more predictable and the Explain output easier to read.
- Avoid ambiguous verbs. "Select value 'test'" can mean clicking, picking from a dropdown, or highlighting text. Be specific: "click the menu item …", "select from the dropdown …".
- Use quotes around important values.
Type "John Doe" into the text field labeled "Name"is much easier to parse than the unquoted version. - Remember earlier values instead of comparing in your head. Each step runs in isolation, so prompts like "I expect that something changes" or "the value should be lower than before" can't be evaluated — the agent has no memory of the previous state. Capture the earlier value with a Remember step and assert against that concrete
[[parameter]]. - Access previously created objects via a remembered parameter. When the test creates something (an order, a customer, …) and a later part needs to open exactly that object again, store the identifying value right after creation —
Remember the order number shown on the confirmation page in [[orderNo]]— and access it explicitly via that parameter:Navigate to "https://app.example.com/orders/[[orderNo]]"orClick the row containing "[[orderNo]]". If it is unclear where the value is visible after creation (URL, confirmation message, a table column), ask instead of guessing. Phrasings like "open the latest order" depend on sort order and timing — absolute last resort. See Parameters. - Don't strip
[[parameter]]placeholders or${…}template expressions. Both are recognized by the classifier and resolved at execution time. See Parameters, Macros and Dynamic Calculations.
Each step has an Explain action (in its overflow menu). It shows exactly how the AI agent understood the step — which action it picked, which element it expects to interact with, and which value it will use. Use it whenever a step misbehaves, before changing the prompt.
Actions
The runner supports the following actions; every step is classified into exactly one.
| Action | Description |
|---|---|
| Clicking | Single, double, right, back or forward click on an element. |
| Checkboxes / Radios / Switches | Set a checkbox, radio button or switch to a specific state, or toggle (flip) it. |
| Typing | Type text into a text field; clear, replace or append; pick a date in a date picker. |
| Expecting | Assert something about the page, URL, tabs, downloads, or a parameter value. |
| Selecting from a dropdown | Pick one or more values from a dropdown / combobox. |
| Hovering | Move the mouse over an element (e.g. to reveal a tooltip). |
| Focusing | Move the keyboard focus to an element. |
| Scrolling | Scroll to an element, to the page edges, by a number of pixels, or inside a container. |
| Drag & Drop | Drag a source element and drop it onto a target element. |
| Slider / Range | Move a slider to a specific value; range sliders are set as two separate steps. |
| File Upload | Upload one or more files (or a folder, packaged as .zip) into a file-input element. |
| Key combination | Press a key or key combination (e.g. Ctrl+S). |
| Wait | Wait for a fixed time or until a condition is met. |
| Switch browser tab | Switch to, create or close a browser tab. |
| Change URL / Navigation | Navigate to a URL, change path/hash, go back/forward, reload, or open a previously downloaded file. |
| Condition | Execute steps based on a single condition. |
| Condition Group | Execute one of several mutually-exclusive branches (if / else-if / else). |
| Loop / Repeat | Repeat steps a fixed number of times or until a condition holds. |
| Remember parameter value | Read a value from the page and store it in a parameter for later steps. |
| Go to transaction (SAP only) | Open an SAP Web GUI transaction by its code (e.g. SE11). |
Clicking
Use this action to click on any element on the page.
The AI agent will:
- Decide how to click. Supported variants: single-click (default), double-click, triple-click, right-click, middle-click, back-click and forward-click. Mention the variant in your prompt if you need anything other than a single click.
- Find the element from your description and click it.
By default the step fails if the element is not clickable (disabled, not visible, behind a modal). You can change this per page in Application Settings so the agent ignores unclickable elements instead of failing.
Clicking inside a text field places the caret at the end of the existing text. Selecting text inside a field is not supported.
A few browser elements cannot be driven through Click:
- Native browser prompts (file-open dialogs, JS prompts, …). The only supported case is uploading via File Upload.
- Browser-level right-click context menus.
For native HTML <select> dropdowns, prefer Selecting from a dropdown — the intended, reliable path. A Click that resolves directly to an <option> still commits the value via a native-select fallback, so it is not strictly impossible, just less reliable.
Examples:
Click on the "Save" buttonDouble-click on the "Save" buttonClick on the text field labeled "Name" inside the section "General"
Checkboxes / Radios / Switches
Checkboxes, radio buttons and switches are driven with a Click under the hood, but the verb you use decides how the agent clicks.
Set to a specific state — activate, deactivate, enable, disable, tick, untick, check, uncheck. The agent reads the current state first and only clicks if a change is needed, so the control always ends in the state you asked for, regardless of where it started. This is idempotent — running the step again is a safe no-op.
Activate the checkbox labeled "Male"Deactivate the switch labeled "Dark Mode"Enable the radio button "Age 10-15"
Flip the current state — toggle. The agent clicks once to invert the control. It has no fixed target and always changes the state, so the result depends on where the control started. Prefer the explicit verbs above when you need a guaranteed final state.
Toggle the switch "Notifications"
On a standard switch every verb above commits a correct result. The distinction matters when the starting state is unknown or the step might run more than once: activate / deactivate are state-aware and idempotent, while toggle simply flips.
Typing
Use this action to type text into an input or textarea. The step fails if the target element is not typeable.
A Type prompt must contain at least the value to type and the element to type into.
By default the existing text is cleared before typing, and the input is not confirmed — Enter is not pressed, focus is just removed afterwards. Override the defaults in your prompt:
Clear the field before typing(or keep it)… and press Enterto confirm the valueReplace "John" in the input field labeled "Name" with "Jane"— to replace a substringClear the text field labeled "Name"— by setting the value to empty
You can change these defaults per page in Application Settings.
A good default for confirm via Enter depends heavily on the application — many apps implicitly expect Enter after typing. Configure it once per page in Application Settings instead of adding "and press Enter" to every step.
Typing and then also pressing Enter via a separate Key combination step is unnecessary and discouraged. The Type action handles confirm-via-Enter natively when you mention it in the same step.
Examples:
Type "John Doe" into the text field labeled "Name"Type "John Doe" into the text field labeled "Name" and press EnterReplace the text "John" in the input field labeled "Name" with "Jane"Clear the text field labeled "Name"Type "John Doe" into the text field labeled "Name" without clearing the field
All element actions consider the full DOM tree, including elements outside the current viewport. Depending on the per-page setting, the agent automatically scrolls the target element into view.
Date pickers
For date and time fields, prefer Type over Click. The Type action understands common date formats and switches to date-picker mode automatically when that beats typing key-by-key.
Type "01.01.2010" into the date picker labeled "Date of Birth"Select "01.01.2010" in the date picker for the field "Date of Birth"← still classified as Type
Expecting
Use the Expect action for all assertions. The agent uses generative AI to evaluate your assertion against a screenshot (or the URL / tab / downloads / parameter context). Pure technical assertions (HTML attributes, CSS classes, raw DOM trees) are not supported — msg.ZenTestAI performs black-box testing.
You can assert about:
- Visual — anything visible in a screenshot (visibility, colors, layout, presence of text/icons, table row counts, …).
- URL / browser tabs — current URL, page title, number of open tabs, tab URLs.
- Downloads — number of downloaded files, file names.
- Static facts — anything derivable from parameter values without inspecting the page.
Focus the agent on a sub-section by mentioning the parent element (e.g. "in the table", "in the section General").
The classifier rewrites every Expect to start with "I expect that …". Phrases like "I cannot see X" become "I expect X to not be visible" — don't worry about inverting yourself.
Combine assertions about the same target into one step, but split those about different targets into separate steps:
- ✅ One step: "I expect that the button is red and enabled" (one target — the button).
- ✅ One step: "I expect that the menu contains the entries Save and Cancel" (one target — the menu).
- ❌ One step: "The button is red and the table has 10 rows" — split into two.
Examples:
Expect that the text "Hello World" is visibleExpect that the license plate of the car contains the text "MUC-123"Expect that the URL of the page is "https://www.msg-systems.com"Expect that the page contains a table with 5 rowsExpect that the section "General" contains a text field labeled "Name"
Scrolling and assertions interact subtly. Assertions are based on a screenshot, so you usually don't need to scroll first — the agent does the right thing:
- Parent element given (e.g. a table): a full screenshot of that element only is taken.
- Single element given: the agent scrolls to it and screenshots the page.
- Nothing given: the agent screenshots the whole page up to ~3000×3000 px (potentially beyond the viewport).
Selecting from a dropdown
Use this action to select one or more values from a dropdown / combobox.
The prompt must contain at least the value(s) to select and the dropdown to select from.
The classifier needs an explicit hint that this is a dropdown — words like dropdown, combobox, select field trigger it. A bare "Select 'green' for color" is ambiguous and more likely to be classified as a Click.
Prefer this action over Click for HTML native <select> elements — the intended, reliable path. A Click that lands directly on an <option> still commits the value via a native-select fallback, but it is less predictable than the dedicated action, so reach for the dropdown wording (and the explicit hint words above) first.
You can pick 1…n values; for multi-comboboxes the agent triggers each value as a toggle (it does not differentiate select vs. deselect — the result depends on the previous state). Combine multiple selections from the same combobox into one step.
For multi-comboboxes the agent clicks the combobox once at the end to close it. For regular dropdowns it assumes the dropdown closes itself — if yours does not, follow with a Click to close it.
Examples:
Select "Germany" from the dropdown labeled "Country"Select "Germany" and "France" from the dropdown labeled "Country"
Hovering
Move the mouse over an element (e.g. to reveal a tooltip) and hold it there.
Examples:
Hover over the "Save" buttonHover over the text field labeled "Name"
Focusing
Move the keyboard focus to an element. The element must be focusable.
Examples:
Focus the "Save" buttonFocus the text field labeled "Name"
Scrolling
Scrolling supports several modes:
- Scroll to an element —
Scroll to the element labeled "Footer". - Scroll to the top / bottom of the page —
Scroll to the bottom of the page. - Scroll by a fixed number of pixels —
Scroll down the page by 500 pixels. - Scroll relative to an element —
Scroll down by 500 pixels relative to the element labeled "Footer". - Scroll inside a container —
Scroll to the right side of the menu labeled "Navigation" by 500 pixels.
Pixel-based and top/bottom scrolls only work if the entire page is scrollable (browser scrollbar on the page itself). Scrolling inside a section requires naming the parent element.
Drag & Drop
Drag a source element and drop it onto a target element. Both must be named in the same step.
Drag & Drop does not support pixel-based offsets (by design — they become flaky when the layout changes) or dragging between different browser tabs. Always describe a target element, not a position.
Examples:
Drag the element labeled "Row 1" to the element labeled "Table 2"Drag the element labeled "Row 1" to the element labeled "Table 2" and drop it at the end of the table
Slider / Range selection
Move a slider (range input) to a specific value. The prompt must contain the slider reference (e.g. "the slider in the section X labeled Y") and the target value.
The step fails if the value cannot be reached (min/max limits, step constraints, …).
Range sliders with two thumbs are set as two separate steps, one per thumb.
Examples:
Set the slider in section "test", labeled "hello" to 50Set the lower thumb of the range slider in section "test", labeled "hello" to 50. Set the upper thumb to 100.(as two steps)
Only sliders built on the standard, accessible HTML pattern are supported. For non-standard implementations, fall back to plain Drag & Drop.
File Upload
Upload one or more files (or a folder, packaged as .zip) into a file-input element.
The prompt must contain the file(s) or folder to upload (by name or description) and the target file-input element.
The file(s) must first be attached to the step via Files (Upload / Download) in the step's advanced settings, and be available in the tenant under Additional Functions → File Upload. Maximum file size: 10 MB per file.
- Assign one file to the step and the agent uses it regardless of how you describe it.
- Assign multiple files and a dedicated agent matches your description (or list of names) to the right file(s).
- To upload a whole folder, package it as a
.zip— the runner extracts it on upload.
Examples:
Upload the file "test.txt" to the file upload element labeled "Upload"Upload the files "image1.png" and "image2.png" to the gallery upload
Mention "upload" only if you can see an actual file-input element on the page (usually identifiable by a Browse button). Some applications hide the file input behind a custom UI; then use Click on the visible trigger and assign the file to that step instead. You cannot interact with the OS-level browse dialog itself — it is handled by the browser, not the page.
Key combination
Press a key or key combination on the page. Keys are joined with +, and sent in the context of the previously focused element.
Examples:
Press "Ctrl" + "C"Press "Ctrl" + "Shift" + "A"Press "Enter"
Use Change URL — not Key combination — for browser-level navigation. Going back, forward, or reloading is a different action even if you would do it with a keyboard shortcut as a user. "Press Alt+Left" will not reliably navigate back; write "Go back" instead.
Likewise, you do not need a Key combination step to confirm a typed value with Enter — Typing handles that automatically when you mention it.
Wait
Wait for a fixed amount of time or until a condition is met. Provide the time (with optional unit — default milliseconds) or a clear description of what to wait for.
Wait for 5 secondsWait for 500 millisecondsWait until the loading spinner disappearsWait for the "Save" button to be enabled
The maximum wait is 180 seconds (3 minutes). Both fixed-time and until-a-condition waits that ask for more are automatically clamped to 180 seconds — the step still runs (a warning is logged), it is not failed.
Explicit waits are often a smell. msg.ZenTestAI already waits automatically for the page to be stable before each step (see Auto Waiting). If you find yourself adding manual waits, investigate the underlying timing issue first.
Switching browser tabs
Switch to, open or close a browser tab. Mention the tab by 1-based index or by URL / title. Detailed behavior is covered in Tab Handling.
Change URL / Navigation
Navigate the current browser tab. Five variants:
1. Navigate to a URL — absolute or partial. Hash-only / path-only changes work.
Navigate to "https://www.msg-systems.com"Change the path of the URL to "/about"Change the hash of the URL to "#contact"
2. Navigate back — equivalent to the browser's Back button.
Go backNavigate to the previous page
3. Navigate forward — equivalent to the browser's Forward button.
Go forward
4. Reload — refresh the current page.
Reload the pageRefresh
5. Open a downloaded file — open a file downloaded during the same execution, in a new tab.
Open the downloaded file "report.pdf"Open the last downloaded file
Without a name, the most-recently-downloaded file is opened. It opens in a new browser tab — you may need to switch back manually.
Opening a downloaded file is only possible if it was downloaded during the current test execution.
Condition
Execute steps based on a single boolean check. A Condition step needs:
- The condition to evaluate.
- The substep(s) to execute when it is true.
- Optionally, the substep(s) to execute when it is false.
The condition is evaluated against either the current screenshot (visual check) or static facts (URL, parameter values, number of downloads, …).
Conditions add execution branches and make tests harder to read. If you find yourself writing many of them, consider splitting into two simpler tests instead.
Examples:
If the text "Hello World" is visible, click on the "Save" button else click on the "Cancel" buttonIf the URL is "https://www.msg-systems.com", click on the "Save" buttonIf the number of downloads is 5, click on the "Save" buttonIf the text "Hello World" is visible, click on the "Save" button and type "John Doe" into the text field labeled "Name"
Condition Group
Use a Condition Group when you have multiple mutually-exclusive branches ("if A do X, else if B do Y, else do Z"). The classifier creates one Condition Group step with one Condition substep per branch, each containing the actions for that branch.
Example:
If the value displayed is higher than 5, press the backward button until it is 5; otherwise press the forward button until it is 5.
Resolves to one Condition Group → two Condition substeps → each with a Loop substep → each with a Click substep.
Looping / Repeating
Repeat a step (or sequence of steps) a fixed number of times or until a condition holds. The Loop step needs the exit condition or repeat count, plus the substep(s) to repeat.
Examples:
Click on the "Save" button 5 timesClick on the "Save" button until the text "Hello World" is visibleClick the next button until the displayed counter is 5
A loop runs at most 10 times. After that the agent assumes the action is not achievable and aborts the test.
Remembering parameter values
Read a value from the page (or the URL, an attribute, a count, …) and store it in a parameter so later steps can reference it via [[parameterName]].
Remember the number of rows in the table as parameter [[ROW_COUNT]]Remember the page title in parameter [[CURRENT_TITLE]]
See Parameters and test-data for how stored parameters interact with variants, macros and assertions.
Go to transaction (SAP only)
Available only when the page under test is identified as SAP Web GUI. Navigates to the given SAP transaction by code.
Go to transaction SE11Open SAP transaction SE16
For other applications the same wording is classified as a Click on a navigation element.
Parameters, macros and template expressions
Three syntaxes are recognized inside step descriptions and field values, and left alone by the classifier:
| Syntax | Meaning | More |
|---|---|---|
[[parameterName]] | Reference to a parameter, resolved per variant or by a previous Remember step. | Parameters |
${=macroKeyword(args)} | Macro call — runs a reusable function and inlines the returned value. | Macros |
${ free-text expression } | Dynamic calculation evaluated by an AI agent (e.g. ${current date in DD.MM.YYYY}). Use sparingly; prefer macros. | Dynamic Calculations |
All three can be combined inside a single step description — for example, a parameter as a macro argument: ${=global_addDays([[OFFSET]])}.