# 9.13 - Test Designer 2.0 / Test Designer 3.0

Test Designer 2.0 / Test Designer 3.0 — Knowledge Base articles.

# Appvance Test Designer 2.0 / Test Designer 3.0

## Contents

- [Automating Multi-Factor Authentication](/books/test-designer-20-test-designer-30/page/automating-multi-factor-authentication)
- [Browser Versions](/books/test-designer-20-test-designer-30/page/browser-versions)
- [How to automate the Scroll bar?](/books/test-designer-20-test-designer-30/page/how-to-automate-the-scroll-bar)
- [How to find the position of an html element?](/books/test-designer-20-test-designer-30/page/how-to-find-the-position-of-an-html-element)
- [How to add Snapshot step in a designer script 2.0?](/books/test-designer-20-test-designer-30/page/how-to-add-snapshot-step-in-a-designer-script-20)
- [How to access and extract the content of the table](/books/test-designer-20-test-designer-30/page/how-to-access-and-extract-the-content-of-the-table)
- [How can I wait for an object to disappear?](/books/test-designer-20-test-designer-30/page/how-can-i-wait-for-an-object-to-disappear)
- [Function to return date in any required format.](/books/test-designer-20-test-designer-30/page/function-to-return-date-in-any-required-format)
- [EnterKey Event in Sahi.](/books/test-designer-20-test-designer-30/page/enterkey-event-in-sahi)
- [Designer : File:// protocol support in Designer](/books/test-designer-20-test-designer-30/page/designer-file-protocol-support-in-designer)
- [Date Functions and Formatting](/books/test-designer-20-test-designer-30/page/date-functions-and-formatting)
- [About Shadow DOM Settings](/books/test-designer-20-test-designer-30/page/about-shadow-dom-settings)
- [Granting Microphone Permissions](/books/test-designer-20-test-designer-30/page/granting-microphone-permissions)
- [How to get the application URL?](/books/test-designer-20-test-designer-30/page/how-to-get-the-application-url)
- [How to get all values of dropdown](/books/test-designer-20-test-designer-30/page/how-to-get-all-values-of-dropdown)
- [How to get hidden elements from DOM?](/books/test-designer-20-test-designer-30/page/how-to-get-hidden-elements-from-dom)
- [How to generate a random number within a given range?](/books/test-designer-20-test-designer-30/page/how-to-generate-a-random-number-within-a-given-range)
- [How to fetch specific date format?](/books/test-designer-20-test-designer-30/page/how-to-fetch-specific-date-format)
- [How to data drive Xpaths](/books/test-designer-20-test-designer-30/page/how-to-data-drive-xpaths)
- [How to Fetch a row which has a particular Style?](/books/test-designer-20-test-designer-30/page/how-to-fetch-a-row-which-has-a-particular-style)
- [How to extract Only Number and "." from a string?](/books/test-designer-20-test-designer-30/page/how-to-extract-only-number-and-from-a-string)
- [How to check Scrollbar is reached to the bottom](/books/test-designer-20-test-designer-30/page/how-to-check-scrollbar-is-reached-to-the-bottom)
- [How to enter 3 digit random number in DS/JS script](/books/test-designer-20-test-designer-30/page/how-to-enter-3-digit-random-number-in-dsjs-script)
- [How to create a unique string for use in designer script?](/books/test-designer-20-test-designer-30/page/how-to-create-a-unique-string-for-use-in-designer-script)
- [How to call a JS function from Test Designer IDE](/books/test-designer-20-test-designer-30/page/how-to-call-a-js-function-from-test-designer-ide)
- [How to data drive a wait statement?](/books/test-designer-20-test-designer-30/page/how-to-data-drive-a-wait-statement)
- [How to check Browser Scrollbar is reached to the bottom](/books/test-designer-20-test-designer-30/page/how-to-check-browser-scrollbar-is-reached-to-the-bottom)
- [How to escape special characters in Designer](/books/test-designer-20-test-designer-30/page/how-to-escape-special-characters-in-designer)
- [Closing a window](/books/test-designer-20-test-designer-30/page/closing-a-window)
- [How to handle Multiple DPL files in Test Designer IDE](/books/test-designer-20-test-designer-30/page/how-to-handle-multiple-dpl-files-in-test-designer-ide)
- [How to handle pop-ups in a website using designer?](/books/test-designer-20-test-designer-30/page/how-to-handle-pop-ups-in-a-website-using-designer)
- [How to hold and free toast message](/books/test-designer-20-test-designer-30/page/how-to-hold-and-free-toast-message)
- [How to parameterize files for the file upload feature?](/books/test-designer-20-test-designer-30/page/how-to-parameterize-files-for-the-file-upload-feature)
- [How to Read and Write multiple rows from the CSV file?](/books/test-designer-20-test-designer-30/page/how-to-read-and-write-multiple-rows-from-the-csv-file)
- [How to remove all extra spacing between words?](/books/test-designer-20-test-designer-30/page/how-to-remove-all-extra-spacing-between-words)
- [How to retrieve all the elements on a page](/books/test-designer-20-test-designer-30/page/how-to-retrieve-all-the-elements-on-a-page)
- [How to retrieve the only number from a string?](/books/test-designer-20-test-designer-30/page/how-to-retrieve-the-only-number-from-a-string)
- [How to retrieve value between 2 characters?](/books/test-designer-20-test-designer-30/page/how-to-retrieve-value-between-2-characters)
- [How to stop the Sahi logging feature in Appvance IQ.](/books/test-designer-20-test-designer-30/page/how-to-stop-the-sahi-logging-feature-in-appvance-iq)
- [How to trim a string value from a string?](/books/test-designer-20-test-designer-30/page/how-to-trim-a-string-value-from-a-string)
- [How to use custom functions from JS file in Test Designer](/books/test-designer-20-test-designer-30/page/how-to-use-custom-functions-from-js-file-in-test-designer)
- [How to Validate whether the video is played back?](/books/test-designer-20-test-designer-30/page/how-to-validate-whether-the-video-is-played-back)
- [How to verify checkbox is checked/unchecked ?](/books/test-designer-20-test-designer-30/page/how-to-verify-checkbox-is-checkedunchecked)
- [How to verify Sorting Functionality](/books/test-designer-20-test-designer-30/page/how-to-verify-sorting-functionality)
- [How to verify the disabled button?](/books/test-designer-20-test-designer-30/page/how-to-verify-the-disabled-button)
- [Include functionality in Appvance Designer](/books/test-designer-20-test-designer-30/page/include-functionality-in-appvance-designer)
- [Latency in AssertExists.](/books/test-designer-20-test-designer-30/page/latency-in-assertexists)
- [Logging Specific Errors](/books/test-designer-20-test-designer-30/page/logging-specific-errors)
- [Pagination - How to search items in a page with multiple paginations](/books/test-designer-20-test-designer-30/page/pagination-how-to-search-items-in-a-page-with-multiple-paginations)
- [Questions of Self-Healing in Test Designer](/books/test-designer-20-test-designer-30/page/questions-of-self-healing-in-test-designer)
- [Regular Expression in Appvance Designer.](/books/test-designer-20-test-designer-30/page/regular-expression-in-appvance-designer)
- [Solutions to common Test Designer IDE Challenges](/books/test-designer-20-test-designer-30/page/solutions-to-common-test-designer-ide-challenges)
- [Statistics at a higher summary level for grouping steps](/books/test-designer-20-test-designer-30/page/statistics-at-a-higher-summary-level-for-grouping-steps)
- [Test Designer 3: HTML5 Support](/books/test-designer-20-test-designer-30/page/test-designer-3-html5-support)
- [To reload a page from a script](/books/test-designer-20-test-designer-30/page/to-reload-a-page-from-a-script)
- [Using setFile in Test Designer with Relative Paths](/books/test-designer-20-test-designer-30/page/using-setfile-in-test-designer-with-relative-paths)
- [Using while loop in Test Designer 2.0](/books/test-designer-20-test-designer-30/page/using-while-loop-in-test-designer-20)
- [Using writeCSVFile API in Sahi.](/books/test-designer-20-test-designer-30/page/using-writecsvfile-api-in-sahi)
- [Working Around Asynchronous Popups](/books/test-designer-20-test-designer-30/page/working-around-asynchronous-popups)
- [Which JavaScript version is supported?](/books/test-designer-20-test-designer-30/page/which-javascript-version-is-supported)
- [Clicking on Record, do not see the browsers listed.](/books/test-designer-20-test-designer-30/page/clicking-on-record-do-not-see-the-browsers-listed)
- [Handling the Location Permission Browser Popup](/books/test-designer-20-test-designer-30/page/handling-the-location-permission-browser-popup)
- [How to get the downloaded files in test designer?](/books/test-designer-20-test-designer-30/page/how-to-get-the-downloaded-files-in-test-designer)
- [Which Accessors can be self-healed?](/books/test-designer-20-test-designer-30/page/which-accessors-can-be-self-healed)
- [Authentication Mechanism in Appvance](/books/test-designer-20-test-designer-30/page/authentication-mechanism-in-appvance)
- [How can I validate and handle a failure in my app so my script can continue?](/books/test-designer-20-test-designer-30/page/how-can-i-validate-and-handle-a-failure-in-my-app-so-my-script-can-continue)
- [How can use a wild card when part of the identifier is always changing?](/books/test-designer-20-test-designer-30/page/how-can-use-a-wild-card-when-part-of-the-identifier-is-always-changing)
- [SmartTags: Using a custom getName Method](/books/test-designer-20-test-designer-30/page/smarttags-using-a-custom-getname-method)
- [Register any email with Google Drive](/books/test-designer-20-test-designer-30/page/register-any-email-with-google-drive)
- [Maximizing the number of concurrent browsers](/books/test-designer-20-test-designer-30/page/maximizing-the-number-of-concurrent-browsers)
- [How are step time durations calculated in Test Designer](/books/test-designer-20-test-designer-30/page/how-are-step-time-durations-calculated-in-test-designer)
- [Iteration Summary Error Message](/books/test-designer-20-test-designer-30/page/iteration-summary-error-message)
- [How to capture and validate tooltips using Test Designer](/books/test-designer-20-test-designer-30/page/how-to-capture-and-validate-tooltips-using-test-designer)
- [How to access two different application at the same time in a single script.](/books/test-designer-20-test-designer-30/page/how-to-access-two-different-application-at-the-same-time-in-a-single-script)
- [How to find the X Y Coordinates](/books/test-designer-20-test-designer-30/page/how-to-find-the-x-y-coordinates)
- [How to perform Mouse Over action using Toggle Style API From Test Designer](/books/test-designer-20-test-designer-30/page/how-to-perform-mouse-over-action-using-toggle-style-api-from-test-designer)
- [How to verify a particular user is available in the database or not?](/books/test-designer-20-test-designer-30/page/how-to-verify-a-particular-user-is-available-in-the-database-or-not)
- [Validate Color of an Object](/books/test-designer-20-test-designer-30/page/validate-color-of-an-object)
- [MFA Authentication Automation](/books/test-designer-20-test-designer-30/page/mfa-authentication-automation)
- [Creating Multiple Orders and Writing the Order IDs into a CSV File on the Repository](/books/test-designer-20-test-designer-30/page/creating-multiple-orders-and-writing-the-order-ids-into-a-csv-file-on-the-repository)
- [Read and Write Data from a Downloaded XLSX File](/books/test-designer-20-test-designer-30/page/read-and-write-data-from-a-downloaded-xlsx-file)

This section contains a collection of articles from the Appvance Knowledge Base.

<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Automating Multi-Factor Authentication in Scenario Editor

# Automating Multi-Factor Authentication in Scenario Editor

Automate MFA only in approved test environments where the authentication flow is designed for repeatable testing. Do not bypass MFA protections in production or capture real user secrets in scenarios.

## Recommended options

- Use a test-only account with an approved MFA method.
- Prefer test bypass codes, sandbox identity-provider rules, or dedicated automation policies when the customer provides them.
- Store any test tokens or secrets in secured variables, not directly in steps.
- Use Scenario Editor validations to confirm the post-login state instead of relying only on timing.
- Document the identity provider, test account type, and approved MFA handling pattern.

## Validation workflow

1. Confirm that MFA automation is approved for the target environment.
2. Run the login flow once manually and document the expected challenge.
3. Add the Scenario Editor steps using test-safe inputs only.
4. Validate the landing page or authenticated state after MFA completes.
5. Review logs to confirm secrets are not printed.

**Security note:** This article is for authorized test automation only. It must not be used to weaken or bypass MFA for real users.

*Last updated: October 8, 2026*

# Browser Versions for Scenario Editor Testing

## Recommended guidance

Browser version alignment is important for reliable Scenario Editor playback. Validate the browser, browser driver, Test Node, operating system, and AIQ version together before treating a failure as a scenario defect.

## When to check browser versions

- A scenario fails after Chrome, Firefox, Edge, or the operating system updates.
- Playback works on one Test Node but fails on another.
- Selectors, downloads, popups, certificates, or permissions behave differently between runs.
- Headless and headed execution produce different results.

## Recommended checks

1. Record the browser name, browser version, Test Node, operating system, and AIQ build used for the run.
2. Confirm the browser is supported by the current AIQ release and the selected execution mode.
3. Check enterprise-managed browser policies before changing browser settings.
4. Reproduce with a controlled browser version when troubleshooting regressions.
5. Update documentation and execution notes when a browser version becomes a known dependency.

**Terminology note:** Use Scenario Editor for current AIQ authoring and playback references. Older Test Designer references should be treated as legacy unless the page is specifically describing a legacy asset.

*Last updated: October 5, 2026*

# Automate Scrolling in Scenario Editor

# Automate Scrolling in Scenario Editor

Use scrolling when the target element or content is not currently visible in the browser viewport. Prefer scrolling to a stable element or section over relying on pixel-only movements.

## Recommended workflow

1. Identify the element or section the scenario needs to reach.
2. Scroll until the target is visible and stable.
3. Use a conditional wait if content loads asynchronously after scrolling.
4. Perform the validation or action once the target is ready.

## Good practices

- Avoid scroll steps that depend on a specific screen size unless that is the test objective.
- Validate the target element after scrolling before clicking or typing.
- Document mobile or responsive behavior separately when scrolling differs by viewport.

**Last updated:** September 9, 2026

# Find the Position of an HTML Element in Scenario Editor

## Recommended guidance

Use element position checks only when a Scenario Editor test truly needs layout validation or coordinate-aware behavior. Prefer stable accessors, labels, and assertions before relying on screen coordinates, because positions can change by browser, device, zoom, responsive layout, or application state.

## When position matters

- Verifying that an element is visible inside a viewport or container.
- Checking scroll behavior, drag targets, or visual placement.
- Troubleshooting why a click or gesture hits the wrong area.
- Comparing responsive layouts across browsers or screen sizes.

## Validation checklist

1. Confirm the element is present, visible, and not covered by another element.
2. Record browser, viewport, zoom, device scale, and Test Node details.
3. Use waits so layout has stabilized before reading position.
4. Avoid hard-coded coordinates unless there is no stable semantic locator.

*Last updated: October 6, 2026*

# Add Snapshot Evidence in Scenario Editor

# Add Snapshot Evidence in Scenario Editor

This page replaces old Designer 2.0 wording with current Scenario Editor guidance. Add snapshot evidence when a screenshot or captured state will help diagnose a failure or prove an important business checkpoint.

## When snapshots help

- Before and after a critical action.
- At the first meaningful failure point.
- When validating layout, displayed data, or a confirmation page.
- When troubleshooting intermittent behavior across browsers or Test Nodes.

## Good practices

1. Name the step clearly so the snapshot is easy to find in output.
2. Capture only useful checkpoints; too many snapshots make analysis noisy.
3. Keep sensitive customer data out of screenshots when possible.
4. Attach execution output to the related defect or maintenance note.

**Last updated:** September 9, 2026

# How to access and extract the content of the table

Below is example script using demosite to get table row/column length and get the text of cell.This example doesnt have any unique accessor so going by row/cell counter along with relational accessor.In case if there’s any unique identifier is available to access row/cell,same can be used directly as well.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/N8AlwDCZUPO7EMh8-f6d8ad48c761.png)<span>[table\_cell\_Data.ds](../../../Resources/Images/GeneralGraphics/table_cell_Data.ds)</span>

