# Script

This is a node that runs JavaScript scripts. It is going to help you solve the following tasks:

* create complex tests to check the results of one or several nodes;
* generate test data;
* change other nodes' variables;
* perform operations to bring the tested system to a specific state (set\_up, tear\_down);
* debug and access all nodes' states.

## Editing a Script&#x20;

The script node editing window is divided into two parts: the code editor and the console output window. To close the console window click the <img src="https://1914040845-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LYfhIaTTw23Sf3L5jfe%2F-LkTrcfYjzYT8him1F5A%2F-LkTtHTOFH08FuWDRtuM%2FTestMace%202019-07-19%2015.42.04.png?alt=media&#x26;token=c964fc73-7da1-4bbb-b8a9-57f1557c97c2" alt="" data-size="original"> button.

You can use the toolbar above the output window to manage the console behavior:

![](https://1914040845-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LYfhIaTTw23Sf3L5jfe%2F-LkTrcfYjzYT8him1F5A%2F-LkTuOuoBQywn7OdMTcW%2FTestMace%202019-07-19%2015.43.23.png?alt=media\&token=1d946a3b-1754-4a50-96de-a220986ca1fe)/![](https://1914040845-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LYfhIaTTw23Sf3L5jfe%2F-LkTrcfYjzYT8him1F5A%2F-LkTtnth9AoCIoum4eB6%2FTestMace%202019-07-19%2015.44.34.png?alt=media\&token=0916f637-f555-4574-848d-5a3af3389b73)- choose what to do with the console output. ![](https://1914040845-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LYfhIaTTw23Sf3L5jfe%2F-LkTrcfYjzYT8him1F5A%2F-LkTuOuoBQywn7OdMTcW%2FTestMace%202019-07-19%2015.43.23.png?alt=media\&token=1d946a3b-1754-4a50-96de-a220986ca1fe) -  clear the window every time you run a script, ![](https://1914040845-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LYfhIaTTw23Sf3L5jfe%2F-LkTrcfYjzYT8him1F5A%2F-LkTtnth9AoCIoum4eB6%2FTestMace%202019-07-19%2015.44.34.png?alt=media\&token=0916f637-f555-4574-848d-5a3af3389b73) -  display all previous outputs.

* ![](https://1914040845-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LYfhIaTTw23Sf3L5jfe%2F-LkTrcfYjzYT8him1F5A%2F-LkTuLaA994Reilwvjy7%2FTestMace%202019-07-19%2015.44.14.png?alt=media\&token=22602ea9-9fb4-4572-8be9-1dc105e40f5f) - auto scroll to the last line of the output
* ![](https://1914040845-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LYfhIaTTw23Sf3L5jfe%2F-LkTrcfYjzYT8him1F5A%2F-LkTuK4OIWVEjikfBLgc%2FTestMace%202019-07-19%2015.43.48.png?alt=media\&token=6ffc25fe-ef66-48f3-90e6-7830da850d82) - clear the console window

## Running a Script

Click the `RUN` button to execute the script. The execution continues to the last line of the code and finishes when all asynchronous tasks are done (e.g.`setTimeout`). The execution is successful if:

* there are no syntax errors in the code;
* the exceptions raised had been handled;
* the execution took no more than 30 seconds (otherwise the execution will be terminated).

{% hint style="success" %}
Since the call to the script is wrapped in a function, you need to use the `return;`command to avoid errors while terminating the script.
{% endhint %}

{% hint style="danger" %}
To get an error after script termination raise an exception with`throw new Error('Something went wrong');`
{% endhint %}

## Libraries

The script is executed in the Node.js virtual environment. Some Node.js modules and all standard JavaScript features supported by V8 are available.

{% hint style="info" %}
The ECMAScript 6 standard is supported as well.
{% endhint %}

### Available Node.js modules

* [fs](https://nodejs.org/docs/latest-v10.x/api/fs.html) - a module for interacting with the file system

### Available third party libraries

* [lodash](https://lodash.com/) - a library that provides lots of utility functions
* [moment.js](https://momentjs.com/) - a library for managing dates
* [CryptoJS](https://cryptojs.gitbook.io/docs/) - a collection of cryptographic algorithms
* [random-js](https://github.com/ckknight/random-js) - a mathematically correct random number generator library
* [faker.js](https://github.com/marak/Faker.js/) - a library that lets you generate random data for different entities properties
* [chai.js](https://www.chaijs.com/) - a library that provides a convenient API for making assertions&#x20;
* [request](https://github.com/request/request) - a library that provides a simplified HTTP client

## Execution Context

Objects and functions of the script's global scope are listed below.

### Accessing third party modules

Every module stated above is automatically added to the execution context and is available in the global scope. <br>

#### lodash

```javascript
const chunks = _.chunk([1, 2, 3, 4], 2);
```

![](https://lh6.googleusercontent.com/Bbf94MZLNaIftEDsdeVw9CrnH5vtcKVYOCJ0guCoyiH8PYTk1rNUUBFTRO5-H1d5gbmtIaYrBMMop9iJZht4DEeoQWWbuQnFZ8nDy9jA2xjBKbsJ8lBycwldHUqQPBU_lJvlY1_e)

#### moment.js

```javascript
const now = moment();
```

![](https://lh3.googleusercontent.com/1wRRxPY02Fp81Ismh5K6lydzKrHSs4Jtvd6XasUVv798jV4TO9ECbEx6h2_ed_ovsKDgml4N6qyv9nfyoZXVHQ_m-OxrcjO8bQZ_T3DSEs8uJKGl3YWFcPJWyeGMIq3bVJRTFcJ2)

#### CryptoJS

```javascript
const hash = crypto.MD5('Message');
```

![](https://lh6.googleusercontent.com/3YzYNVXeUR3R9YcarDMP9FiFzAmypv4tAo2sFFYhdd6uNWRmXUqmTM6iA1Tmob7h266DMRgOzacajJkQ0nlshEBJcqeUCmh9oNPIO4eZI1GkhWJD41s8mSZdzbE0hDoTPl4QL2UY)

#### random-js

```javascript
const randomEngine = new random.Random();
const shuffledArray = randomEngine.shuffle([1,2,3,4,5]);
```

![](https://lh3.googleusercontent.com/e1BiGi1jMy7eTYVbyNZp_A3veHRJeBUh0D-n-rvemlQ6LaJB7oTDF456Hvvn3DpmnDUlO1pSVQM1SzcphIQd33Nj1lcZjfPzRZTltl_whoboKX2jFnuyTzJfm65cXBbS5wfo8RJ5)

#### faker.js

```javascript
const person = { 
    'name': faker.name.findName(),
    'email': faker.internet.email()
};
```

![](https://lh4.googleusercontent.com/XXeDedNzlFvzx-9o7-3ubb9Mtc3iOS21fs0gVyUpeJ-eikRl9E6uRYb81pmZG2vZMHjpCMuxjz6om3w0PkQNp78C5d1C0MmIFZGRk-tBGmC8UT3EAYK4YT5bxdha3JIde7AygmBv)

#### chai.js

```javascript
const foo = 'bar';

// success
assert.equal(foo, 'bar');
expect(foo).to.equal('bar');

// failure
assert.equal(1, 0);
```

![](https://lh3.googleusercontent.com/esHpUUaeRWLbbjJdBoZlsUQS3OaqK2gTDBgIne41dsAM3ekFNS3AixFhDmJQfJbM_7Ibt2XTMxX1UaCbuBdmPPEgiQARHzcVwvdkJVcLwwjjynVQsnPiDIF5zpskmJIwyBiomgMC)

#### request

```javascript
request('https://docs-ru.testmace.com', (error, response, body) => {
  assert.equal(error, null);
  assert.equal(response.statusCode, 200);
  assert.notEqual(body, null);
});
```

![](https://lh5.googleusercontent.com/5xhSJgXEJPciYXsxy9lCFhikDBHZB1QyYGiAGx8ESkAYY9mbbzWiZ_MlVVeI6CKWi2FAW-78ACtGDilzYA-yU74ZLmayE258v5UZnqLqh6yEhhRD5OXifc7yZ0DKbNJVRnziohBQ)

### console.\*

There are different console output methods, such as log, info, warn, error, debug, exception.

Their signatures are equal to the signatures of their standard versions. In the console every method type is highlighted in different color. Each colored line contains the particular row and column where the output method is called. Events of the exception type are displayed along with the stack trace.

![](https://lh6.googleusercontent.com/wXycl_ul2Ck-AODiyKugRkFcxcwUuRDKVPKAhb9BaQH_gv2lHD8cM9n-xT7Mqj8AN2-7TRr3otwQ55kiMMVQq7XVNO4O6hTyKka74K3XllkvrgOCmyAELyDar2ABbMwuxLDTQXJ-)

### Navigating your project

There is an object used to access the project and the current Script node. It is called `tm` and it is available in the global scope.&#x20;

#### tm

* `currentNode: nodeAPI` - the current Script node API&#x20;
* `project: nodeAPI` - the project node API
* `env: envAPI` - the API for accessing the environment variables
* `cookies: cookie[]` - a list of cookies used in the project

#### nodeAPI

* `parent: nodeAPI` - returns a parent node API and null for the project node
* `name: string` - the given node name
* `type: string` - the given node type
* `path: string` - the path to the given node starting with the project root
* `children: nodeAPI[]` - a list of child nodes APIs
* `findChild(name: string): nodeAPI` - searches for the child node using its name and returns null if the node doesn't exist
* `next: nodeAPI` - the API of the next node in the group. If the given node is the last one, null is returned
* `prev: nodeAPI` - the API of the previous node in the group. If the given node is the first one, null is returned
* `nextNodes: nodeAPI[]`  - a list of all next nodes in the group. If the given node is the last one, an empty list is returned
* `prevNodes: nodeAPI[]` - a list of all previous nodes in the group. If the given node is the first one, an empty list is returned
* `vars: object` - the object that stores all static variables of the given node
* `dynamicVars: object` - the object that stores all dynamic variables of the given node
* `setDynamicVar(name: string, value: any): void` - sets the name dynamic variable with a certain value for the given node

#### requestNodeAPI

The interface of a `RequestStep` node is more advanced.

* `request: object` - the object that stores the node's request configuration
* `response: object` - the object that stores the results of the last request

#### envAPI

* `active: string` - the active environment title
* `vars: object` - the object that stores the current environment variables

## Code examples

### Recursive traversal of the node's children

```javascript
const current = tm.currentNode;
const parent = current.parent;
if (!parent) {
  console.warn(`Parent of ${current.path} not found`);
  return;
}

const value = parent.vars['ID'];
if (!value) {
  console.warn(`Node ${parent.path} hasn't have value for ID`);
  return;
}
console.log(`Parent ID = ${value}`);

const setIDToNode = (node) => {
  node.setDynamicVar('ID', value);
};

const traverseDescendants = (node, func, depth) => {
  node.children.forEach((child) => {
    func(node);
    
    indent = '\t'.repeat(depth);
    console.debug(
      `${indent}${child.path}`,
      `${indent}Value: ${child.dynamicVars['ID']}`
    );
    
    traverseDescendants(child, func, depth+1);
  });
};

traverseDescendants(parent, setIDToNode, 0);
```

### Searching a node by its name

```javascript
const current = tm.currentNode;
const scriptNode = current.parent.findChild(current.name);
assert.equal(current, scriptNode);
```

## File Representation

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Script node",
      "const": "Script",
      "type": "string"
    },
    "script": {
      "description": "Javascript code",
      "type": "string"
    },
    "children": {
      "description": "List of children names",
      "type": "array",
      "items": {
        "type": "string"
      },
      "default": []
    },
    "variables": {
      "$ref": "#/definitions/NodeVariables",
      "description": "Node variables dictionary"
    },
    "name": {
      "description": "Node name",
      "type": "string"
    }
  },
  "required": [
    "children",
    "name",
    "script",
    "type",
    "variables"
  ],
  "definitions": {
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```
