Today I Learned

How to run a node command from the UI Vision RPA Chrome extension

How to run a node command from the UI.Vision RPA chrome extension

The anatomy of a basic UI Vision task looks like this:

  "Command": "XType",
  "Target": "Hello World${KEY_ENTER}",
  "Value": "",
  "Description": ""

It can be a very simple task such as typing some text in the before-selected input control. But it can also perform advanced sequences. These sequences can involve conditional structures, and system calls. It can even execute javascript in a sandboxed context.

The two most important parameters are Value and Target. But sometimes its usage is not very intuitive.

Luckily, the documentation is clear and accessible. As a quick link next to the command dropdown.

Let's call a node.js process sometime in our automation flow.

To do this, make sure you have the UI Vision extra X Modules installed. If you're running this on mac, make sure to also grant the necessary permissions.

The inconsistent usage of Value and Target made me spend some time figuring out how to split the command. I've found that this works:

  "Command": "XRun",
  "Target": "/My Path/.n/bin/node",
  "Value": "/My Path/automations/my_automation.js",
  "Description": ""

The Target is the binary we want to run, and the Value is the parameter we want to pass to it. In our case, a javascript file.

Another mention-worthy caveat: In the Chrome extension, you can't pass the Terminal as Target process due to security concerns.

How to use DocumentFragment to render large lists faster

Using DocumentFragment does the trick because it isn't part of the active document tree structure.

This means it doesn't interact with the main document until mounted.

Hence, it doesn't impact the performance when changes occur to its contents.

// Setup
const outlet = document.getElementById('#myList');
const fragment = new DocumentFragment();
const results = fetchResults(); // returns Array<Result>

We then go through each result and prepare it properly:

results.map((result, index) => {
    const li = document.createElement('li');
    li.textContent = result;
    // We append to the DocumentFragment

Finally, we append the end result to the list:


If we were to append each item to the list outlet within the map above, it would have triggered a repaint/reflow every time we performed the action.

Conditionally add properties to objects in JavaScript

This comes in handy when you want to completely omit a property from an object in case the value is undefined or null.

{prop1, prop2, ...(condition && prop3)}

The trick being here:

...(condition && prop3)

In case the condition evaluates to false, the property will be completely omitted from the object, otherwise, both the value and its corresponding key will show up in the end result.

Correctly grouping members within modules in JSDoc v3

JSDoc is great! It's documentation not so much. I needed a way to logically group together global methods and I was unsuccessful in finding a straightforward way in its official documentation.

Eventually, I've come across the following method, using @module and @member.

First, we define the module name, usually at the top of the file:

@module MyModule

We then proceed to annotate the target function with @memeber MyModule. One other important aspect is to also include @function along with the name of the function in order to appear in the module section.

 * @member MyModule
 * @function myFunction
 export const myFunction = () => ....

Using destructuring assignment to dynamically create new functions in JavaScript

// www.codewars.com/kata/525f3eda17c7cd9f9e000b39

const curry = (operand, operator) => (!operator) ? operand : operator(operand);

const [zero, one, two, three, four, five, six, seven, eight, nine] =
  [0,1,2,3,4,5,6,7,8,9].map(operand => ((operator) => curry(operand, operator)));

const plus = (first) => (second) => second + first;
const minus = (first) => (second) => second - first;
const times = (first) => (second) => second * first;
const dividedBy = (first) => (second) => Math.floor(second / first);

vue-cli-service environment variables

While you can find detailed information in the official docs, I dare to spoil the fun for you:

1. All app variables are pulled in if they are prefixed with VUE_APP_.


You can now access the variables in your application like this: process.env.APP_URL.

2. All e2e variables are fetched if they are prefixed withCYPRESS_.


You can now access the variables in your tests like this: Cypress.env('APP_URL').