<div id="bkmrk-last-updated%3A-july-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">July 03, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How can I wait for an object to disappear?

# Problem

I need to wait until an object disappears.

### Context

My application has reports it generates, and it can take time. When a report is generating, an animated Please Wait image and text appears. Once the report is generated, the page loads and the Please Wait image and text goes away.

# Solution

### Option A

Wait until the object is no longer visible, but only wait for a maximum amount of time. Notice the not (!) negating the isVisible statement.

<div id="bkmrk-action-accessor-wait"> <table> <tbody> <tr> <td>**Action**

 </td> <td>**Accessor**

 </td> </tr> <tr> <td> Wait

 </td> <td> 60000,!(isVisible(paragraph("Please Wait")))

 </td> </tr> </tbody> </table>

 </div>### Option B

If you want to wait, as well as check something else while waiting, you could use .wasNotFound() in a While. Note: The Set Search Retries lowered to and then restored after the While completes.

<div id="bkmrk-action-accessor-set-"> <table> <tbody> <tr> <td>**Action**

 </td> <td>**Accessor**

 </td> </tr> <tr> <td>Set Search Retries

 </td> <td>2

 </td> </tr> <tr> <td>While

 </td> <td>!(paragraph("Please Wait").wasNotFound())

 </td> </tr> <tr> <td>Wait

 </td> <td>1000

 </td> </tr> <tr> <td>End While

 </td> <td> </td> </tr> <tr> <td>Set Search Retries

 </td> <td>12

 </td> </tr> </tbody> </table>

 </div><div id="bkmrk-last-updated%3A-june-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 02, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Return the Current Date in a Specified Format

You can use the following function to return the current date in a specific format.

The example below returns the date in the following format:

```text
DD-MMM-YYYY
```

For example:

```text
24-Aug-2026
```

## Example

```javascript
function datefunc() {

    var monthNames = new Array(
        "Jan", "Feb", "Mar",
        "Apr", "May", "Jun",
        "Jul", "Aug", "Sep",
        "Oct", "Nov", "Dec"
    );

    var date = new Date();

    var day = date.getDate();
    if (day < 10) {
        day = "0" + day;
    }

    var month = date.getMonth();
    var year = date.getFullYear();

    var formattedDate = day + "-" + monthNames[month] + "-" + year;

    return formattedDate;
}

var currentDate = datefunc();
log(currentDate);
```

## How It Works

The function uses the JavaScript `<span class="editor-theme-code">Date</span>` object to retrieve the current date.

- `<span class="editor-theme-code">getDate()</span>` returns the day of the month.
- `<span class="editor-theme-code">getMonth()</span>` returns the month as a zero-based value (`<span class="editor-theme-code">0</span>` for January through `<span class="editor-theme-code">11</span>` for December).
- `<span class="editor-theme-code">getFullYear()</span>` returns the four-digit year.
- The month number is used to retrieve the corresponding abbreviated month name from the `<span class="editor-theme-code">monthNames</span>` array.
- A leading zero is added to the day when necessary.

For example, if the current date is August 24, 2026, the function returns:

```text
24-Aug-2026
```

## Changing the Date Format

You can modify the `<span class="editor-theme-code">formattedDate</span>` expression to return a different format.

For example, to return `<span class="editor-theme-code">YYYY-MM-DD</span>`:

```javascript
var formattedDate = year + "-" + (month + 1) + "-" + day;
```

To return `<span class="editor-theme-code">DD/MM/YYYY</span>`:

```javascript
var formattedDate = day + "/" + (month + 1) + "/" + year;
```

> **Note:** `<span class="editor-theme-code">getMonth()</span>` returns a zero-based month value. Therefore, add `<span class="editor-theme-code">1</span>` when using the numeric month directly in the formatted date.

---

Last updated: August 24, 2026

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>.

# EnterKey Event in Sahi.

Below is the sample code snippet to work with EnterKey.

<div id="bkmrk-var-%24storedvars-%3D-ne" style="border-width:1px;"><div>```
var $storedVars = new Array();
_sahi.robot = new java.awt.Robot();
Sahi.prototype._typeNativeKeyCode = function(keyCode){
this.robot.keyPress(keyCode);
this.robot.keyRelease(keyCode);
};
_navigateTo("http://sahitest.com/demo/training/login.htm");
_setValue(_textbox("user"),"test");
_setValue(_password("password"),"secret");
_sahi._typeNativeKeyCode(java.awt.event.KeyEvent.VK_ENTER);
_wait(10000);
```

 </div> </div>   
Since Key events happens at OS level, Please make sure that your app under test is active while re-playing the test.

<div id="bkmrk-last-updated%3A-march-">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">March 09, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Designer: file:// Protocol Support

Issue

Appvance Designer does not support automating pages opened directly using the `<span class="editor-theme-code">file://</span>` protocol.

## Solution

To automate a local HTML page with Designer, serve the page through a web server instead of opening it directly with the `<span class="editor-theme-code">file://</span>` protocol.

1. Start a web server that serves the directory containing your HTML pages.
2. Open the page using its HTTP or HTTPS URL, for example:  
    `<span class="editor-theme-code">http://localhost:8080/index.html</span>`
3. Open the page in Designer using the web server URL.
4. Create or run your automation against the page served through HTTP/HTTPS.

> **Note:** Opening the page directly from the local file system using a URL such as `<span class="editor-theme-code">file:///C:/path/to/page.html</span>` is not supported for Designer automation.

---

**Last updated:** August 19, 2026

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>.

# Date Functions and Formatting

<u>First example is this:</u>

Create a logic so that the script should always choose a date that is 3 days ahead of the todays date and make sure that 3 days ahead date is not landing on any weekends i.e., Sat/Sun.

function getThreeDaysAhead()  
{  
var myDate = new Date();  
myDate.setDate(myDate.getDate() + 3); //Three days ahead of today's date  
var day = myDate.getDay(); //getDay() returns 0-6, 0 for sunday.. , 6 for saturday  
log(day);  
if (day == 6) {  
myDate.setDate(myDate.getDate() + 2); //If saturday , do plus 2 days  
} else if (day == 0) {  
myDate.setDate(myDate.getDate() + 1); // If Sunday , do plus 1 day  
}

return formatDate(myDate);

}

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/FAEe0sOCeIKP3Dlz-805d676d7dc9.png)<u>Date Formatting functions:</u>

function formatDate(date) {  
var d = new Date(date),  
month = '' + (d.getMonth() + 1),  
day = '' + d.getDate(),  
year = d.getFullYear();

if (month.length &lt; 2)  
month = '0' + month;  
if (day.length &lt; 2)  
day = '0' + day;

return \[month, day, year\].join('/');

}

Below are some examples using toLocaleDateString();

var date2 = new Date(date1).toLocaleDateString("en-US");  
log(date2); //will return in US time format  
var options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };  
var date3 = new Date(date1).toLocaleDateString("en-US", options);  
log(date3); ////will return in US time format with options as specified above  
var date4 = new Date(date1).toLocaleDateString("en-GB", options);  
log(date4); //will return in UK time format

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/NJPmcOpaJ9k7007g-9bcbaf8d6fbc.png)<span>[date.js](../../../Resources/Images/GeneralGraphics/date.js)</span>

some examples from browser console using toLocaleDateString functions:

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/xl2sNq5YZ9td84aK-1da849266ada.png)These functions can be directly used in ds file – customJS as action and function name can be called simply like the normal javascript calling.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/nQceqnRLTUVPJxcK-71e30fdd6917.png)<div id="bkmrk-last-updated%3A-july-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">July 03, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Shadow DOM Settings for Scenario Editor Tests

## Recommended guidance

Shadow DOM can hide application elements behind component boundaries, which affects how Scenario Editor identifies and interacts with controls. Review Shadow DOM settings when selectors work on normal pages but fail inside web components.

## When to review these settings

- Elements are visible but cannot be found during playback.
- Recorded locators are unstable inside custom components.
- Self-healing chooses a similar element outside the intended component.
- The application framework changed and moved elements into shadow roots.

## Maintenance workflow

1. Confirm the target element is inside open or closed Shadow DOM.
2. Use stable labels, accessible names, or application-provided test attributes when possible.
3. Validate the selector in the same browser and Test Node used by the scenario.
4. Update waits and assertions so the component is ready before interaction.
5. Document Shadow DOM dependencies that may break after front-end framework changes.

*Last updated: October 6, 2026*

# Grant Microphone Permissions for Scenario Editor Tests

**Last reviewed:** October 2, 2026

Use this article when a Scenario Editor test must interact with a browser workflow that requests microphone access.

## What changed in this article

- Replaced generic permission wording with Scenario Editor and browser permission setup guidance.
- Added checks for browser profile, test environment policy, HTTPS requirement, permission persistence, and evidence capture.
- Clarified that production user microphone prompts should not be handled with personal accounts or real user data.

## Validation workflow

1. Confirm the test environment is approved to use microphone access and does not capture sensitive audio.
2. Preconfigure the browser profile or test policy so the permission behavior is deterministic.
3. Run the scenario and verify the permission state, browser prompt behavior, and resulting evidence.

**Review note:** This page now treats microphone access as a controlled browser-permission setup task.

---

Last updated: October 2, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# How to get the application URL?

Suppose you want to extract the URL of the application. Below is the method to extract it.

\_eval("window.location.href")

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/eMFjBQ48JqgZklup-0bd77185970e.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to get all values of dropdown

Below is example script that shows how to get all text and option values of dropdown

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/7hIXJv2lKMCZSDaf-19931dfa3493.png)<span>[SetSelectedExamples.ds](../../../Resources/Images/GeneralGraphics/SetSelectedExamples.ds)</span>

<div id="bkmrk-last-updated%3A-july-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">July 03, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to get hidden elements from DOM?

Steps:

