# Script

Узел, выполняющий сценарии, написанные на JavaScript. Script будет полезен для решения разных задач:

* Реализация сложных тестов над результатами одного или нескольких других узлов
* Генерация тестовых данных
* Преобразование переменных других узлов
* Выполнение операций для приведения тестируемой системы в заданное состояние (set\_up, tear\_down)
* Отладка и доступ к состоянию всех узлов проекта

## Редактирование

Окно редактирования узла разделено на две области - окно редактирования кода и окно консольного вывода. Для скрытия консоли нажмите на кнопку <img src="https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_h1PL8l6PT7lhrK1H%2FTestMace%202019-07-19%2015.42.04.png?alt=media&#x26;token=0b3a10fc-2c8a-40fa-a68c-5a8850f777e9" alt="" data-size="original"> .

Над окном консольного вывода расположена панель инструментов для управления поведением консоли:

* <img src="https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_hOSBQvP4qe3Riv4E%2FTestMace%202019-07-19%2015.43.23%20(1).png?alt=media&#x26;token=68cd8189-e348-46b5-91a8-14eac49912b2" alt="" data-size="original">/ <img src="https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_hTTunohBFKEZy1Wc%2FTestMace%202019-07-19%2015.44.34%20(1).png?alt=media&#x26;token=75ba2757-b83a-4008-9e31-24722a1a4701" alt="" data-size="original"> - переключение между режимами сохранения результатов выполнения в консоли. <img src="https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_hOSBQvP4qe3Riv4E%2FTestMace%202019-07-19%2015.43.23%20(1).png?alt=media&#x26;token=68cd8189-e348-46b5-91a8-14eac49912b2" alt="" data-size="original"> - очистка консоли перед каждым запуском скрипта, <img src="https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_hTTunohBFKEZy1Wc%2FTestMace%202019-07-19%2015.44.34%20(1).png?alt=media&#x26;token=75ba2757-b83a-4008-9e31-24722a1a4701" alt="" data-size="original"> - накопление результатов запуска.
* <img src="https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_hnFKHfCrfBxWPORk%2FTestMace%202019-07-19%2015.44.14.png?alt=media&#x26;token=67103e9a-79e3-448e-99d6-463f5b9d2a9a" alt="" data-size="original"> - автоматическая прокрутка к последней строке вывода консоли
* <img src="https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_iGoJ2glWwnW_bhTr%2FTestMace%202019-07-19%2015.43.48.png?alt=media&#x26;token=0d6f2572-c6cb-4092-a6c5-194da486bd1f" alt="" data-size="original"> - очистить текущий вывод консоли

## Запуск

Скрипт начинает выполнение при нажатии на кнопку `RUN`. Узел заканчивает свое выполнение после исполнения всех строки кода и после завершения всех асинхронных задач (например, `setTimeout`). Скрипт считается выполненным успешно при выполнении следующих условий:

* В коде не выявлено синтаксических ошибок
* При выполнении все выброшенные исключения обработаны
* Выполнение заняло не более 30 секунд (по истечении этого времени скрипт будет прерван)

{% hint style="success" %}
Вызов скрипта обернут в функцию, поэтому для того, чтобы прервать выполнение без ошибок воспользуйтесь инструкцией возврата: `return;`
{% endhint %}

{% hint style="danger" %}
Чтобы прервать выполнения скрипта с ошибкой, воспользуйтесь выбросом любого исключения: `throw new Error('Something went wrong');`
{% endhint %}

## Библиотеки

Запуск осуществляется в виртуальном окружении node.js. Пользователю доступно некоторые модули из node.js, а также все встроенные возможности JavaScript, поддерживаемые движком V8.&#x20;

{% hint style="info" %}
Осуществляется поддержка стандарта ECMAScript 6
{% endhint %}

### Доступные модули из node.js

