Skip to main content

Loops and Conditions

Loops and conditions let you build tests that adapt to data and context without writing custom code. msg.ZenTestAI offers several places where these constructs can live — each with different trade-offs around scope and determinism.

The general guidance:

  • For conditions, prefer the structured options (activity-, snippet- and step-level settings). Reserve inline "if …" clauses in the step prompt for genuinely simple cases.
  • For loops, always use the structured options on activities or snippets. Inline loop hints in step prompts work occasionally but are unreliable for anything beyond a handful of iterations.

Conditions

A condition is an expression that decides whether a piece of the test runs at all. msg.ZenTestAI evaluates conditions in four places, in increasing order of determinism:

1. Activity-level condition

Open an activity's settings sidebar and use the Condition field. The condition is written in plain language and may reference parameters with [[parameterName]]. Examples:

[[environment]] != "production"
the cookie banner is visible
[[country]] == "DE" and [[loggedIn]]

At execution time, the runner evaluates the condition. If it is false, every step inside the activity is skipped.

2. Snippet-level condition

A condition can be attached to a snippet-reference step in the calling test (not to the snippet itself). It works exactly like an activity condition, but its scope is the snippet's expanded steps. Configure it in the snippet-reference step's sidebar, next to the parameter bindings.

3. Step-level Disable on parameter

On any step's settings sidebar there is a Disable step toggle. With the simple toggle on, the step is always skipped. The interesting variant is Disable on parameter, which compares a parameter against a value using a comparison operator and skips the step only when the comparison is true.

You configure three things:

  • Parameter — the parameter to evaluate.
  • Operator — one of ==, !=, >, <, >=, <=.
  • Value — the value to compare against.

Unlike the activity and snippet-level conditions above, Disable on parameter is fully deterministic — it does not involve the AI agent at runtime. Use it whenever a step needs to be gated by a simple boolean or value comparison.

4. Inline "if …" in the step prompt

You can also write a condition straight into a step's natural-language prompt — for example, "Enter the promo code only if a code was provided". This is the least deterministic option: the AI agent has to detect and honour the if clause every time. It works for simple cases but should be avoided when correctness matters; use one of the three options above instead.

Order of evaluation and visibility

When a step is reached at execution time, the gating rules are evaluated in this order:

  1. The step's own Disable / Disable on parameter setting.
  2. The containing activity's Disabled flag.
  3. The containing activity's Condition.
  4. The containing snippet-reference step's Condition, if the step lives inside an inlined snippet.
  5. Any inline "if …" the AI infers from the prompt.

The first rule that says "skip" wins. Skipped items appear in the execution results with a Skipped badge and a short reason ("disabled by parent activity", "condition evaluated to false", …). The overall test still passes — Skipped is a neutral status, not a failure.

Loops

A loop repeats a piece of the test multiple times — once per row of a data table, while a condition holds, or a fixed number of times. As with conditions, the structured loop options are far more reliable than inline ones.

1. Activity-level loop

Open an activity's settings sidebar and choose Loop. A small wizard walks you through the configuration:

  1. Loop type — what kind of loop this is (see below).
  2. Loop condition / data source — the table, condition, or count that drives iteration.
  3. Parameter mapping — how iteration variables are bound to the parameters used inside the activity's steps (see Iteration variables and parameter mapping).
  4. Review — confirm and save.

The available loop types are:

Loop typeWhen to use
Over a data tableYou have a fixed set of rows (test data) and want one iteration per row. The most common case.
Static countYou want exactly N iterations regardless of any data — useful for stress checks or to repeat an action a fixed times.
Until / while (dynamic)The number of iterations isn't known up front; keep looping until the AI determines a condition is met (e.g. "until no more rows remain").
Do-until (dynamic)Like until / while, but the body always runs at least once before the condition is re-checked.
Hard iteration cap

Every loop has a built-in safety net of 15 iterations. Tests that depend on running more than that are almost certainly doing too much in one run — split the work, or refine the data source.

2. Snippet-level loop