1. Open the application in the chrome browser
2. Inspect the element
3. Go to the console tab
4. Paste this code : javascript:(function(){var newScript = document.createElement('script'); newScript.type = 'text/javascript; newScript.src = '[//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js](https://appvance.slack.com//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js)'; document.getElementsByTagName("head")\[0\].appendChild(newScript);})();  
    setTimeout(function(){  
    console.log($('#ELEMENT\_Attribute').html());},18000);
5. Mouse over on the element and wait
 
<div id="bkmrk-last-updated%3A-june-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 02, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to Generate a Random Number Within a Given Range

You can use the following JavaScript expression to generate a random integer within a specified range, including both the minimum and maximum values:

```
var $randomnumber = Math.floor(Math.random() * ($maximum - $minimum + 1)) + $minimum;
```

For example, the following code generates a random integer between `<span class="editor-theme-code">3</span>` and `<span class="editor-theme-code">7</span>`:

```
var $randomnumber = Math.floor(Math.random() * (7 - 3 + 1)) + 3;
```

The generated value can be `<span class="editor-theme-code">3</span>`, `<span class="editor-theme-code">4</span>`, `<span class="editor-theme-code">5</span>`, `<span class="editor-theme-code">6</span>`, or `<span class="editor-theme-code">7</span>`.

The random value can then be used in a Test Designer action. For example:

```
_highlight(_link($randomnumber, _near(_span("Smart Account"))))
```

This approach is useful when test scripts need to select or interact with different values dynamically during execution.

---

Last updated: August 21, 2026

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

# How to fetch specific date format?

Ex: October 20, 2020

=today().format('MMMM d,Y')

Add Functions and methods in JS DPL:

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/LzZFbbstlW4ubXnr-ac7ea6aabda9.png)Evaluate DPL:

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/48Yz8F5C35ATwU75-1eedcd27466f.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to Data-Drive Xpaths

In some scenarios, the XPath used by an accessor may need to be dynamically generated based on test data. Test Designer supports data-driven XPaths by using variables within the XPath expression.

The following example shows how to use a variable as part of an XPath:

byXPath("//\*\[@id='" + $Test + "'\]")

In this example, $Test is replaced with the value provided by the test data, allowing the same accessor to interact with different elements during test execution.

# How to Fetch a row which has a particular Style?

If the user wants to click a particular link for with Particular Style

Ex: if the user wants to click the link which has Style = background-color:rgb(1,0,0)

The user can use this in the accessor column

cell("style==background-color:rgb(1,0,0)")

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/fTOVMafhVkNRx36W-fdfbf19ed450.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to extract Only Number and "." from a string?

**string.replace(/\[^0-9.\]/g, "") / string.replace(/\[^a-zA-Z0-9.\]/g, '')**

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/hVfsQ4KAd20u3duv-d4803c61e73f.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Check Whether a Scrollbar Has Reached the Bottom

When working with applications that contain scrollable grids or containers, you may need to scroll through the content until a specific cell becomes visible.

The following function checks whether the specified cell is visible. If the cell is not visible, it scrolls the target vertical scrollbar and continues checking until the cell is reached.

> **Note:** The scrollbar selector used in this example is specific to the application's DOM structure. The index (`<span class="editor-theme-code">[2]</span>`) may need to be adjusted depending on which scrollbar is being targeted.

```javascript
function IsScrollbarAtBottom(VARIABLE) {

    var totalHeight = 1;
    var clientHeight = 0;

    while (totalHeight > clientHeight) {

        var scrollHeight = _eval(
            "document.getElementsByClassName('k-scrollbar k-scrollbar-vertical')[2].scrollHeight"
        );
        var intScrollHeight = parseInt(scrollHeight);

        var scrollTop = _eval(
            "document.getElementsByClassName('k-scrollbar k-scrollbar-vertical')[2].scrollTop"
        );
        var intScrollTop = parseInt(scrollTop);

        var offsetHeight = _eval(
            "document.getElementsByClassName('k-scrollbar k-scrollbar-vertical')[2].clientHeight"
        );
        clientHeight = parseInt(offsetHeight);

        totalHeight = intScrollHeight - intScrollTop;

        log("Scroll height: " + intScrollHeight);
        log("Scroll position: " + intScrollTop);
        log("Client height: " + clientHeight);
        log("Remaining height: " + totalHeight);

        if (isVisible(cell(VARIABLE))) {
            totalHeight = clientHeight;
        } else {
            _eval(
                "document.getElementsByClassName('k-scrollbar k-scrollbar-vertical')[2].scroll(0,40000)"
            );
        }
    }
}

IsScrollbarAtBottom(VARIABLE);
```

## How It Works

The function performs the following operations:

1. Retrieves the total height of the target scrollbar using `<span class="editor-theme-code">scrollHeight</span>`.
2. Retrieves the current vertical scroll position using `<span class="editor-theme-code">scrollTop</span>`.
3. Retrieves the visible height of the scrollbar using `<span class="editor-theme-code">clientHeight</span>`.
4. Calculates the remaining scrollable height.
5. Checks whether the specified cell is visible using `<span class="editor-theme-code">isVisible(cell(VARIABLE))</span>`.
6. If the cell is visible, the function stops.
7. If the cell is not visible, the scrollbar is moved down and the check is repeated.

The following calculation determines how much content remains below the current scroll position:

```javascript
totalHeight = scrollHeight - scrollTop;
```

## Identifying the Target Scrollbar

The example uses the following DOM selector:

```javascript
document.getElementsByClassName(
    'k-scrollbar k-scrollbar-vertical'
)[2]
```

The `<span class="editor-theme-code">[2]</span>` selects the third matching scrollbar element on the page. This value is application-specific and may need to be changed if the page contains a different number or order of vertical scrollbars.

## Example

To scroll until a specific cell becomes visible:

```javascript
IsScrollbarAtBottom(VARIABLE);
```

Replace `<span class="editor-theme-code">VARIABLE</span>` with the value used to identify the target cell.

> **Important:** Despite the function name, the primary purpose of this implementation is to scroll through a container until the specified cell becomes visible. It should not be considered a generic scrollbar-position API.

# Generate a Three-Digit Random Number in Scenario Editor

# Generate a Three-Digit Random Number in Scenario Editor

Use generated numeric data when a Scenario Editor test needs a simple unique or variable value. Keep the generation rule easy to understand and validate that the application accepts the expected numeric range.

## Recommended approach

- Generate values from 100 through 999 when a true three-digit number is required.
- Use a DPL or approved helper when the value must be reused across steps.
- Store the generated value if later validation needs to compare it.
- Avoid using random values for data that must be repeatable for troubleshooting.

## Validation workflow

1. Generate the number before the input step.
2. Enter it into the target field.
3. Validate that the application saved or displayed the same value.
4. Capture the value in output when diagnosing failures.

**Last updated:** September 9, 2026

# Create Unique Strings in Scenario Editor Scripts

**Last reviewed:** September 28, 2026

Use this article when a Scenario Editor script needs unique values for usernames, emails, order IDs, or other test data.

## What changed in this article

- Replaced “designer script” wording with Scenario Editor terminology.
- Added examples of when to use timestamp, random number, GUID-style value, or DPL-driven uniqueness.
- Added a warning to avoid unique strings that break downstream cleanup, reporting, or repeatability.

## Validation workflow

1. Choose the uniqueness strategy based on the system under test and cleanup requirements.
2. Store the generated value if later steps need to reuse it for validation.
3. Run the scenario twice and confirm each run creates a distinct value without breaking assertions.

**Review note:** The page now explains the data strategy, not just a code trick for generating a string.

---

Last updated: September 28, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# Call JavaScript Functions from Scenario Editor

**Last reviewed:** September 25, 2026

Use this article when a Scenario Editor test needs to call a custom JavaScript function from JS Edit &amp; Play.

## What changed in this article

- Replaced “Test Designer IDE” wording with Scenario Editor terminology.
- Corrected the old typo “Fist step” and clarified that Include loads the script before customJS calls the function.
- Separated examples for DPL-driven parameters, hard-coded parameters, and values captured with Store/getText so users can choose the right call pattern.

## Validation workflow

1. Add the JavaScript file with Include before calling the function.
2. Call the function with customJS and pass parameters from DPL, constants, or captured variables.
3. Replay the step in JS Edit &amp; Play and then run the scenario to confirm the function executes in context.

**Review note:** Kept the article as useful Scenario Editor guidance, but modernized the naming and parameter examples.

---

Last updated: September 25, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# Data-Drive Wait Values in Scenario Editor

# Data-Drive Wait Values in Scenario Editor

Use data-driven wait values only when different test data genuinely requires different timing. Prefer conditional waits based on application state whenever possible.

## When data-driven waits make sense

- Different workflows have documented processing windows.
- External systems return at different approved polling intervals.
- The timing value is part of the test data model and needs traceability.

## Good practices

1. Store timing values in an approved DPL or test data source.
2. Use clear field names such as waitTimeoutSeconds or pollingIntervalSeconds.
3. Set maximum limits so bad data does not create excessive waits.
4. Review repeated wait failures before increasing data-driven timing values.

**Last updated:** September 9, 2026

# Validate Scrolling Reaches the Bottom of a Page

# Validate Scrolling Reaches the Bottom of a Page

Use this pattern when a Scenario Editor test must confirm that the browser reached the bottom of a page, list, or scrollable container. This is common for lazy-loaded content, terms pages, infinite scroll, or long result lists.

## Recommended checks

- Validate a stable element that appears only near the bottom.
- Check that lazy-loaded content has finished loading before continuing.
- Use a container-specific check if the page has multiple scrollable areas.
- Avoid assuming that one scroll action always reaches the bottom on every viewport.

## Validation workflow

1. Scroll toward the target area.
2. Wait for the expected bottom marker, footer, or final item.
3. Assert that the expected element or content is visible.
4. Capture output if the page continues loading or the target never appears.

**Last updated:** September 9, 2026

# How to escape special characters in Designer

What do we do when we encounter a special character and we have to assert it in a designer script ?

Lets take the below Example:

User navigates to the Apple website and tries to do a assert on iphone page and finds that the iphone 7 has special character " just before 7. So the user now has to assert iPhone"7 which contains a special character just before 7.

We can "\\" to escape the special character and run the script successfully.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/VYvRyqFjstu0oJCA-b5d9416e81f7.png)

For characters that are usually treated specially, '\\' indicates that the next character is not special and should be interpreted literally.

<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Close Browser Windows in Scenario Editor

# Close Browser Windows in Scenario Editor

Use this guidance when a Scenario Editor test opens a second browser window, tab, or popup and must return to the main application flow. Keep window handling explicit so the test does not continue in the wrong context.

## Recommended workflow

1. Trigger the action that opens the new window or tab.
2. Wait for the expected window, tab, or popup to be available.
3. Validate or capture the needed content.
4. Close the secondary window and switch back to the original context.
5. Validate that the next step runs in the intended page.

## Good practices

- Use clear step names that identify the window being handled.
- Avoid relying on window order if titles or URLs can be validated.
- Capture output when popup behavior fails or is blocked by the browser.

**Last updated:** September 9, 2026

# How to handle Multiple DPL files in Test Designer IDE

We can add multiple DPL files in Test Designer IDE. Once the user adds one of the DPL files in Data tab User can still add other DPL files if any with the help of API that is already available for Hash DPL and JS DPL.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/7lwJui1HwOA6Qygr-1e65b68de430.png)With the help of the above API called “Add Hash DPL” and “Add JS DPL”. User can add multiple DPL’s in the IDE.

Below is the screenshot for the successful execution of the same

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/uy9uNj6P5ZeGSdFW-250402dee2ab.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to handle pop-ups in a website using designer?

The user will not be knowing when exactly the window might be popped up and has to handle the popup with an if condition so that, if a particular message or a link or an image is present in the popup and the user recognizes that particular element and has to take necessary decisions. Here is an example for the mentioned situation and its implementation in Appvance Designer.

Consider user navigates to [www.appvance.com](http://www.appvance.com). The user might get a pop up sometimes and sometimes not. Hence we have used an If condition with the Appvance Designer API (\_isVisible\_Heading("Sign up for email updates")) which returns the Boolean value based on the presence of the heading "Sign up for email updates". If the condition is true, then the further actions are performed on the popup and if the condition is false, the span of If condition is skipped for further continuation of the script.

Here is the script attached for the above mentioned example

<span>[Popup.ds](../../../Resources/Images/GeneralGraphics/Popup.ds)</span>

<div id="bkmrk-last-updated%3A-july-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">July 03, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to hold and free toast message

To hold toast message \_eval("hold\_toaster = setInterval(function() { $('.toast-message').mouseenter() })")

To free toast message \_eval("clearInterval(hold\_toaster);$('.toast-message').mouseleave()")

Note: “toast-message“ is a class name. If toast message is getting disappeared after click some element of toast message then no need to use a step to free toast message

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/l9TjhDeJCaCWD7Mo-d7a1bfaf6e49.PNG)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to parameterize files for the file upload feature?

Question:

How to parameterize files for the file upload feature? (Like we have a random set of files as test data for upload)

Attached is the Test designer script and associated files that can be used for testing which was created on a public-facing site.

This example has files (5 different files) that are followed by numbers like filename1, 2, and so on.

By making use of Math.floor, we can generate random numbers as needed and can be passed to grab the files on the run, this way every time it runs, it will generate a random number, and based on the generated number, it will pick up the file from the resources.

Below is an example screenshot for test designer steps.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/TCCTBiaKgkTIZ8Vc-5e3a5a444784.png)This file contains a sample script: [FileUpload.zip](../../../Resources/Scripts/FileUpload.zip)

<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to Read and Write multiple rows from the CSV file?

var Account = readCSVListHashMap("{ds}/Account.csv");  
var ini=0;  
var i=0;  
var $data = new Array();  
$data.push(\["Email", "Password","PhoneNumber","Date","Month","Year"\])  
while (ini&lt;Account.length){  
var Email=Account.get(ini).get("Email");  
var Password=Account.get(ini).get("Password");  
var PhoneNumber=Account.get(ini).get("PhoneNumber");  
var Date=Account.get(ini).get("Date");  
var Month=Account.get(ini).get("Month");  
var Year=Account.get(ini).get("Year");  
log(Email);

var file="{ds}/Result.csv";

$data.push(\[Email,Password,PhoneNumber,Date,Month,Year\])

var ini=ini+1;  
};  
writeCSV(file, $data);

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/IqD9oqu8oK0NjiNr-80963ebedec8.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to remove all extra spacing between words?

Text1.replace(/ {1,}/g," ")

The `g` at the end of the RegExp means: global, ie match and replace all occurrences.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/P2pIVE7c1Z75X75n-fb2b98361f0b.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to retrieve all the elements on a page

Please use the following line of code in test designer IDE that will log all the elements on a given page.

getTagsSmartTags() API will get all the elements of a web page.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/yZf1IpGyTsmX6rEz-5c209fdb7294.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to retrieve the only number from a string?

Suppose there is a pop-up like below which has a combination of text and Numbers and if we want to retrieve only Numbers

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/37Vl6TyTQQZrwln0-4a8abfd1470a.png)Then we can use the below code to fetch only Numbers

Store the content into a variable and apply to replace(/\[^0-9\]/g, "") to the string and it will fetch only Numbers present in the string

Code Snippet

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/2A27FJYuVkkC7Kzj-707078d81a01.png)Logs from DS3

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/mk20zD2tAxibziLH-9c5945c2b1fe.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to retrieve value between 2 characters?

var str="Cart saved as Quote No :14393430\*";

var mySubString = str.substring(str.lastIndexOf(":") + 1,str.lastIndexOf("\*"));

