# Virtuoso Directives

Using directives, you can automate how Virtuoso automates! This guide provides a gentle introduction on how this can be achieved.

Alpha Release

Virtuoso's directive feature is currently only released as an alpha release. The feature and the interface for it can significantly change in future releases which may not be backwards compatible.

This feature is intended towards engineers with previous technical automation and/or software engineering background. For any questions, feedback, or challenges on building directives to support your custom scenarios, please contact [email protected] and our engineering team will be more than happy to guide you on building your own custom directives. Your feedback can help shape the future of directives in Virtuoso.

# What is a directive?

When Virtuoso explores an application, it starts by discovering the first page from the starting point of your goal. Following this, Virtuoso systematically makes user-like interactions to the page such as clicking links, buttons, etc. and filling forms. Based on the resulting states Virtuoso arrives at, using its machine-learning based intelligent graph consolidation mechanism, Virtuoso creates a unique graph of the application.

The interactions described in the previous scenario can be guided using directives. All automated journeys generate corresponding tests. Therefore, not only can you generate interactions to the page, but also perform assertions that can serve as regression tests, and/or be used for compliance testing. The Directive Library contains ready-to-use directives that you can import straight into your project. The following sections explain how you can build a custom directive.

# The lifecycle of an exploration

Directives control the exploration process by emitting sets of instructions that are run in a real web browser. Virtuoso will then capture the state of the application, including a screenshot, that is then added to your application graph. When Virtuoso captures the state ("discovering" it), it records the set of interactive elements on the page, which are used to generate further interactions in subsequent explorations. The diagram below shows how exploration of a page can lead to more interactions with more pages in subsequent exploration jobs. Note how the "fan-out" pattern matches the shape of the application graph - as Virtuoso explores more of the application, it uncovers more potential interactions:

# 1. Starting the exploration

If you are exploring from scratch, Virtuoso will first perform a discovery of the page at the goal URL and save it in the graph. If you are exploring from one or more states in your graph (exploring further), Virtuoso will re-use the discoveries of those pages from the graph.

# 2. Running your directive

For each page in the exploration, Virtuoso will create a new instance of your directive class and call exploreFromCheckpoint() on it. Each list of instructions your directive returns will correspond to a discovery.

# 3. Performing the interactions

Virtuoso will prepend the instructions your directive emits with the steps required to reach the state that your directive is running on and run them in a browser before capturing the page.

# 4. Post-processing

Finally, if enabled, intelligent graph consolidation will replace duplicated states in your graph, and journeys will be generated for newly discovered states.

You can use more than one directive!

You can switch directives in the goal settings between jobs, allowing you to use different directives on different parts of your application to build a single graph.

# How to create a directive?

Directives are written in JavaScript (ES6+ compatible). To get started, you need to first create a directive extension. Afterwards, you can enable the directive in the advanced settings in the goal configuration page.

Here is an example of a basic directive that clicks on every link on a page:

class Directive extends VirtuosoDirective {
    exploreFromCheckpoint() {
        return this.getState().elements.links.map(link => ({
            instructions: [

In the above, notice the following:

  • A directive has to be created as a class named Directive, that extends VirtuosoDirective (support for custom naming of the class will be made available in future updates).
  • A function named exploreFromCheckpoint() needs to be implemented, that returns a list of directive outcomes. A directive outcome is an object containing a list of instructions to perform from the current checkpoint. These instructions can be interactions as well as assertions.

In the context of the VirtuosoDirective class that you extend, a number of methods are available that enable you to get details from Virtuoso or from the context. See the directive examples section for usage examples:

  • this.getState() provides you the checkpoint state that was discovered (the checkpoint you are exploring further from).
    • TIP: use the auto-complete to find out what information is available in each state.
  • this.getDataTableById() / this.getDataTableByName() / this.getDataTables() provide you the ability to get data tables from Virtuoso.
  • this.getGoal() provides you the goal of the exploration.
  • this.getProject() provides you the project of the exploration.
  • this.getScriptByName() / this.getScripts() enable you to get scripts that are available to the project.
  • this.getTask() provides you the ability get the discovery task at the current state (e.g., get instructions executed up to this state)
  • this.getRandom() provides you the generate random values. Some examples are provided below:
    • name / fullname: Generate a random full name. e.g., this.getRandom('name')
    • email: random email address
    • street: random street
    • city: random city
    • country: random country
    • postcode: random postcode/zipcode
    • string: random string of 10 characters
    • number: random number
    • uuid: random UUID
    • ipsum: two lorem-ipsum words generated randomly
  • this.instruction gives you access to the instruction builder of Virtuoso. For example, you can write this.instruction.click(...) to build an instruction to click on an element.
  • this.kvGetString() and this.kvPutString() allow you to share data between invocations of the directive.


The interface of the directive is easily accessible via the auto-complete on the editor. You can press ctrl/cmd + space to open up the auto-complete in the Virtuoso extension IDE to help with writing the extension. Try this by writing this.instruction. inside the exploreFromCheckpoint() method, and press ctrl/cmd + space to get the auto-complete suggestions.

# Key-value storage: sharing data between pages

Key-value storage allows directives to save data after processing one page and then recall that data when processing another page. For example, you could use key-value storage to restrict the total number of pages explored, or use it to skip repeated interactions with the same elements that appear on different pages.

Each goal has its own dedicated key-value (KV) storage that directives can access via the kvPutString and kvGetString methods. KV storage is accessible from within the directive and persists between explorations, allowing you to store data for use in future explorations.

KV storage is subject to the following quota limits:

  • At most 100 unique keys can be written or read each time the directive runs
  • Keys can be at most 512 characters
  • The size of all values in the goal's KV store is limited to 10 MB
Last Updated: 3/29/2021, 8:58:45 AM