A loop can also wrap a snippet-reference step. The configuration is identical to an activity loop (same wizard, same options), but the loop iterates the snippet's expanded steps instead of an activity's. Use this when the thing you want to repeat is an existing reusable snippet — for example, for each customer in this table, run the snippet "Onboard a customer".

3. Inline loop hint in the step prompt

Writing "for each row in the customers table, …" directly into a step prompt occasionally works, but is unreliable for the same reasons as inline conditions. Avoid it. If you find yourself writing one, replace it with an activity-level loop and a data table.

Iteration variables and parameter mapping

When a loop runs, each iteration produces values that the inner steps need to consume. The mapping happens in the loop wizard's Parameter mapping step. Each row in the mapping table is one parameter referenced inside the looping activity / snippet; for each, you choose where its value comes from in this iteration:

  • Column of the data table — typical when looping over a table. The cell at the current row's column becomes the parameter's value.
  • Iteration index — the iteration number, formatted as an ordinal word (first, second, …), a 1-based number (1, 2, …) or a 0-based number (0, 1, …).
  • Fixed value — a constant the inner steps should use.
  • Mapped from the calling test — a parameter of the calling test, passed straight through.
  • Screen iterator — for dynamic loops, a value the AI agent identifies on the page as the iteration handle.

The mapping is what makes the loop body refer to "the right thing" each iteration — without it, the inner steps would all keep referencing the same value.

Data tables

A data table is a parameter whose value is a table of rows and columns rather than a single value. See Test data for how to define one. Briefly: in the Variants tab you add a parameter of type Tabular, then open its editor to fill in rows and columns. Columns are free-form — there is no schema; the values inside the rows are plain text.

Once a table exists, a loop can iterate over its rows. Two row-matching strategies are available:

StrategyWhat it does
IndexTake row 1 for iteration 1, row 2 for iteration 2, … Stops when the table runs out of rows. The default and simplest choice.
LookupDon't iterate over the table in order — instead, for each iteration, find the row that matches certain column values (e.g. matching by ID or by what's currently on the screen). Useful when iteration order is driven by something else, not the order of rows.

In Lookup mode you also pick what happens if no row matches: skip the iteration, or fail it.

Combining loops and conditions

If an activity or snippet-reference has both a condition and a loop, the condition is evaluated first. If the condition is false, the loop never runs and the contained steps are skipped. If the condition is true, the loop runs as configured and the loop's own condition / data source decides how many iterations happen.

You can also disable individual steps inside the loop body with Disable on parameter, which is useful when only some iterations should run a particular step.

How loops and skipped items look in results

In the execution results, a loop is shown as one block with one section per iteration. Each iteration's header carries the iteration number and (for table loops) the row's values for quick scanning. Inside each iteration you see the steps, with their individual statuses.

Skipped steps and skipped activities appear with the Skipped badge described above, regardless of which rule caused the skip.

A few concrete examples

Activity-level condition

You have a Login flow activity, but if the user is already signed in you don't want to log in again.

  • Activity: Login flow containing four steps (open the login page, type the user, type the password, submit).
  • In the activity sidebar, set Condition to the login button is visible.

At runtime the AI evaluates whether the login button is visible. If it is, the four steps run; otherwise the entire activity is skipped.

Activity-level loop with a data table

You want to create three products in a row, each with different values.

  • In the Variants tab, create a parameter products of type Tabular. Add three rows with columns name, price, category.
  • Create an activity Create product containing the steps that fill the form and submit.
  • Open the activity sidebar, click Loop, pick Over a data table, choose products.
  • In Parameter mapping, bind the inner-step parameters [[name]], [[price]], [[category]] to the matching table columns.
  • Save.

At runtime the activity runs three times, once per row, with the row's values substituted into the inner steps.

Step-level Disable on parameter

You have a step Clear the cache that should only run when the test runs against the staging environment.

  • On the step's settings sidebar, turn Disable step on.
  • Choose Parameter = environment, Operator = !=, Value = staging.

The step is skipped unless [[environment]] equals staging. The decision is deterministic and does not depend on the AI agent.