You can use the below code to retrieve the value between ":" and "\*"

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/BDBNyihWyQShWUbL-60fac5df3bd2.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to stop the Sahi logging feature in Appvance IQ.

While I am running sahi/designer based vusers in Appvance IQ, sahi logs are taking up lot of disk space (sometimes 100 GB in 3 to 4 days).  
 How can we disable the traffic logs that are written to this folder?  
 /AIQ/sahi/userdata/logs/traffic  
  
 <u>**Solution:**</u>  
 Kill all java process, Start sahi dashboard alone in the below given path.  
 Please try disabling the traffic logs by launching sahi dashboard(/AIQ/sahi/userdata/bin/start\_dashboard.bat).  
  
 Restart Appvance IQ.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/6VeK0OVZvKKmo88K-90efb041d7f9.png)

<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to trim a string value from a string?

For example: Need only " 14393430" from the string "Cart saved as Quote : 14393430" use the below function:

var quote = "Cart saved as Quote : 14393430"

var quotenum=quote.substring(quote.indexOf(':') + 1)

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/tlo62WWTkc4IvR2i-829e426753e8.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to use custom functions from JS file in Test Designer

1. We are calling the JS function from the DS script and it returns the values after evaluation
 
The JS function that we have created is shown below

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/VsgzdZafeZ0RjkPU-b2d15578a9c8.png)This function will calculate a 10% discount on a Price that is entered. The usage of function in TD script is shown below

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/JkhfWQs0WC8KPKta-40fab5636b65.png)2\. We can also make use of the Custom JS action in DS and then fetch the value using the locker

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/wDmjsG6bgaEnIwTN-08ddc2c4dee9.png) ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/iCCjRRJftNCxa0No-c20497d428ee.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to Validate whether the video is played back?

\_eval('document.getElementsByClassName("jw-video jw-reset")\[0\].currentTime')

Look for the Video tag in the DOM and use the class or id of it.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/Rt6Sb9OGcMJDZSpz-2431f46c8e6f.png) ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/eKUJDcGRW7tY3Sy1-d7d4a3ef2615.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Verify Checkbox Checked and Unchecked States

**Last reviewed:** September 28, 2026

Use this article when a Scenario Editor validation needs to confirm whether a checkbox is selected or cleared.

## What changed in this article

- Cleaned up the title punctuation and changed it into a direct validation task.
- Added guidance to validate checkbox state through the DOM/property value instead of relying only on visual appearance.
- Added caution for custom checkbox controls where aria-checked, checked, class names, or hidden inputs may differ.

## Validation workflow

1. Inspect whether the checkbox is native HTML or a custom UI control.
2. Validate the correct state attribute or property for checked/unchecked behavior.
3. Replay the step after toggling the checkbox both ways to confirm the assertion fails and passes correctly.

**Review note:** Added custom-control guidance because modern web apps often style checkboxes in ways that hide the real state.

---

Last updated: September 28, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# How to verify Sorting Functionality

You can use a JavaScript function to verify whether the values displayed in a table are sorted in ascending or descending order.

The following example retrieves the values from a table column, stores them in an array, and compares each value with the next value to determine the sorting order.

```javascript
function Sortingverify()
{
    var rowlength = _eval("ds$('tbody tr').length");

    log(rowlength);

    var i = 0;
    var values = [];

    while (i <= rowlength - 1)
    {
        var cellClassName = "slds-truncate uiOutputTextArea[" + i + "]";

        assertExists(span(cellClassName));

        values.push(getText(span(cellClassName)));

        i = i + 2;
    }

    log("Number of values: " + values.length);

    if (values.length > 0)
    {
        sortCheck(values);
    }
}

function sortCheck(arr)
{
    var ascending = true;
    var descending = true;

    for (var i = 0; i < arr.length - 1; i++)
    {
        log("Comparing: " + arr[i] + " and " + arr[i + 1]);

        if (arr[i] > arr[i + 1])
        {
            ascending = false;
        }

        if (arr[i] < arr[i + 1])
        {
            descending = false;
        }
    }

    if (arr.length == 1)
    {
        log("Only one row exists.");
    }
    else if (ascending && !descending)
    {
        log("Ascending order.");
    }
    else if (descending && !ascending)
    {
        log("Descending order.");
    }
    else if (ascending && descending)
    {
        log("All values are the same.");
    }
    else
    {
        log("Values are not sorted.");
    }
}
```

### How it works

1. The script determines the number of rows in the table.
2. It retrieves the values from the target column and stores them in an array.
3. Each value is compared with the following value.
4. The script determines whether the values are:
    - **Ascending** — each value is less than or equal to the next value.
    - **Descending** — each value is greater than or equal to the next value.
    - **All the same** — all values are identical.
    - **Not sorted** — the values do not follow a consistent order.

For example:

```text
Apple
Banana
Orange
```

returns:

```text
Ascending order.
```

While:

```text
Orange
Banana
Apple
```

returns:

```text
Descending order.
```

If the values are:

```text
Apple
Orange
Banana
```

the script reports:

```text
Values are not sorted.
```

> **Note:** The `<span class="editor-theme-code">i = i + 2</span>` increment is specific to the DOM structure used by the original example. If the target page uses a different HTML structure, the selector and increment may need to be adjusted accordingly.

---

Last updated: **August 17, 2026**

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>.

# How to verify the disabled button?

To verify the disabled button where XML syntax is like below:

&lt;button type="button" disabled&gt;Add Comment&lt;/button&gt;

Use the below code to verify disabled:

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/sv0i13TlUEGF7EtZ-a93070a99bca.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Include functionality in Appvance Designer

To reuse a function from one script in another, we include the relevant script using the **include** Action from Appvance Designer.

**Usage**: **include relative:-**&lt;filename&gt;

This will be helpful in shortening your designer scripts.

Call other scripts as functions. This will let users to include other designer script at any given step as shown in below screenshot.

In the example below, note:

- The prefix : **relative:-** just before the login.ds filename on the Value column.
- This script can be executed only in the Scenario Builder.
 
 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/0MPqogz5OM1WV4SN-c0ab0e23d2f4.png)

In the Scenario Builder it can be added as shown below

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/GbFlPrGdLn6hXOG1-8ed5b90cc730.png)

The other dependent designer scripts can be added in resources section.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/KtmUDWAlJWd0JSoH-e3eb3adf1818.png)

An Example Designer script is attached is this article as well for reference.

[activity.ds](../../../Resources/Images/GeneralGraphics/activity.ds)

[login.ds](../../../Resources/Images/GeneralGraphics/login.ds)

[logout.ds](../../../Resources/Images/GeneralGraphics/logout.ds)

<div id="bkmrk-last-updated%3A-july-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">July 03, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Latency in AssertExists.

<div id="bkmrk-we-need-to-do-load-t">We need to do load testing of our web page. I have a designer script that checks 30 components on the page using assetExists. Appvance is taking up to 1 second to perform each assert check so using it for load testing is not feasible. The assert check should take microseconds to complete.

Response:

In an assertexists, Appvance IQ waits until the page is settled to guarantee the element is present.  
This is so at any load the script is still valid.

 </div><div id="bkmrk-last-updated%3A-june-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 02, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Log Specific Errors During Scenario Execution

**Last reviewed:** September 29, 2026

Use this article when a Scenario Editor test needs to capture targeted errors for debugging or reporting.

## What changed in this article

- Changed the vague title into an execution logging task.
- Added guidance for capturing step context, input data, browser state, response details, and assertion messages.
- Added caution to avoid logging secrets, tokens, passwords, or customer-sensitive payloads.

## Validation workflow

1. Decide which error condition needs explicit logging and where it occurs in the scenario.
2. Log the minimum useful context: step name, data row, expected value, actual value, and relevant output.
3. Review execution output to confirm the log helps diagnose the failure without exposing sensitive data.

**Review note:** Added data-safety guidance so error logging is useful but not noisy or risky.

---

Last updated: September 29, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# Pagination - How to search items in a page with multiple paginations

If you want to search for a specificstring, "Testappvance15860" for example, and if is not found then it should click on the next page.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/z3a5h8PDGW6xmHVE-9fcf4cf12d40.png)

The code will search for the string in the page if the string is not found then it will click on the next pagination

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/TmUwk5zt2lqOfOSx-3e2c213c00fe.png)

The Js Code is given below

<div class="codeSnippet" id="bkmrk-copy-var-job%3Disvisib"><div class="codeSnippetBody">```
var Job=<span style="color:#795da3;">isVisible</span><span style="color:#000000;">(</span><span style="color:#795da3;">link</span><span style="color:#000000;">(</span>Jobname<span style="color:#000000;">))</span>;<br></br>var Pagination=<span style="color:#008080;">2</span>;<br></br><span style="color:#795da3;">log</span><span style="color:#000000;">(</span>Pagination<span style="color:#000000;">.</span><span style="color:#795da3;">toString</span><span style="color:#000000;">())</span>;<br></br><span style="color:#a71d5d;font-weight:bold;">while</span> <span style="color:#000000;">(</span>Job==<span style="color:#000000;font-weight:bold;">false</span><span style="color:#000000;">){</span><br></br><span style="color:#795da3;">click</span><span style="color:#000000;">(</span><span style="color:#795da3;">link</span><span style="color:#000000;">(</span>Pagination<span style="color:#000000;">.</span><span style="color:#795da3;">toString</span><span style="color:#000000;">()))</span>;<br></br>var Job=<span style="color:#795da3;">isVisible</span><span style="color:#000000;">(</span><span style="color:#795da3;">link</span><span style="color:#000000;">(</span>Jobname<span style="color:#000000;">))</span>;<br></br>var Pagination=Pagination<span style="color:#000000;">+</span><span style="color:#008080;">1</span>;<br></br><span style="color:#000000;">}</span><br></br><span style="color:#795da3;">click</span><span style="color:#000000;">(</span><span style="color:#795da3;">link</span><span style="color:#000000;">(</span>Jobname<span style="color:#000000;">))</span>;
```

 </div> </div><div id="bkmrk-last-updated%3A-june-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 01, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Self-Healing Questions for Scenario Editor

**Last reviewed:** September 30, 2026

Use this article as a focused FAQ for Scenario Editor self-healing behavior, review expectations, and locator maintenance.

## What changed in this article

- Replaced Test Designer terminology with Scenario Editor and changed the title into a self-healing FAQ.
- Added guidance that self-healing suggestions should be reviewed rather than accepted blindly.
- Clarified that self-healing helps locator drift but does not replace stable locator design, assertions, or functional maintenance.

## Validation workflow

1. Review the original locator, the suggested healed locator, and the page context before accepting a change.
2. Replay the scenario to confirm the healed locator selects the intended element consistently.
3. Update the scenario or locator strategy if repeated healing indicates unstable application markup.

**Review note:** This article now complements the self-healing support page without duplicating its accessor inventory.

---

Last updated: September 30, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# Regular Expression in Appvance Designer.

<div id="bkmrk-"> </div><div id="bkmrk-query%3A">Query: </div><div id="bkmrk--1"> </div><div id="bkmrk-we-need-a-generic-st">We need a generic statement for the below accessor.  
cell("AddImage/Attachment for Issue # 40")</div><div id="bkmrk-as-in-the-40-will-be">As in the 40 will be replaced by any random number.</div><div id="bkmrk--2"> </div><div id="bkmrk-solution%3A">Solution:</div><div id="bkmrk--3"> </div><div id="bkmrk-here-are-some-of-the"><div>Here are some of the reg ex that you can give a try.</div><div>cell("AddImage/Attachment for Issue #/")</div><div>cell("AddImage/Attachment for Issue/")</div><div>cell("AddImage/")</div><div>cell("AddImage/Attachment for Issue #/[0-9]/").</div> </div><div id="bkmrk-last-updated%3A-june-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 02, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Solutions to common Test Designer IDE Challenges

Most of the times click and record can solve your testing needs. But also it is not rare that due to the “scripting” oriented description of the use cases to implement, the tester is faced with the challenge to approach the automation from a scripting angle.

This document provides some examples of scenarios where a little coding like steps are needed to speed up some automation requirements implementation using IDE.

