Skip to main content

Running Javascript

In some use cases, it is useful to be able to run a piece of js code in the browser from within a test. For instance, accessing window object to perform actions like window.focus(), retrieving viewport dimensions using window.innerHeight/window.innerWidth, running a plugin in form of js snippet at the beginning of a test to see how the site function with that plugin installed.

In some lesser used cases, you may want to run custom js code that take arguments from the test, do some process using the arguments and return some data to the test for validation. For example, setting a timeout to hide an element from page (whose reference was supplied from test) and return some data back to the test for validation. Doing these js tricks may not be required if your tests only purely validate actions that an end user can perform but still there may be some use cases depending on what you're trying to accomplish.

Script execution functions#

Following functions can be used for running js from a test:

executeScript(stringScript, ...args)
executeAsyncScript(stringScript, ...args)
  • The provided js script is injected into the page and executed as the body of an anonymous function. It's execution context will be the current browsing context.

  • The arguments passed to a function can be accessed in the script using arguments object. See below:

    button = findElement('Submit', by.text)executeScript('arguments[0].style.display = "none"', button)
  • executeScript runs the script synchronously on the page which means it will block page execution until completed. The script can have a return statement to return a value. Test resumes only once the script has completed execution.

  • executeAsyncScript run the script asynchronously on the page and doesn't block page execution. If you're accessing network or need to run script with a delay, use this function. Note that even though it runs the script asynchronously on page, the test will block until the execution has finished.

    Being asynchronous, the test can't know about the completion on it's own. It's your responsibility to invoke a provided callback to inform the completion. The callback is injected as the last argument to executeAsyncScript and is used to return a value as well. See below:

    noteId = 150data = executeAsyncScript(`  const callback = arguments[arguments.length - 1];  fetch('https://some-app.com/notes/' + arguments[0])    .then(data => callback(data))    .catch(error => callback(error));`, noteId)noteDescription = data.desc

We now know how to use the functions, access arguments and use callback. Let's understand what can be passed as arguments, how values returned from the script are resolved and few other things like adjusting timeout value.

Script function arguments#

  • You can supply any supported type in ZWL as arguments such as string, list or map. list and map are internally converted to be accessed as array and object respectively in js script.

  • To pass an element, just use the elementId returned by findElement functions. ZWL internally converts elementId to real element before passing to script. You may then access the element in script as if it was retrieved using one of the element retrieval method such as document.getElementById(ID). If some of your elementIds are kept in a list or map, those are also converted recursively into a real elements before passing to script. You can assume that ZWL's elementIds are the real elements.

Returned values from script#

Whatever values you returned from script are converted back into ZWL supported types. For instance, if you return a js object it will be converted to a map, if array it will be converted to a list, if it's an element it will be converted into an elementId.

Anything kept in js array or object will be recursively converted into ZWL types too so that you can use the returned values as you'd use any other value in a ZWL test.

Customizing script timeout#

A script is allowed to run for a limited time before a timeout error occurs to prevent forever running scripts. If you think your scripts may take more time than the default timeout, you can check options to customize it.

Examples#

# Get window's viewport widthviewportHeight = executeScript('window.innerWidth')