Creating Loops in Test Cases

Thorough testing often requires repeating the same task multiple times to validate consistency, accuracy, and functionality. In Functionize, you can achieve this in two main ways:

  • Page Objects → Store reusable flows (e.g., login, search, navigation).
  • Loops → Repeat an action sequence in a test a fixed number of times or until a condition is met.

Loops provide more precision and flexibility than Page Objects. They allow you to test tasks comprehensively, uncover edge cases, and validate against conditions that may only appear after multiple iterations.

Shared Concepts

Viewing Completed Loops

  • By default, the Browser Results tab and Slider View show only the final iteration.
  • Click Show All Iterations to expand and view each iteration with pass/fail results.
  • Each iteration is labeled (L1, L2, L3, etc.) in the first Action of its sequence.

Visual Indicators in Results

  • The looped actions are highlighted in a blue wrapper.
  • A vertical line appears to the left of all looped Actions.
  • A dot marks the first Action in the Loop sequence.
  • A greater-than (>) icon in the Action footer highlights all steps in the Loop. Clicking the icon keeps the highlighting visible.
  • Nested loops display additional vertical lines and icons (e.g., L2, L3).

Use Cases

Shopping Cart Validation

  • Bug: cart item count did not always match the number of items added.
  • Solution: record a test that loops through adding multiple items, verifying that the display count increases each time.
  • Advanced check: include a Custom JS Action to validate that the cart total matches (iteration count × item price).

Dropdown Category Validation

  • Goal: ensure each category link in a dynamic menu navigates correctly.
  • Approach: create Variables capturing all category texts and hrefs, then iterate through them with a Custom JS Loop.

Adding Loops with Architect

  1. Record a new test up to the Loop insertion point.
  2. Record the Actions you want repeated.
  3. Open the Actions Sidebar Panel → select Loops.
  4. Choose:
    • X Times → repeat a fixed number of iterations.
    • Custom JS → define a condition (while logic).
    • Example: X Times = 10 iterations.
  5. Select the Actions to include (via white dot selectors or range selection).
  6. Click Add → Architect groups the Actions under a Loop container.

Dynamic Verification Example

  • Edit the Verify Action inside the Loop.
  • Replace a fixed text value (e.g., 1) with a dynamic expression: {{parseInt(fze.iteration) + 1}} 
  • This validates against the current iteration number.
  • Note: +1 is needed since iterations start at 0.

Adding Loops to an Existing Test

  1. Open the Test Detail Page.
  2. From the Insert Menu above the first Action in the sequence, click Loop.
  3. Choose X Times or Custom JS and enter values.
  4. Select the Loop End Action → Insert.
  5. Loops are visually denoted in the same way as in Architect (vertical line, dot, L1 icon, > icon).

Nested Loops

Functionize supports nested Loops:

  • Record Parent Loop Actions in Architect.
  • Add Child Loop in the Test Detail Page.
  • Visual indicators:
    • Second vertical line.
    • L2 notation.
    • Double greater-than icons in Action footer.

Editing Loops

  • Edit Actions → Expand Action within Loop and update.
  • Insert Actions → Use standard Insert process when Loop is collapsed.
  • Delete Actions → Use normal Delete inside Loop.
  • Delete Entire Loop → Removes the Loop wrapper but retains the Actions inside.

Advanced Use: Custom JS + Variables

Example: Category Menu Validation

Setup Variables

// Capture category link texts

let listElements = Array.from(document.getElementsByClassName("product-categories")[0].childNodes);

fze.local.categorylisttexts = [];

for (let i = 0; i < listElements.length; i++) {

  if (listElements[i].firstChild && listElements[i].firstChild.textContent) { 

fze.local.categorylisttexts.push(listElements[i].firstChild.textContent.trim());

  }

}

// Capture category link hrefs

fze.local.categorylisthrefs = [];

for (let i = 0; i < listElements.length; i++) {

  if (listElements[i].firstChild && listElements[i].firstChild.hasAttribute('href')) {

    fze.local.categorylisthrefs.push(listElements[i].firstChild.getAttribute('href'));

  }

}

This creates two arrays:

  • fze.local.categorylisttexts → menu labels.
  • fze.local.categorylisthrefs → menu URLs.

Define the Loop Condition

return fze.iteration < fze.local.categorylisttexts.length;

Use Dynamic Expressions

Click link by text:
{{fze.local.categorylisttexts[fze.iteration]}}

Verify correct URL opens:
{{fze.local.categorylisthrefs[fze.iteration]}}

Result: The test iterates through each menu option, clicks it, and verifies the correct page loads.

Loop using timeout and iteration limit

Code:

// Initialize startTime globally (persists during the test)

if (!window.startTime) {

window.startTime = Date.now();

}

// Continue loop while both conditions are true

return fze.iteration < 10 && (Date.now() - window.startTime) < 10000;

Explanation:

  • fze.iteration < 10 → stops after 10 iterations.

  • (Date.now() - window.startTime) < 10000 → stops if 10 seconds have passed.

  • window.startTime is global, persisting across iterations.

Purpose:

  • Adds a timeout safeguard to avoid infinite or long-running loops.

  • Ensures loop stops after max iterations or time limit, whichever comes first.

Use Case:

  • Loops where time or iteration limits are needed to prevent hanging.

Best Practices

  • Use X Times Loops for predictable iteration counts.
    • Variables can be used as iteration counts with SetVariable or TDM test actions.
  • Use Custom JS Loops for data-driven or condition-based workflows.
  • Always add verifications inside Loops to catch issues mid-iteration.
  • Use dynamic expressions (e.g., fze.iteration) instead of hardcoding values.
  • Nest Loops only when necessary → they can make debugging harder.
  • Keep Loops short and well-scoped.
  • Loops repeat Actions, while Page Objects store reusable flows. Combining both improves maintainability and reusability.
  • Incorporate conditional checks or try/catch logic within Custom JS Loops to handle intermittent failures gracefully.
  • Iteration-specific screenshots help identify exactly which iteration failed.

Additional Considerations

  • Be aware that Loops will increase execution time.
  • Use waits or conditional waits for elements that load slowly or dynamically to mitigate test flakiness.
  • Test action limits still apply to test cases with loops and are cumulative.