If you are facing AI automation challenges please take a look at [Useful smartags workbench custom actions and other js examples.  
  
**Solutions to Common Test Designer IDE Challenges**](https://docs.appvance.net/Content/AIQ/General_KB_Articles/Useful_smartags_workbench_custom_actions_and_other_js_examples.htm)

#### Numbers: convert parts of a string value to a floating number

<div id="bkmrk-%2F%2F-suppose-you-have-" style="border-width:1px;"><div>```
// Suppose you have a span with the value $19.99 but you need validate the number is greated than 15.
Store                |  $stringValue    |  getText(span("carttotal"))     // "$19.99"Store                |  $floatingValue  |  parseFloat($stringValue.substring(1))   // removes the $ then convertes "19.99" to a floating number 
Assert Greater Than  |  $floatingValue  |  15
```

 </div> </div>#### Numbers: convert a string value to an integer number

<div id="bkmrk-%2F%2F-when-needing-to-p" style="border-width:1px;"><div>```
// When needing to perform math operation so often you need to convert a number in string format to an actual integer 
Store   |   $integerValue   |   parseInt(span("item-quantity"))
```

 </div> </div>####    
Tables: getting the number of rows in a table using ds$

<div id="bkmrk-%2F%2F-assuming-the-tabl" style="border-width:1px;"><div>```
// Assuming the table has an id myTable you can get the number of rows in the IDE using: 
Store  |  $rowsQuantity  |  _eval("ds$('#myTable tbody > tr').length")
or
Store  |  $rowsQuantity  |  getLength("ds$('#myTable tbody > tr')")
```

 </div> </div>An alternate way is to use the getLength function:

<div id="bkmrk-%2F%2F-assuming-the-tabl-1" style="border-width:1px;"><div>```
// Assuming the table has an id myTable you can get the number of rows in the IDE using: 
Store  |  $rowsQuantity  |  getLength("#myTable tbody > tr")
```

 </div> </div>#### Tables: getting the column index with a given header using ds$

<div id="bkmrk-%2F%2F-you-can-use-the-j" style="border-width:1px;"><div>```
// You can use the jQuery index() function to find the column index of a table that contains certain text "MyHeader". REF: https://api.jquery.com/index/
Store  |  $columnIndex  |  _eval("ds$('thead th:contains(MyHeader)').index()")+1
```

 </div> </div>#### Tables: Iterate over a table to process all the cells values of a given column using ds$

<div id="bkmrk-%2F%2F-if-you-need-to-it" style="border-width:1px;"><div>```
// If you need to iterate over a table column to process the contents of a certain column you can use above functions to get the total number of 
// rows in the table and the column that has the appropiate heade and then:
Store   |  $rowIndex                  | 1
While   |  $rowIndex < $rowsQuantity
  Store |  $cellValue                 |  _eval("ds$('tbody tr:nth-child("+$rowIndex+") td:nth-child("+$columnIndex+")').text()")
  [ do something with $cellValue ]
  Store |  $rowIndex                  |  $rowIndex + 1
End While
```

 </div> </div>#### General: close browser window.

<div id="bkmrk-%2F%2F-if-the-applicatio" style="border-width:1px;"><div>```
// If the application does not provide a button to close the window, need to insert
// the link and click it with following lines. 
CustomJS  |  "ds$('body').append('<a id=\"aiq-close\" href=\"javascript:close_window();\">aiq-close</a>')"Click     |  link("aiq-close")
```

 </div> </div>#### General: get an attribute value of an element

<div id="bkmrk-store-%7C-%24url-%7C-getat" style="border-width:1px;"><div>```
Store     |   $url   |  getAttribute(link("id"),"href")
```

 </div> </div>#### General: confirm an element is disabled

<div id="bkmrk-set-findonlyenabled-" style="border-width:1px;"><div>```
Set FindOnlyEnabled  |  false      | 
Store                |  submitdis  |  getAttribute(button("cancellation-submit"),"disabled")
Set FindOnlyEnabled  |  true       | 
Assert Equal         |  submitdis  |  "disabled"
```

 </div> </div> ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/tIjvb0mqSgh0Ykgk-6c1cecbdaf8d.png)#### General: get a dynamic value and use it elsewhere

<div id="bkmrk-get-from-whiteboard-" style="border-width:1px;"><div>```
Get from Whiteboard |  $caseNum                 | "CaseNumber"Click               |  link("Case Search")      |
Set Value           |  textbox("form-control")  | $caseNum
Click               |  submit("Search")         |  
Store               |  caseName                 | getText(cell(1,_near(span(["caseNameLabel"]))))
Click               |  link($caseNum)           |
Select Window       |  caseName                 |
```

 </div> </div> ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/MGeNXmzEdM9yIzgB-04b598dd9b23.png)##    
Links to other common challenges:

- [How to automate the Scroll bar? ](/books/test-designer-20-test-designer-30/page/how-to-automate-the-scroll-bar)
- [Pagination - How to search items in a page with multiple paginations ](/books/test-designer-20-test-designer-30/page/pagination-how-to-search-items-in-a-page-with-multiple-paginations)
 
<div id="bkmrk-last-updated%3A-july-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">July 03, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Group Step Statistics at a Higher Summary Level

**Last reviewed:** September 28, 2026

Use this article when execution results need grouped step statistics for easier analysis and reporting.

## What changed in this article

- Rewrote the title for clarity and made the purpose about grouped result analysis.
- Added guidance on grouping related steps by business transaction, flow, or validation section.
- Added a warning that grouping should not hide critical step-level failures or timing outliers.

## Validation workflow

1. Identify which steps belong to the same business action or transaction.
2. Apply grouping/naming consistently before running the scenario.
3. Review both grouped statistics and individual step details after execution.

**Review note:** The page now balances summary-level reporting with the need to preserve detailed failure evidence.

---

Last updated: September 28, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# Test Designer 3: HTML5 and Web Application Compatibility

Test Designer 3 supports modern HTML5-based web applications and many of the technologies commonly used to build interactive web applications.

HTML5 introduced new HTML elements, attributes, APIs, and browser behaviors, while the broader modern web platform includes technologies such as JavaScript, CSS, browser APIs, and client-side frameworks.

For additional information about HTML and the web platform, see:

- [WHATWG HTML Standard](https://html.spec.whatwg.org/)
- [MDN HTML Documentation](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5)

## HTML5 Compatibility

Test Designer supports most commonly used HTML5 features. However, compatibility can depend on how an application implements its UI components and JavaScript event handling.

Modern web applications can trigger actions through multiple mechanisms. For example, an application may use standard browser events, JavaScript event handlers, CSS pseudo-classes, custom components, or framework-specific event processing.

As a result, an action that works with a standard HTML element may behave differently when the same functionality is implemented through a custom component or JavaScript framework.

### Click Actions

Test Designer provides multiple methods for interacting with clickable elements, including `<span class="editor-theme-code">click</span>` and `<span class="editor-theme-code">click2</span>`.

In most cases, the standard `<span class="editor-theme-code">click</span>` action is sufficient. However, some applications implement additional JavaScript behavior or custom event handling that may require an alternative click method.

For example, an application may perform additional processing through JavaScript or use CSS pseudo-classes and framework-specific event handlers.

For more information about CSS pseudo-classes, see the [MDN CSS pseudo-classes documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes).

If a standard click action does not produce the expected behavior, try the alternative click method or use an action specifically designed for the application's implementation.

### File Upload

HTML5 does not prescribe a single implementation pattern for file-upload interactions across all web applications.

Applications may implement file selection using standard HTML elements, JavaScript, custom components, or framework-specific controls.

To accommodate these implementations, Test Designer provides multiple `<span class="editor-theme-code">setFiles</span>` methods. The appropriate method depends on how the application's file-upload component is implemented.

If a file-upload action does not work as expected, verify the underlying HTML element and the application's JavaScript implementation, then select the appropriate `<span class="editor-theme-code">setFiles</span>` method.

## Authentication Support

Test Designer supports the following authentication mechanisms:

- Basic Authentication
- NTLM Authentication
- Cookie-Based Authentication
- Digest Authentication
- ADFS with Kerberos Authentication
- Active Directory Authentication
- ADFS with NTLM Authentication when ADFS Extended Protection token checking is disabled
- ADFS with Negotiate Authentication when ADFS Extended Protection token checking is enabled

### AIQ Authentication

Authentication to the AIQ application itself can be configured using:

- Internal AIQ credentials
- LDAP authentication, which requires additional configuration

These authentication mechanisms are separate from authentication used by the web applications being automated.

## Record and Playback Considerations

Test Designer uses browser instrumentation and injection mechanisms to provide recording and playback capabilities.

Certain application security mechanisms can interfere with these capabilities.

### Man-in-the-Middle Detection

Applications or security tools that detect man-in-the-middle (MITM) activity may prevent Test Designer from recording, injecting, or interacting with a page correctly.

If an application uses certificate pinning, traffic inspection, or other mechanisms designed to detect intercepted browser traffic, additional configuration may be required.

### Browser Certificate Validation

Test Designer may use certificates as part of its browser instrumentation and traffic interception mechanisms.

Depending on the browser and application configuration, certificate validation can prevent a page from loading correctly or cause the browser to display certificate warnings.

For example, browsers may reject certificates that do not match the certificate expected for a particular domain.

If a page displays an invalid-certificate error when accessed through Test Designer, verify the browser certificate configuration and the application's security policies.

## JavaScript Framework Support

Test Designer 3 has been tested with commonly used JavaScript frameworks and web technologies, including:

- React
- AngularJS
- Angular
- jQuery
- ExtJS
- Bootstrap

Support for a framework does not necessarily guarantee compatibility with every application built with that framework.

Framework implementations can vary significantly, and applications may use custom components, third-party libraries, proprietary event handling, or newer framework versions that behave differently from the versions originally tested.

## Compatibility Considerations

Although Test Designer is designed to support modern HTML5 applications and commonly used web frameworks, compatibility can depend on several factors, including:

- Browser version
- Framework version
- Application architecture
- Custom JavaScript event handling
- Custom web components
- Security and certificate policies
- Third-party browser extensions
- Application-specific DOM behavior
- Framework-specific event handling

New framework releases, major version changes, forks, and highly customized implementations may require additional validation.

When an application does not behave as expected, first determine whether the behavior is specific to the application's implementation or to the underlying framework.

## Support and Feature Requests

Appvance continuously evaluates compatibility with modern web technologies and commonly used frameworks.

If you encounter a web application that does not behave as expected in Test Designer, provide the relevant application details, the Test Designer action being used, and the observed behavior when submitting a support request.

Feature requests and compatibility issues can be submitted through the available Appvance support channels.

---

**Last updated: August 25, 2026**

If you have any feedback about this topic, please contact <documentation@appvance.ai>.

# Using setFile in Test Designer with Relative Paths

<span style="color:rgb(0,0,0);">setFile action in designer is used to set a file in the file input field.</span>   
<span style="color:rgb(0,0,0);">Form elements of type "file" cannot be populated using javascript on the browser.</span>   
<span style="color:rgb(0,0,0);">Appvance designer has a workaround for handling file uploads, </span><span style="color:rgb(0,0,0);">designer intercepts the request in the proxy, reads the file off the file system and inserts it into the multi-part request.</span>

<span style="color:rgb(0,0,0);">The file has to be present on that path on the machine running Appvance AIQ.</span>

By using relative paths, the files can be sent to all the test node machines running Appvance AIQ so the files need not be moved to all the testnode instances.

Below designer script example shows the same:

<u>Scenario: Image need to be uploaded to my web application and need to run performance test on several test nodes without moving the files manually to all the test node machines.</u>

Images or any folder was created in the same place as the designer script, in my case 'FileUpload.ds' script is located in /Appvance AIQ/MyScripts folder and a folder by name 'Images' was created inside MyScripts folder.

<u>Designer:</u>

- setFile in designer should have the path "Images/photo.JPG" as seen in the below screen shot.
 
 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/mB7uRqPBnN1BXnVw-9db0ccfa7afb.png)

<u>Scenario Builder:</u>

- Create the scenario by browsing the designer script created.
- Go to Resources and select the Images folder as seen below.   
    ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/6tnXQIA58toNpbit-7c0d15d6f42b.png)
- Save and play the scenario!
 
Note: In the locations panel, user can provide any location to run this particular scenario or can use the cloud files to initialise any cloud machine and run the scenario, all the resource files will be copied over to the test node machines!

<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Using while loop in Test Designer 2.0

Attached example designer script will show how to use while loop in designer script.

[whileLoop.ds](../../../Resources/Images/GeneralGraphics/whileLoop.ds)

<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Using writeCSVFile API in Sahi.

Below code example shows how to use writeCSVFile API.

<div id="bkmrk-_navigateto%28%22http%3A%2F%2F" style="border-width:1px;"><div>```
_navigateTo("http://localhost:8080/Appvance/login.html");
_setValue(_textbox("username"), "appvance");
_setValue(_password("password"), "appvance");
_click(_submit("Login"));
//user function
var htmlelement1 = "username";
var value1 = "appvance";
var htmlelement2 = "password";
var value2 = "appvance";
//capture elements and write to CSV
var array = [[htmlelement1,value1],[htmlelement2,value2]];
_writeCSVFile(array, "elements1.csv", true);
//another way of declaring array and writing to CSV
var $datatowrite1 = [];
$datatowrite1[0] = [htmlelement1,value1];
$datatowrite1[1] = [htmlelement2,value2];
_writeCSVFile($datatowrite1, "elements.csv", true);
_writeCSVFile($data, "userinfo.csv", true); // overwrites data into userinfo.csv
To get value of some element below step can be used. 
var value1 = "_getText(_div("/someclass/"))";
===============================================
writeFile
_writeFile("Value", "FilePath"); // appends second line in file
```

 </div> </div>
            ```

                    <br></br>                    <br></br>                
            
```
        

<div id="bkmrk-last-updated%3A-march-">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">March 09, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Working Around Asynchronous Popups

Asynchronous ads and popups are becoming more common on commerce sites. Many of the dialogs can be closed by simply re-forcing focus back to the main portion of the page.

Manually adding a focus step prior to each action in places where a modal popup may appear, ensures you can gracefully continue without error or interruption.

# Example

The following site always displays a modal, at an unpredicted time. The site however discontinues trying to display once the user leaves the main page. The focus action is used prior to the planned action to ensure the planned action occurs without error.

This can be accomplished in one of two ways:

## Approach 1: Using Two Separate Steps

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/ZbvxUTsqgQJTN1bG-1c3f73bbcdcf.png)

## Approach 2: Using eval()

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/Tt9LPAZdwHXuTMpx-81e7ca8c8103.png)

## Sample Designer Script

<span>[](../../../Resources/Images/GeneralGraphics/shopping_checkForModal.ds)</span>

<div id="bkmrk-last-updated%3A-july-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">July 03, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Which JavaScript version is supported?