* [fs](https://nodejs.org/docs/latest-v10.x/api/fs.html) - работа с файловой системой

### Доступные сторонние модули

* [lodash](https://lodash.com/) - библиотека со множеством утилитарных алгоритмов
* [moment.js](https://momentjs.com/) - библиотека для работы с датами
* [CryptoJS](https://cryptojs.gitbook.io/docs/) - библиотека реализующая множество криптографических алгоритмов&#x20;
* [random-js](https://github.com/ckknight/random-js) - библиотека для генерации математически корректных случайных чисел
* [faker.js](https://github.com/marak/Faker.js/) - библиотека для генерации случайных данных для свойств различных сущностей
* [chai.js](https://www.chaijs.com/) - библиотека предоставляющая комфортные интерфейсы для проверки логических утверждений. &#x20;
* [request](https://github.com/request/request) - библиотека предоставляющая простой в использовании HTTP-клиент.

## Контекст выполнения

Ниже приведены объекты и функции глобальной области видимости скрипта.

### Доступ к сторонним модулям

Все описанные модули автоматически подключаются к контексту выполнения и доступны в глобальной области видимости.&#x20;

#### lodash

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

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_j59hv8CU87yGHhrv%2FTestMace%202019-07-19%2015.40.23.png?alt=media\&token=85f870de-25f9-452f-8758-11364f9a245d)

#### moment.js

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

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_jCKveFUFssRFWiYy%2FTestMace%202019-07-19%2015.48.03.png?alt=media\&token=e555908c-6c84-4bdf-85f5-f5024e0333d2)

#### CryptoJS

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

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_jJUr0eLd8Xty_OI1%2FTestMace%202019-07-19%2015.50.41.png?alt=media\&token=a0eb0d9b-2f24-4279-871c-35ec098a5306)

#### random-js

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

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_jSsERf8RF2_Q3Zn3%2FTestMace%202019-07-19%2015.56.08.png?alt=media\&token=7c8b7daa-37bb-4196-8523-0fbe84c2553b)

####

#### faker.js

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

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_jdERmoRN8GM_Xvwm%2FTestMace%202019-07-19%2016.00.44.png?alt=media\&token=777e51b6-ae29-4cb8-b8bb-d4b554345665)

#### chai.js

```javascript
const foo = 'bar';

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

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

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_jmX6kkYQbnHCsOlQ%2FTestMace%202019-07-19%2016.08.18.png?alt=media\&token=fd400f28-2f3b-46b5-b948-de4e7aeaed6c)

#### 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://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_jt1hK5trdPNrnaEf%2FTestMace%202019-07-19%2016.22.25.png?alt=media\&token=23f3befa-fa9b-4f75-b3c3-39b5729379ec)

### console.\*

Методы для вывода данных в консоль: log, info, warn, error, debug, exception

Сигнатура методов совпадает с их стандартными версиями. Каждый тип события в консоли окрашивается в свой цвет. Каждая строка сопровождается указателем на строку и столбец, из которой произошел вызов функции вывода. События типа exception отображаются вместе со стеком вызовов внутри скрипта.

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_fYDd2sqAfI_PYFd1%2F-Ll_jzHVP3ir1TS948b5%2FTestMace%202019-07-19%2016.34.47.png?alt=media\&token=403c399e-5730-4e42-808b-63e4ae9b1310)

### Навигация по проекту

В глобальной области видимости доступен объект для доступа к проекту и текущему Script узлу - `tm`.&#x20;

#### tm

* `currentNode: nodeAPI` - интерфейс текущего Script узла&#x20;
* `project: nodeAPI` - интерфейс узла проекта
* `env: envAPI` - интерфейс для доступа к переменным окружения проекта
* `cookies: cookie[]` - список установленных в проекте cookies

#### nodeAPI

* `parent: nodeAPI` - возвращает интерфейс для родительского узла. Для узла проекта значение будет null
* `name: string` - имя данного узла
* `type: string` - тип данного узла.&#x20;
* `path: string` - путь до данного узла, относительно корня проекта.
* `children: nodeAPI[]` - список интерфейсов дочерних узлов
* `findChild(name: string): nodeAPI` - поиск дочернего узла по его \`name\`. Если узел с таким именем не найдет, вернется null
* `next: nodeAPI` - интерфейс следующего по порядку узла в группе. Если текущий узел является последним, то вернется null
* `prev: nodeAPI` - интерфейс предыдущего по порядку узла в группе. Если текущий узел является первым в группе, то вернется null
* `nextNodes: nodeAPI[]`  - список всех узлов в группе следующих за текущим. Если текущий узел является последним, то вернется пустой список
* `prevNodes: nodeAPI[]` - список всех узлов в группе предшествующих текущему. Если текущий узел является первым по порядку, то вернется пустой список
* `vars: object` - объект, содержащий все статические переменные данного узла
* `dynamicVars: object` - объект, содержащий все динамические переменные данного узла.
* `setDynamicVar(name: string, value: any): void` - метод устанавливает динамическую переменную \`name\` cо значением \`value\` для данного узла.

#### requestNodeAPI

Узел типа `RequestStep` обладает расширенным интерфейсом.

* `request: object` - объект содержит настройки запроса узла.
* `response: object` - объект содержит результаты последнего выполнения запроса

#### envAPI

* `active: string` - имя активного окружения
* `vars: object` - объект содержит переменные текущего окружения

## Примеры

### Рекурсивный обход потомков узла

```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);
```

### Поиск узлов по имени

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

## Файловое представление

```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#"
}
```
