Skip to content

Using JavaScript in UI-licious Tests

UI-licious test scripts are executed in a JavaScript sandbox.

Unlike other low-code, keyword-driven frameworks that introduce a custom DSL, UI-licious intentionally runs tests as JavaScript. This design gives developers the flexibility to write custom logic using a familiar language, while still benefiting from the simplicity of the UI-licious API. As a result, you can use standard JavaScript syntax, create reusable functions, and write data-driven tests without being constrained by the framework.

WARNING

Because tests are executed in a sandbox, you cannot install external libraries or use the import or export keywords. UI-licious provides the TEST.run function for running logic from another file (see below).

Variables, loops, and conditionals in practice

JavaScript is commonly used in UI-licious tests to:

  • store and manipulate test data using variables
  • branch test flows using conditionals
  • iterate through datasets for data-driven testing

Here's an example:

js
// load products from csv
var products = TEST.loadDataFromCsv("data/products.csv", { headers: "row" })

// iterate products to search and add the product to the cart
products.forEach((p) => {

	I.fill("Search", p.name)
	I.pressEnter()

	if (I.see$(p.name)) {
		I.click("Add to cart")
	} else {
		TEST.log.fail("Product '" + p.name + "' is not found")
	}
})

Using functions to reuse logic

When a sequence of steps is used repeatedly, a common pattern is to extract it into a reusable function:

js
// this is a helper function to search for a product
// and then add it to cart if it exists
function searchAndAddToCartIfExists(productName){
	
	I.fill("Search", productName)
	I.pressEnter()

	if (I.see$(productName)) {
		I.click("Add to cart")
	}

}

products.forEach((p) => searchAndAddToCartIfExists(p.name))

This keeps tests readable and easy to maintain.

Reusing logic with TEST.run

Although the import and export keywords are not supported, UI-licious provides TEST.run() and TEST.runOnce() for executing other test files. This is commonly used for shared setup logic or reusable flows such as login.

js
// load utility functions
TEST.runOnce("helpers/date_utils")

// start of test case
TEST.run("flows/login")

I.see("Dashboard")

This allows larger test suites to be composed from smaller, focused scripts without relying on external libraries.

For a deeper look at structuring reusable flows and composing larger test suites, see the guide on Reusing and Composing Tests.