GraalVM JavaScript implements JavaScript as prescribed in the ECMAScript (ECMA-262) specification. It is fully compatible with the [ECMAScript 2021 specification](https://262.ecma-international.org/12.0/) (sometimes referred to as the 12th edition or “ES12”).

<div id="bkmrk-last-updated%3A-march-">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">March 09, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Browsers Not Listed When Clicking Record

## Issue

When you click **Record** in Test Designer, the expected browsers are not listed.

## Solution

### 1. Verify the browser paths

Make sure the browser executable paths configured in Test Designer are correct.

1. Open the `<span class="editor-theme-code">config</span>` folder in your local Test Designer installation:  
    `<span class="editor-theme-code">TestDesigner/NetworkProxy/config</span>`
2. Locate and open the `<span class="editor-theme-code">global.json</span>` file.
3. Find the browser and platform that are experiencing the issue.
4. Verify that the configured browser executable path matches the actual location of the browser executable on your system.
5. If the path is incorrect, update it to the correct browser installation path.

### 2. Restart Test Designer as Administrator

After verifying or updating the browser paths:

1. Close Test Designer.
2. Restart Test Designer using **Run as administrator**.
3. Click **Record** and verify that the expected browsers are now listed.

---

**Last updated:** August 19, 2026

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>.

1. Make sure the browser paths are correct. Open the /TestDesinger/NetworkProxy/config folder inside the Test Designer local installation and find the global.json. Scroll down and find the browser and platform that is giving problems. Verify that the listed paths for the browser executables are matching the browser program location in your system.
2. Restart Test Designer as Admin.

# Handle Browser Location Permission Prompts

# Handle Browser Location Permission Prompts

Browser permission prompts can interrupt Scenario Editor executions. Configure location permission behavior intentionally before the run instead of treating the prompt as an ordinary application dialog.

## Recommended approach

- Confirm whether the test requires real, mocked, or blocked location behavior.
- Use approved browser/profile configuration for the execution environment.
- Document the expected permission state with the scenario or environment notes.
- Do not grant browser permissions in production or shared environments without approval.

## Troubleshooting

1. Check whether the prompt is from the browser, the operating system, or the application.
2. Confirm the Test Node browser profile matches the intended permission state.
3. Review output and screenshots when a prompt blocks execution.
4. Prefer environment configuration over fragile click automation on browser prompts.

**Last updated:** September 9, 2026

# How to get the downloaded files in test designer?

The solution to this is using a function known as getDownloadedFiles(). This particular function is used to get the downloaded files. It can be passed through a variable. This function can be used as shown below:

var \[\] filedownloadedList = getDownloadedFiles(),

To get the file path from the downloaded list, use as below:

var filepath = fileDownloadedList.getJSONObject(0).getString("path")

where “fileDownloadedList” is a variable that has been used to store the downloaded file. This function is fetching the path of the downloaded file and stores it in a variable.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/rV8pErkkwpBlOzmO-aecb597b9bb4.png)<div id="bkmrk-last-updated%3A-june-2">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 26, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Self-Healing Support in Scenario Editor

Self-Healing Support in Scenario Editor

Self-healing can help Scenario Editor recover when a locator changes between runs. AIQ evaluates the recorded locator and available execution evidence to recommend an alternative when supported.

Use self-healing as a review aid, not as a substitute for maintaining reliable locators. Validate any proposed change in Scenario Editor before accepting it.

Supported actions and locator behavior can vary by AIQ release and browser technology. Consult the release-specific Scenario Editor documentation for the authoritative supported-accessor list.

Last updated: September 14, 2026

If you have any feedback on this topic, please contact us at documentation@appvance.ai

# Authentication Mechanisms in AIQ Tests

## Recommended guidance

Design authentication in AIQ tests so credentials, sessions, tokens, and test accounts are controlled, repeatable, and safe to use. Authentication steps should reflect the application under test and should not expose passwords or tokens in documentation, logs, screenshots, or scenario code.

## Common approaches

- UI login through Scenario Editor when the login flow is part of the test objective.
- Service Suite authentication for API tokens, OAuth flows, or setup calls.
- Pre-created test accounts with known permissions and reset procedures.
- Session setup or teardown steps that keep each run independent.

## Best practices

1. Use dedicated test accounts instead of personal or production accounts.
2. Store secrets in approved secure locations, not in visible steps or shared notes.
3. Validate multi-factor, SSO, captcha, or conditional-access requirements before automation.
4. Clear sessions when tests must start from a known state.
5. Document account role, environment, and cleanup expectations without revealing credentials.

*Last updated: October 6, 2026*

# Handle Validation Failures and Continue Scenario Execution

**Last reviewed:** September 30, 2026

Use this article when a Scenario Editor test should record a validation failure, continue safely, and leave clear evidence for review.

## What changed in this article

- Rewrote the question-style title into a clear Scenario Editor failure-handling task.
- Added guidance on soft validation versus hard stop decisions, cleanup actions, screenshots/logs, and result evidence.
- Clarified that continuing after a failure should be intentional and should not hide defects or corrupt downstream steps.

## Validation workflow

1. Decide whether the validation failure is safe to continue past or should stop the scenario immediately.
2. Capture evidence such as message text, screenshot, output log entry, or response payload before continuing.
3. Add cleanup or guard steps so later actions do not depend on a failed state.

**Review note:** This page now explains controlled continuation instead of simply bypassing failures.

---

Last updated: September 30, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# How can use a wild card when part of the identifier is always changing?

## Question

How can I use a wild card when part of the identifier is always changing?

How can I find an object, if part of the name is always changing?

## Resolution

A quick way to work with accessors, or objects where a portion of the name or attribute is dynamic, is to use the **Fuzzy Logic** syntax. By simply enclosing the string in quotes with **\[ \]**, AIQ will treat that portion as a contains search, and not require a complete match.

<div id="bkmrk-read-more-about-fuzz"><div>Read more about Fuzzy Logic in our documentation

 </div> </div>## Example 1

Given an object recorded as **span("person testuser")**  
Where **testuser** matches the name of the logged in user  
The Fuzzy Logic syntax would be **span(\["person"\])**

## Example 2

Given a link generated as **link("http://test.someurl.com/abc123")**  
Where **abc123** matches the a unique resource ID  
The Fuzzy Logic syntax would be **link(\["**<a>**http://test.someurl.com/"\])**</a>

<div id="bkmrk-need-more-complex-pa"><div>Need more complex pattern matching? Learn how to use Regular Expressions here

 </div> </div><div id="bkmrk-last-updated%3A-june-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 02, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# SmartTags: Using a custom getName Method

## Problem

As a user, I want to customize how AIQ finds and interacts with a specific element type in my application

## Resolution

Teach AIQ how to best identify and interact with your specific element type using SmartTag Rules and Actions.

## Related Topics

<div id="bkmrk-knowledge-base-artic"><div>Knowledge Base Articles

- [Understanding your Application with SmartTags ](https://docs.appvance.net/Content/AIQ/TestDesigner/TestDesigner2_3_KB/Understanding_your_Application___with_SmartTags__.htm)
- [Useful smartags workbench custom actions and other js examples ](https://docs.appvance.net/Content/AIQ/General_KB_Articles/Useful_smartags_workbench_custom_actions_and_other_js_examples.htm)
 
Documentation

- [Test Designer API Reference ](https://docs.appvance.net/Content/AIQ/TechRef/TestDesignerAPIRef/API_References_New/API%20Reference.htm)
 
 </div> </div>## Using a custom getName Method

### getBestName (option a)

This Action contains a prioritized list of attributes listed within the arr array variable. The first match is returned, or UNKNOWN is returned if no valid attribute value is found.

<div id="bkmrk-var-theelement-%3D-ds%24" style="border-width:1px;"><div>```
var theElement = ds$(element);
// attributes to try and in a given order
let arr = ["name", "placeholder"];
for (let i = 0; i < arr.length; i++) {
	try {
    var accessorValue = theElement.attr(arr[i]);
    if (typeof accessorValue !== 'undefined') {
      accessorValue = accessorValue.trim().replace(/(\r\n|\n|\r|\t)/g,"");
      break;
    }
  } catch(e) {
   // maybe the element doesn't contain the attribute
  }
}
if (typeof name === 'undefined') {
     accessorValue = "UNKNOWN";
}
return accessorValue;
```

 </div> </div>### getBestName (option b)

This Action contains a prioritized list of attributes, which returns the first attribute containing a valid value as the method for locating the object.

<div id="bkmrk-var-htmlelement-%3D-ds" style="border-width:1px;"><div>```
var htmlElement = ds$(element);
var name = htmlElement.attr('id');
if (typeof name === 'undefined') {
  name = "";
}
if (name === "") {
  name = htmlElement.attr("text");
}
if (typeof name === 'undefined') {
  name = "";
}
if (name === "") {
  name = htmlElement.attr("name");
}
if (typeof name === 'undefined') {
  name = "";
}
if (name === "") {
 name = "UNDEFINED"; // if nothing works, clearly denote as UNDEFINED
}
return name.replace(/(\r\n|\n|\r|\t)/g, "").trim();
```

 </div> </div>#### How can I use this?

Create a SmartTag to use the getBestName action: When combined with a SmartTag, this example overrides the default getName method using an Action for input type fields, but only those matching the Rule, which specifies a specific class. The Action defines a specific approach to locating and naming the Input object separate from the default Accessor Preferences.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/KoalXvG8WjQYwSYI-4f9965609a37.png)

<div id="bkmrk-last-updated%3A-july-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">July 03, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Maximizing the number of concurrent browsers

For performance testing, you can increase the number of concurrent Chrome browsers that can run on an AIQ Test Node by optimizing the node's compute and storage resources.

The maximum number of concurrent browsers depends on the application under test, the complexity of the test, browser activity, available CPU and memory, and storage performance.

As a general starting point, an AWS EC2 node using standard EBS storage may support approximately **20 to 30 concurrent Chrome browsers**. Higher concurrency can be achieved by using EC2 instance types that provide local NVMe SSD instance storage and by configuring AIQ to use that storage.

> **Important:** These numbers are guidelines, not fixed limits. The appropriate browser count must be determined through performance testing with the application under test.

## Using NVMe SSD Instance Storage

Storage I/O can become a bottleneck when running a large number of concurrent browsers. Browser processes generate significant disk activity, including cache and temporary-file operations.

AWS EC2 instance types such as the **m6id** family include local NVMe SSD instance storage. For example, current AWS specifications list:

- `<span class="editor-theme-code">m6id.2xlarge</span>`: 8 vCPUs, 32 GiB memory, 474 GB NVMe SSD
- `<span class="editor-theme-code">m6id.4xlarge</span>`: 16 vCPUs, 64 GiB memory, 950 GB NVMe SSD

These NVMe SSD volumes provide substantially higher I/O performance than typical baseline EBS configurations.

### Important considerations

NVMe instance storage is **ephemeral**. Data stored on an instance store volume persists only for the lifetime of the associated EC2 instance. It should therefore be treated as temporary working storage rather than permanent storage.

AIQ files, configuration files, or other data that must survive an instance stop or termination should remain on persistent storage.

Because the NVMe storage is not persistent, the node must prepare the storage and copy the required AIQ files to it each time the instance is initialized.

## Configuring AIQ to Use NVMe Storage

The recommended setup uses an initialization script, such as `<span class="editor-theme-code">nvme_setup.sh</span>`, to prepare the performance node.

The script should:

1. Detect and mount the available NVMe instance-store device.
2. Copy the GraalVM installation to the NVMe storage.
3. Copy the `<span class="editor-theme-code">aiq_distribution</span>` directory to the NVMe storage.
4. Configure Chrome to use a local cache directory on the NVMe storage.
5. Start AIQ from the NVMe storage.

The Chrome configuration can be added to:

`<span class="editor-theme-code">aiq_distribution/NetworkProxy/config/global.json</span>`

Add the following configuration:

```json
{
  "name": "experimentalDS3",
  "value": "--disk-cache-dir=cache||--disk-cache-size=1"
}
```

This configuration redirects the Chrome disk cache to the local storage used by the AIQ node.

## Setting Up an AWS EC2 Performance Node

### 1. Prepare the NVMe setup script

Add the `<span class="editor-theme-code">nvme_setup.sh</span>` script to the AIQ distribution on the EC2 instance.

The script should detect the available NVMe instance-store volume, mount it, and copy the required AIQ and GraalVM directories to the local storage.

The original script assumes that AIQ is installed in:

```text
/opt/aiq/aiq_distribution
```

If AIQ is installed in another location, update the script accordingly.

> **Note:** The exact NVMe device name can vary between EC2 instance types and operating systems. The setup script should detect the device rather than assuming a fixed device name.

### 2. Configure Chrome disk caching

Modify:

```text
aiq_distribution/NetworkProxy/config/global.json
```

Add:

```json
{
  "name": "experimentalDS3",
  "value": "--disk-cache-dir=cache||--disk-cache-size=1"
}
```

The cache directory should reside on the NVMe-backed AIQ installation.

### 3. Start AIQ using systemd

For Linux performance nodes, start AIQ through a `<span class="editor-theme-code">systemd</span>` service rather than `<span class="editor-theme-code">/etc/rc.local</span>`.

Using `<span class="editor-theme-code">systemd</span>` also allows you to increase operating-system resource limits. This is particularly important when running many concurrent browsers because the default per-process file descriptor limit may be too low.

Create:

```text
/etc/systemd/system/appvance.service
```

Use the following configuration and adjust the paths and Java version for the environment:

```ini
[Unit]
Description=Start Appvance IQ services
After=syslog.target

[Service]
Environment=PATH=/opt/graalvm-ce-java11-21.3.3.1/bin:/sbin:/bin:/usr/sbin:/usr/bin
Environment=JAVA_HOME=/opt/graalvm-ce-java11-21.3.3.1
User=ec2-user
Type=simple

LimitNOFILE=10000000
LimitNPROC=20000

ExecStart=/bin/bash /opt/aiq/aiq_distribution/TestNode/nvme_setup.sh
WorkingDirectory=/opt/aiq/aiq_distribution/TestNode

TimeoutStartSec=0

[Install]
WantedBy=multi-user.target
```

> **Note:** Verify the Java/GraalVM version and installation path before using this configuration. The paths above are examples from the original configuration and may not match the AIQ version installed on your node.

After creating the service, run:

```bash
sudo systemctl daemon-reload
sudo systemctl enable appvance
sudo systemctl start appvance
```

To verify the service:

```bash
sudo systemctl status appvance
```

The original article contains a typo (`<span class="editor-theme-code">systemclt enable</span>`). The correct command is:

```bash
systemctl enable appvance
```

## Resource Limits

When increasing browser concurrency, make sure the operating system can support the required number of processes and open files.

The example service uses:

```ini
LimitNOFILE=10000000
LimitNPROC=20000
```

These values are intentionally high and should be validated against the requirements of the specific environment. Increasing limits does not by itself guarantee higher browser concurrency; CPU, memory, storage I/O, network capacity, and the application under test can all become bottlenecks.

## Example Concurrency Results

The original performance testing produced the following results:

<table id="bkmrk-ec2-instanceconcurre"><colgroup><col></col><col></col></colgroup><tbody><tr><th>EC2 Instance

</th><th>Concurrent Chrome Browsers

</th></tr><tr><td>`<span class="editor-theme-code">m6id.2xlarge</span>`

</td><td>40

</td></tr><tr><td>`<span class="editor-theme-code">m6id.4xlarge</span>`

</td><td>80

</td></tr></tbody></table>

These results were obtained with a Test Designer test case and should be treated as **example performance results rather than guaranteed capacity**.

Actual concurrency can vary depending on:

- Application complexity
- Number and type of requests generated by each browser
- JavaScript execution
- Browser memory consumption
- CPU utilization
- Network traffic
- Test data
- AIQ configuration
- Chrome version
- Operating-system configuration
- Storage performance

For this reason, perform a capacity test before selecting the final number of concurrent browsers for a performance environment.

## Amazon Linux Version

The original version of this article specifically targeted **Amazon Linux 2**.

**Amazon Linux 2 reached end of life on June 30, 2026.** AWS recommends migrating to **Amazon Linux 2023**.

Therefore, new performance nodes should use an AWS-supported operating system and the corresponding AIQ installation and startup configuration.

If an existing environment still uses Amazon Linux 2, treat the configuration in this article as a legacy setup and plan migration to Amazon Linux 2023.

## EBS Storage Considerations

EBS performance depends on the volume type and its provisioned performance.

For example, Amazon EBS `<span class="editor-theme-code">gp3</span>` volumes provide a baseline of **3,000 IOPS and 125 MiB/s throughput**, with additional IOPS and throughput available through provisioning.

Therefore, the storage bottleneck should not be described simply as a limitation of a "60 GB EBS volume." When investigating concurrency limitations, monitor the actual EBS IOPS, throughput, latency, and utilization of the node.

For workloads that generate substantial browser disk activity, local NVMe instance storage can be an effective way to reduce EBS-related storage contention.

## Troubleshooting and Capacity Testing

If increasing the number of browsers causes execution failures or significantly longer response times, monitor the following resources during the test:

1. CPU utilization
2. Memory utilization
3. EBS IOPS and throughput
4. NVMe utilization
5. Disk latency
6. Network utilization
7. Number of open files
8. Number of running processes
9. Chrome memory consumption
10. AIQ/Test Node logs

Increase concurrency gradually rather than immediately configuring the maximum expected browser count.

For example:

```text
20 browsers → 40 browsers → 60 browsers → 80 browsers
```

At each level, verify that the node remains stable and that response times and error rates remain within the requirements of the performance test.

---

**Last updated: September 2, 2026**

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>.

# Understand Step Duration Calculations in Scenario Editor

**Last reviewed:** September 29, 2026

Use this article to choose and interpret AIQ step-duration metrics such as DOM Complete, Server Response Complete, Full Page Loaded, Script Time, Ajax Time, and Next Step Ready.

## What changed in this article

- Replaced Test Designer/Web Designer wording with Scenario Editor terminology while keeping browser PerformanceNavigationTiming context.
- Clarified which timings come from the browser and which are calculated by AIQ, including the SPA behavior where browser timings may return 0.
- Added guidance that Script Time is often closer to perceived user duration, while Ajax Time is mostly retained for backward compatibility.

## Validation workflow

1. Select the timing option that matches the question being answered: browser timing, user-perceived step time, or SPA readiness.
2. Compare AIQ output with browser performance timing only for browser-provided metrics.
3. Document the selected timing option when sharing reports so reviewers interpret duration values correctly.

**Review note:** This update keeps the technical timing distinctions but removes older Designer/Web Designer naming and fixes readability around asynchronous behavior.

---

Last updated: September 29, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# Troubleshoot Iteration Summary Error Messages

**Last reviewed:** September 28, 2026

Use this article when an AIQ execution shows an iteration-summary error and the team needs to identify whether it came from data, playback, or reporting.

## What changed in this article

- Changed the article from a vague error-message title into a troubleshooting workflow.
- Added checks for DPL row availability, failed assertions, step-level output, report generation timing, and execution logs.
- Clarified that the iteration summary is an investigation entry point, not the only source of failure evidence.

## Validation workflow

1. Open the failed execution and compare the iteration summary with the step output.
2. Check whether the failing iteration maps to a specific DPL row or input value.
3. Review report/output logs before changing the scenario logic.

**Review note:** This now helps triage data-driven iteration failures instead of just naming the error.

---

Last updated: September 28, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# Capture and Validate Tooltips in Scenario Editor

**Last reviewed:** September 29, 2026

Use this article when a Scenario Editor test needs to trigger, capture, and validate tooltip text.

## What changed in this article

- Replaced Test Designer wording with Scenario Editor terminology.
- Added guidance to distinguish native title tooltips, ARIA/toolkit tooltips, and custom DOM tooltip components.
- Added timing and hover/focus validation checks so flaky tooltip assertions are easier to diagnose.

## Validation workflow

1. Identify whether the tooltip appears on hover, focus, or click and whether it is native or custom HTML.
2. Capture the tooltip text or attribute after the UI has displayed it.
3. Replay the step with timing checks and confirm the assertion fails when expected text changes.

**Review note:** Modernized the tooltip workflow and added custom component handling for current web apps.

---

Last updated: September 29, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# How to access two different application at the same time in a single script.

1. Navigate to any URL Eg: [https://demosite.appvance.com/](https://demosite.appvance.com/)
2. Perform some steps
3. Add new action called “Open Tab” and add a URL “[https://www.apple.com/](https://www.apple.com/) “
4. Store any value for any element on the page
5. Use Select Window action and go to 1st URL i.e [https://demosite.appvance.com/](https://demosite.appvance.com/)
6. Click on the search text field icon on the Appvance Demo site app
7. Use the Variable on the text field which was stored in the Apple website
8. You will be able to search with the created variable in 2nd application
9. User can use Select Window to move Back and Forth in both the applications.
 
 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/R3o9eovNWKxGUCuK-a2809a9d7a11.png)

<div id="bkmrk-last-updated%3A-june-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 01, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to find the X Y Coordinates

function alertMousePos(event) {  
 alert(  
 "X: " + event.clientX +  
 " - Y: " + event.clientY);  
}  
document.addEventListener("click", alertMousePos);

1. Just copy and paste the above code into the browser’s console and press the ‘Enter’ key.
2. Now click on wherever on the page- An alert will get displayed with x and y values -- It gets the x, and y coordinates of the click of the mouse pointer. Note - Any console (Normal browser or test designer browser) should work, but advisable to use the Test Designer browser in maximized state.
 
<div id="bkmrk-last-updated%3A-june-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 02, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# How to perform Mouse Over action using Toggle Style API From Test Designer

We have the below two APIs to perform mouse over from Test Designer

- Mouse Over
- Toggle Style
 
**MouseOver using Toggle Style Action**

Add the below step with the accessor which needs to be Mouse over

1. Select API as **Toggle Style** from the scripts step
2. Add the Accessor which needs to mouse over
3. Add **“hover“** in the value column
 
**Example Screenshot**

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/UIGkL2wFfvqOxkEO-ec6cdc47b5ef.png)

<div id="bkmrk-last-updated%3A-june-0">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">June 01, 2023</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# Verify Whether a User Exists in the Database

**Last reviewed:** September 29, 2026

Use this article when a Scenario Editor or Service Suite validation needs to confirm whether a specific user record exists in a database.

## What changed in this article

- Rewrote the question-style title into a database validation task.
- Added checks for parameterized queries, database connection settings, permissions, expected row count, and negative-case validation.
- Added a safety note to avoid logging passwords, tokens, email addresses, or sensitive user attributes from query results.

## Validation workflow

1. Identify the unique user key to validate, such as username, user ID, or test email.
2. Run a parameterized query through the approved AIQ database/service workflow.
3. Assert the expected row count or field value, then run a negative case to confirm the validation can fail correctly.

**Review note:** The article now focuses on safe database validation instead of a broad yes/no question.

---

Last updated: September 29, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# Validate Color of an Object

This is an example of a script that detects the color of a specific object and then uses conditional statements to compare it to a reference color.

### Web Designer Script

This is the AIQ designer test script to accomplish this validation. The script uses the `GetCssValue` function.

See [getCssValue for more information about the function.](https://docs.appvance.net/Content/AIQ/TechRef/TestDesignerAPIRef/API_References_New/General/APIRef_GetCSSValue.htm)

The example script uses the Appvance demo site. The object that the script is the comparing color of is a footer which contains the price of an item.

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/11gopdllupNFwcLT-2d396046a175.png)

Download a copy of this script from: [ColorCheckExample.ds](../../Resources/Scripts/ColorCheckExample.ds)

### JS Code

For reference, this is the corresponding java script code for the ColorCheckExample test script.

<div class="codeSnippet" id="bkmrk-copy-%2F%2A%2A%C2%A0%2A-%40aiq.webd"><div class="codeSnippetBody">```
/**<br></br> * @aiq.webdesigner<br></br> * This script requires AIQ Web Designer<br></br>*/<br></br>setShadowDOM(true);<br></br>navigateTo("https://demosite.appvance.net/");<br></br>click(fallback(`div(2, _in(div("product_1"))).xy(0.11, 0.58 )`,<br></br>   `div(2, _in(div({'id':'product_1'}))).xy(0.11, 0.58 )`,<br></br>   `div("panel-footer text-center").xy(0.11, 0.58 )`,<br></br>   `div("$15.99").xy(0.11, 0.58 )`,<br></br>   `byXPath("//div[@id='product_1']/div/div[2]").xy(0.11, 0.58 )`,<br></br>   `byXPath('//*[@class="panel-footer text-center"]').xy(0.11, 0.58 )`,<br></br>   `byXPath('/html/body/div[2]/div/div/div/div[2]/div/div/div[2]').xy(0.11, 0.58 )`,<br></br>   `byXPath("id('product_1')/div[@class='panel panel-default']/div[@class='panel-footer text-center']").xy(0.11, 0.58 )`,<br></br>   `byJQuery('div[class="row"] > div[class="col-md-3 col-sm-6 col-xs-6 product-list-item"] > div[class="panel panel-default"] > div[class="panel-footer text-center"]').xy(0.11, 0.58 )`,<br></br>   `byJQuery('#product_1 > .panel.panel-default > .panel-footer.text-center').xy(0.11, 0.58 )`));<br></br>var FooterColor=getCssValue(byXPath("//div[@class='panel-footer text-center']//span[@class='price selling lead']"), "color");<br></br>log(FooterColor);<br></br>if (FooterColor == "rgb(51, 51, 50)"){<br></br>   alert("The color correspond");<br></br>}<br></br>else {<br></br>   alert(“Those are not the droids you are looking for");<br></br>}<br></br>
```

 </div> </div><div id="bkmrk-last-updated%3A-februa">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">February 25, 2025</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>

# MFA Authentication Automation Guidance

**Last reviewed:** September 30, 2026

Use this article to decide how AIQ tests should handle applications protected by multi-factor authentication.

## What changed in this article

- Reframed MFA automation around approved test-environment patterns instead of bypassing or weakening MFA.
- Added guidance for test accounts, pre-authorized sessions, API token flows, IdP test policies, and audit requirements.
- Added a warning that real user OTPs, personal devices, and production MFA prompts should not be automated in shared tests.

## Validation workflow

1. Confirm the approved MFA strategy with the application owner or identity team before building the scenario.
2. Use a controlled test account, test IdP policy, or token-based flow that is explicitly approved for automation.
3. Record evidence of the authentication path without logging OTPs, recovery codes, personal phone numbers, or secrets.

**Review note:** This page now treats MFA as a security control to coordinate around, not a popup to defeat.

---

Last updated: September 30, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# Create Multiple Orders and Write Order IDs to a Repository CSV

**Last reviewed:** September 30, 2026

Use this article when a Scenario Editor test needs to create multiple records and persist generated order IDs to a repository CSV for later validation or reuse.

## What changed in this article

- Shortened and corrected the long title while preserving the order-ID-to-CSV use case.
- Replaced Test Designer framing with Scenario Editor and repository CSV terminology.
- Added checks for CSV headers, append versus overwrite behavior, concurrency collisions, cleanup, and sensitive data masking.

## Validation workflow

1. Create the order records and capture each generated order ID from the response, UI, or service output.
2. Write only the required fields to the repository CSV with a clear header and deterministic file path.
3. Replay the consuming scenario and confirm it reads the expected rows without duplicate or stale IDs.

**Review note:** This page now focuses on the data handoff pattern and calls out concurrency risks when multiple runs write to the same CSV.

---

Last updated: September 30, 2026

If you have feedback on this topic, contact <documentation@appvance.ai>.

# Read and Write Data from a Downloaded XLSX File

Attaching the script along with the Screenshot to follow the steps

We need 3 different Service suite scripts

- A common JS script
- Filename JS: Where we are providing the Sheet name, Path of the repository where the file is being saved
- Write JS: Here as well, we need to define the repository name and file path after making the write action, We also need to add the controller URL and AIQ username  
    and Password
 
### Test Script

 ![](https://docs.appvance.net/uploads/images/gallery/2026-07/scaled-1680-/11B8cOUcXbP6ElHp-f7050ee28e24.png)Sample Script: [WriteExcel.ds](../../Resources/Scripts/WriteExcel/WriteExcel.ds)

- Testfile name: At step number 45, make sure to add the repository path and the repository name which the user cloned in the AIQ
- After clicking on download, add a step store in locker and provide the sheet name, which is there in the download file
- 
 
- In Ds script at step 55 and 61, make sure to give the exact header name for the targetted column header
 
### Write JS

Write JS: Here as well, we need to define the repository name and file path after making the write action, We also need to add the controller URL and AIQ username  
and Password

<div class="codeSnippet" id="bkmrk-copy-1-2-3-4-5-6-7-8"><div class="codeSnippetBody">```
<span class="codeSnippetLineNumbers" style="border-right:#AAA 2px solid;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</span>```
<span style="color:#333333;font-weight:bold;">function</span> <span style="color:#990000;font-weight:bold;">writeexcel</span>(row, col, value)<br></br>{<br></br><span style="color:#333333;font-weight:bold;">var</span> $excel= readExcel(filepathval);<br></br><span style="color:#333333;font-weight:bold;">var</span> $sheetname = locker.get(<span style="color:#dd1144;">"sheet"</span>);<br></br>log($sheetname);<br></br><span style="color:#999988;font-style:italic;">//var $sheetname="Sheet1";</span><br></br><span style="color:#333333;font-weight:bold;">var</span> $sheet = $excel.getWorkbook().getSheet($sheetname); <span style="color:#999988;font-style:italic;">// Get sheet as an object HSSFSheet</span><br></br>  $excel.getWorkbook().setActiveSheet($excel.getWorkbook().getSheetIndex($sheetname));<span style="color:#999988;font-style:italic;">//Change active sheet to the one specified</span><br></br>  <span style="color:#333333;font-weight:bold;">var</span> $headers = $sheet.getRow(<span style="color:#008080;">0</span>);<br></br>  <span style="color:#333333;font-weight:bold;">var</span> $lastExistingColumn = $headers.getLastCellNum(); <span style="color:#999988;font-style:italic;">// Get number of colum</span><br></br>  locker.put(<span style="color:#dd1144;">"columnlength"</span>,$lastExistingColumn);<br></br>        log($excel);<br></br>        $excel.setValueAt(row, col, value);<br></br>        writeExcel($excel,  filepathval);<br></br>}<br></br><span style="color:#333333;font-weight:bold;">var</span> filepathval=locker.get(<span style="color:#dd1144;">"filenameval"</span>);<br></br><span style="color:#333333;font-weight:bold;">var</span> rowval=locker.get(<span style="color:#dd1144;">"rownum"</span>);<br></br><span style="color:#333333;font-weight:bold;">var</span> colval=locker.get(<span style="color:#dd1144;">"colnum"</span>);<br></br><span style="color:#333333;font-weight:bold;">var</span> actualval=locker.get(<span style="color:#dd1144;">"excelval"</span>);<br></br><br></br>log(<span style="color:#dd1144;">"servicesuite "</span>+filepathval);<br></br>writeexcel(rowval,colval,actualval);<br></br><br></br><span style="color:#333333;font-weight:bold;">var</span> $boundary = <span style="color:#dd1144;">"--AIQ-DS-BOUNDARY"</span>;<br></br><span style="color:#333333;font-weight:bold;">var</span> $repositoryName = <span style="color:#dd1144;">"Appvance"</span>; <span style="color:#999988;font-style:italic;">// CHANGE FOR YOUR REPO NAME, THIS CONF MUST BE IN THE USER ACCOUNT USED TO LOGIN</span><br></br><span style="color:#333333;font-weight:bold;">var</span> $CONTROLLER = <span style="color:#dd1144;">"http://localhost:8080"</span>; <span style="color:#999988;font-style:italic;">// Controller URL</span><br></br><span style="color:#333333;font-weight:bold;">var</span> $username = <span style="color:#dd1144;">"appvance"</span>; <span style="color:#999988;font-style:italic;">// username used to login to aiq</span><br></br><span style="color:#333333;font-weight:bold;">var</span> $password = <span style="color:#dd1144;">"appvance"</span>; <span style="color:#999988;font-style:italic;">// password used to login to aiq</span><br></br><span style="color:#333333;font-weight:bold;">var</span> $uploadPath = <span style="color:#dd1144;">"Customer/VWR/ReadWriteXLS/"</span>; <span style="color:#999988;font-style:italic;">// CHANGE FOR folder in repo where the modified file should be uploaded</span><br></br>include(<span style="color:#dd1144;">"{ds}/commonFunctions.js"</span>);<br></br><br></br><span style="color:#333333;font-weight:bold;">if</span> (login($CONTROLLER)) {<br></br>    uploadFile(fileName, fileName);<br></br>    <span style="color:#333333;font-weight:bold;">var</span> $resp= get($CONTROLLER+<span style="color:#dd1144;">"/AppvanceServer/rest/admin/logout"</span>);<br></br>    log(<span style="color:#dd1144;">"logout: "</span>+$resp.getDataString());<br></br>};
```
```

 </div> </div>Write JS. At step 26 and 30, make sure to add the repository name and the repository path, respectively, which the user cloned in the AIQ

###  

### Filename JS

Filename JS:

<div class="codeSnippet" id="bkmrk-copy-1-2-3-4-5-6-7-8-1"><div class="codeSnippetBody">```
<span class="codeSnippetLineNumbers" style="border-right:#AAA 2px solid;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
</span>```
<span style="color:#333333;font-weight:bold;">function</span> <span style="color:#990000;font-weight:bold;">columnlen</span>(filepathvalcol)<br></br>{<br></br>  <span style="color:#999988;font-style:italic;">//var filepathvalcol=locker.get("filenameval");</span><br></br>  <span style="color:#333333;font-weight:bold;">var</span> $sheetname = locker.get(<span style="color:#dd1144;">"sheet"</span>);<br></br>  log($sheetname);<br></br>  log(<span style="color:#dd1144;">"reading excel from "</span>+filepathvalcol);<br></br>  <span style="color:#333333;font-weight:bold;">var</span> $excel= readExcel(filepathvalcol);<br></br>  <span style="color:#999988;font-style:italic;">//var $sheetname="Sheet1";</span><br></br>  <span style="color:#333333;font-weight:bold;">var</span> $sheet = $excel.getWorkbook().getSheet($sheetname); <span style="color:#999988;font-style:italic;">// Get sheet as an object HSSFSheet</span><br></br>  $excel.getWorkbook().setActiveSheet($excel.getWorkbook().getSheetIndex($sheetname));<span style="color:#999988;font-style:italic;">//Change active sheet to the one specified</span><br></br>  <span style="color:#333333;font-weight:bold;">var</span> $headers = $sheet.getRow(<span style="color:#008080;">0</span>);<br></br>  <br></br>  <span style="color:#333333;font-weight:bold;">var</span> $lastExistingColumn = $headers.getLastCellNum(); <span style="color:#999988;font-style:italic;">// Get number of colum</span><br></br>  locker.put(<span style="color:#dd1144;">"columnlength"</span>,$lastExistingColumn);<br></br>  <span style="color:#333333;font-weight:bold;">var</span> headersArray = []<br></br>  <span style="color:#333333;font-weight:bold;">for</span> (<span style="color:#333333;font-weight:bold;">var</span> col = <span style="color:#008080;">0</span>; col < $lastExistingColumn; col++) {<br></br>    <span style="color:#333333;font-weight:bold;">var</span> cell = $headers.getCell(col);<br></br>     <span style="color:#333333;font-weight:bold;">switch</span> (cell.getCellType().toString()) {<br></br>        <span style="color:#333333;font-weight:bold;">case</span> <span style="color:#dd1144;">"STRING"</span>:<br></br>           headersArray.push(cell.getStringCellValue());<br></br>           <span style="color:#333333;font-weight:bold;">break</span>;<br></br>        <span style="color:#333333;font-weight:bold;">case</span> <span style="color:#dd1144;">"NUMERIC"</span>:<br></br>           headersArray.push(cell.getNumericCellValue());<br></br>           <span style="color:#333333;font-weight:bold;">break</span>;<br></br>        <span style="color:#333333;font-weight:bold;">default</span>:<br></br>           headersArray.push(cell.toString());<br></br>           <span style="color:#333333;font-weight:bold;">break</span>;<br></br>     } <br></br>  }<br></br>  locker.put(<span style="color:#dd1144;">"headers"</span>, headersArray);<br></br>}<br></br><br></br><br></br><span style="color:#333333;font-weight:bold;">var</span> json = locker.get(<span style="color:#dd1144;">"fileDownloadedList"</span>);<br></br><br></br><span style="color:#999988;font-style:italic;">// [{"path":"C:\Users\Administrator\TestDesigner\NetworkProxy\execution\Chrome10383680D\EnrollmentSearch_2024022217255349.xls","name":"EnrollmentSearch_2024022217255349.xls","length":4702}]</span> <br></br><br></br><span style="color:#333333;font-weight:bold;">var</span> filePath = <span style="color:#dd1144;">""</span>+json.getJSONObject(<span style="color:#008080;">0</span>).getString(<span style="color:#dd1144;">"path"</span>);<br></br><span style="color:#333333;font-weight:bold;">var</span> fileName1 = <span style="color:#dd1144;">""</span>+json.getJSONObject(<span style="color:#008080;">0</span>).getString(<span style="color:#dd1144;">"name"</span>);<br></br><span style="color:#333333;font-weight:bold;">var</span> fileName = fileName1.replace(/\s+/g, <span style="color:#dd1144;">'_'</span>)<br></br>locker.put(<span style="color:#dd1144;">"repofilename"</span>,fileName);<br></br>locker.put(<span style="color:#dd1144;">"filenameval"</span>,fileName);<br></br>filePath = filePath.replace(/\\/g,<span style="color:#dd1144;">"/"</span>);<br></br><span style="color:#999988;font-style:italic;">// path to your repo</span><br></br><span style="color:#333333;font-weight:bold;">var</span> pathToYourRepo = <span style="color:#dd1144;">"REPOSITORY/Appvance/Customer/VWR/ReadWriteXLS/"</span> + fileName; <span style="color:#999988;font-style:italic;">// Give the path pointing to the folder that has the script</span><br></br>log(<span style="color:#dd1144;">"servicefilename val "</span>+pathToYourRepo);<br></br>locker.put(<span style="color:#dd1144;">"pathToYourRepoval"</span>,pathToYourRepo);<br></br>log(<span style="color:#dd1144;">"file saved at: "</span> + pathToYourRepo);<br></br><span style="color:#333333;font-weight:bold;">var</span> fileContentAsBytes = java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(filePath));<br></br><br></br>writeBytes(fileName, fileContentAsBytes);<br></br><br></br>log(<span style="color:#dd1144;">" | downloaded file size: "</span>+fileContentAsBytes.length);<br></br><br></br>columnlen(fileName);
```
```

 </div> </div>##  HEADING

<div class="codeSnippet" id="bkmrk-copy-1-2-3-4-5-6-7-8-2"><div class="codeSnippetBody">```
<span class="codeSnippetLineNumbers" style="border-right:#AAA 2px solid;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
</span>```
function uploadFile(fileName, filePath) {<br></br>        var data = createMultipartPayload(fileName, filePath);<br></br>    var call = createPost($CONTROLLER + "/AppvanceServer/rest/file/uploadFile?&commitMessage=Appvance+skip+commit&path=REPOSITORY/" + $repositoryName + "/" + $uploadPath + fileName, data, "multipart/form-data", " boundary=" + $boundary);<br></br>    var resp = process(call);<br></br>    log(resp.getDataString())<br></br>}<br></br><br></br><br></br>function getSessionCookie() {<br></br>    var $jsession = getCookieValue($CONTROLLER, "JSESSIONID");<br></br>    var cookie = "JSESSION=" + $jsession;<br></br>    locker.put("aiq-cookie", cookie);<br></br>    addGlobalHeader("cookie", "JSESSION=" + $jsession);<br></br>}<br></br><br></br>function login() {<br></br>    var $loginForm = formData();<br></br>    $loginForm.put("username", $username);<br></br>    $loginForm.put("password", $password);<br></br>    var $resp = get($CONTROLLER+"/AppvanceServer/rest/admin/isLogged");<br></br>    if ($resp.getDataString().indexOf("false")) {<br></br>        var $call = createPost($CONTROLLER + "/AppvanceServer/rest/admin/logginForServices", $loginForm);<br></br>        var $resp = process($call).getDataString();<br></br>        if ($resp.indexOf("true") != -1) {<br></br>            getSessionCookie();<br></br>            log("Login successful");<br></br>            return true;<br></br>        } else {<br></br>            log("Login was NOT successful: " + $resp)<br></br>            return false;<br></br>        }<br></br>    } else {<br></br>        getSessionCookie();<br></br>    }<br></br>    <br></br>}<br></br><br></br>function createMultipartPayload(filename, path) {<br></br>    var header = '--' + $boundary + '\n' +<br></br>        'Content-Disposition: form-data; name="file"; filename="' + filename + '"\r\n' +<br></br>        'Content-Type: application/octet-stream\r\n\r\n';<br></br>    var headerBytes = new Array(header.length);<br></br>    for (var i = 0; i < header.length; ++i) {<br></br>        headerBytes[i] = header.charCodeAt(i);<br></br>    }<br></br>    var $data = readBytes(path);<br></br>    var footer = '\r\n--' + $boundary + "--\r\n";<br></br>    var footerBytes = new Array(footer.length);<br></br>    for (var i = 0; i < footer.length; ++i) {<br></br>        footerBytes[i] = footer.charCodeAt(i);<br></br>    }<br></br>    return headerBytes.concat($data).concat(footerBytes);<br></br>}<br></br><br></br>function getLastDownloadedFile(json) {<br></br>    json.sort((a, b) => b.modifiedTime - a.modifiedTime);<br></br>    return json[0];<br></br>}
```
```

 </div> </div><div id="bkmrk-last-updated%3A-decemb">---

Last updated: <span class="mc-variable General.NewDateTimeVariable variable">December 20, 2024</span>

If you have any feedback on this topic, please contact us at <documentation@appvance.ai>

</div>