# Быстрый старт

Данное руководство позволит вам быстро освоить интерфейс и основные функции TestMace.

{% hint style="info" %}
В этом руководстве мы протестируем работу back-end сервера для записей типа post на следующем сценарии:

* запросим у сервера все имеющиеся записи
* добавим новую запись
* проверим корректное добавление записи
* обновим только что созданную запись и проверим корректность обновления через ответ от сервера
* запросим обновленную запись от сервера
* проверим, что на сервере запись действительно обновлена
* удалим запись
* проверим, что на сервере запись не существует

**Для этого нам потребуется не более 10 минут, после запуска программы.**
{% endhint %}

## Установка TestMace

Скачать TestMace можно по ссылкам ниже или с сайта <https://client.testmace.com>

* Windows <https://client.testmace.com/download/?os=windows>&#x20;
* Mac OS <https://client.testmace.com/download/?os=mac>
* Linux <https://client.testmace.com/download/?os=linux>

Запустите скачанный файл  и следуйте инструкциям инсталлятора, во время установки будет предложено выбрать директорию установки приложения.

{% hint style="warning" %}
*Для установки TestMace на Windows запустите инсталлятор **с правами администратора.***
{% endhint %}

По завершению установки запустите приложение. Перед вами откроется новый проект.&#x20;

## Обзор интерфейса

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhRnoIjwW7Dhql0g3%2Fmain_screen_1.png?alt=media\&token=7ffe69a0-d600-46d0-a6be-68163828abf9)

## Ваш первый GET запрос

Для создания первого запроса создайте новую вкладку нажав на **+**. При этом в зоне "Scrathes Area" будет создан узел с названием **Scratch 1**. Вставьте в поле URL адрес: <https://testmace-stage.herokuapp.com/posts>. Можно сразу протестировать ответ сервера из "Scrathes Area" или перенести наш черновик в проект. Для удобства переименуйте этот узел, дав ему название **getPosts**.&#x20;

{% hint style="info" %}
Обратите внимание, что все изменения в проекте сохраняются автоматически в режиме реального времени.
{% endhint %}

![Создание шаблона GET запроса](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhWmHEyt7Wg_pwGOK%2Fgetting_started_1.gif?alt=media\&token=a449b957-5d13-4714-bd85-ffdf0a8506de)

Создайте в проекте узел типа [Folder](/0.0.1-beta.14/node-types/folder) с названием **posts** и перенесите созданный черновик **getPosts** из "Scratch Area" в "Project Area".

![Создание Folder узла и перенос шаблона GET запроса](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhbUocmpVlEgJv8Wx%2Fgetting_started_2.gif?alt=media\&token=98edc4c3-659c-45f8-bb60-14fc441b0161)

Откройте двойным кликом созданный запрос **getPosts** и выполните его нажав на кнопку "Run".

![Запуск GET запроса](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhh6Qu8HogBVo8YVV%2Fgetting_started_3.gif?alt=media\&token=2994c506-2517-4eb5-8d5b-0cfdac3e46ef)

Мы видим, что запрос выполнен успешно, в **Response Area** получен список существующих записей.  Давайте рассмотрим этот экран подробнее:

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhmH053dp3fjyobYv%2Frun%20screen.png?alt=media\&token=f7605fac-dd77-40c1-a4a7-eb21b3810a93)

{% hint style="info" %}

#### Request parameters

Здесь вы можете указать http заголовки, а так же передать параметры запросу с автодополнением и использование переменных.

#### Request type

* **GET** — получение ресурса
* **POST** — создание ресурса
* **PUT** — обновление ресурса
* **DELETE** — удаление ресурса
* **PATCH** — для частичного изменения ресурса
* **OPTIONS** — для описания параметров соединения с ресурсом

#### URL

Поле URL поддерживает автодополнение, а так же использование переменных. Мы воспользуемся этими функциями чуть позже.&#x20;

#### Make Request

Выполнение запроса или группы запросов при запуске из корня проекта или ноды типа folder

#### Response area

Зона ответа сервера, вкладка Response Body может быть представлена в виде: Parsed, JSON, text. В соседних вкладках можно посмотреть Response Headers, а так же создать или посмотреть существующие Assertion узлы для запроса.
{% endhint %}

## POST запрос и Assertion

Давайте теперь добавим новую запись типа post на сервер, для этого нам нужно создать новый [RequestStep](/0.0.1-beta.14/node-types/requeststep) узел.&#x20;

{% hint style="info" %}
**Существует три способа добавления нового узла в проект:**

1. Мы можем создать черновик (Scratch) нажав на **+** и позже перенести его в проект используя Drag and Drop;&#x20;
2. Можно нажать правой кнопкой мыши по узлу родителю и выбрать **Add node -> Request step**;&#x20;
3. Можно нажать на кнопку **Add project node-> Add node -> Request step**.&#x20;
   {% endhint %}

Создайте новый узел любым из этих способов и задайте ему имя **createPost**.&#x20;

1. Выберите для этого узла "**Request type**" значением POST
2. В поле URL вставьте <https://testmace-stage.herokuapp.com/posts>
3. Во вкладке body выберите тип данных JSON и добавьте `{"title": "Testing post", "content": "Sendt via TestMace"}`
4. Выполните запрос нажав на кнопку RUN.&#x20;

Будет получен ответ об успешном добавлении записи, но нам нужно проверить, что запись добавлена корректно, для этого мы воспользуемся механизмом быстрого создания [Assertion](/0.0.1-beta.14/node-types/assertion) узлов. Мы сравним отправляемые данные с полученными от сервера.

В зоне "Response Area" в формате Parsed нажмите правой кнопкой мыши по **значению title**, которое мы передавали в  запросе, выберите **Create Assertion -> Compare -> Equal.** После этого узел [Assertion](/0.0.1-beta.14/node-types/assertion) будет создан и открыт, нам дополнительной настройки не требуется, поэтому закроем его. Аналогично создадим Assertion узел для значения Content.

А теперь запустим запрос **createPost** и интерфейс проинформирует нас об успешном выполнении теста. Это совсем не сложно, посмотрите анимацию ниже:

![POST запрос и создание Assertion](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMi-YplERQn7P7vAdh%2Fgetting_started_4.gif?alt=media\&token=72a8ead4-09d7-4042-bcf3-5dfc4baac62b)

### Динамические переменные

Для того, чтобы мы могли взаимодействовать с созданной нами записью на сервере, нужно передавать в последующие [Request step](/0.0.1-beta.14/node-types/requeststep) значение её **Id**. Создадим динамическую переменную **postId** и присвоим ей значение Id возвращаемое в записи после выполнения **CreatePost**.&#x20;

1. Кликните правой кнопкой мыши по значению **Id** в Response body ноды **CreatePost**,&#x20;
2. Выберите пункт **Assign to variable**.&#x20;
3. Во всплывающем окне в качестве ноды выберите директорию проекта **posts**, введите имя переменной: **postId** и нажмите **ОК**.

Для того чтобы обратиться к переменной используйте [встроенную переменную](/0.0.1-beta.14/variables/variables) `$dynamicVar`:

```
${$dynamicVar.postId}
```

![Создание динамической переменной](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMi7013WKadQVvXiGl%2Fgetting_started_5.gif?alt=media\&token=062fae05-2749-47ee-8cb9-f3ca2ebb949b)

## PUT запрос&#x20;

На этом этапе мы будем использовать запрос типа PUT. Обратимся  к записи созданной на предыдущем шаге при помощи динамической переменной: `${$dynamicVar.postId}` и обновим  значения записи **title** и **content**.

1. Создайте [RequestStep](/0.0.1-beta.14/node-types/requeststep) узел c именем **updatePost**
2. Request type выберите **PUT**
3. URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>
4. Body: `{"title": "Testing post updated", "content": "Updated via TestMace"}`
5. Выполним запрос и аналогично шагу **POST запрос**, создадим два [Assertion](/0.0.1-beta.14/node-types/assertion) узла для сравнения отправленных и полученных значений **title** и **content**.

![Создание PUT запроса](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMiCJFpZet2AU5b53U%2Fgetting_started_6.gif?alt=media\&token=f2afbe7f-c124-4766-a83f-f9a41eeba3fd)

## Проверка изменений

В некоторых случаях необходимо провести дополнительную проверку изменений записи, так как сервер может ответить на PUT запрос успешным выполнением, а при обращении через GET запрос мы получим старую запись.&#x20;

Для этого мы создадим GET запрос по URL записи с использованием динамической переменной:

1. Создайте новый [RequestStep](/0.0.1-beta.14/node-types/requeststep) узел с именем **getPost**
2. Тип запроса: GET
3. URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>
4. Выполните запрос и создайте 2 [Assertion](/0.0.1-beta.14/node-types/assertion) узла для сравнения данных **title** и **content**.

![Проверка изменений через GET запрос](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMiT5mOsq1gAMPerMW%2Fgetting_started_7.gif?alt=media\&token=5e59de9b-f62d-41bc-837b-64cc73fefb57)

## DELETE запрос

Следующий шаг - удаление созданной нами записи по URL записи с использованием динамической переменной:

1. Создайте узел типа [RequestStep](/0.0.1-beta.14/node-types/requeststep) с именем **deletePost**
2. Тип запроса: DELETE
3. URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>

![DELETE запрос](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMiZW7ZpmWWOjtKxmv%2Fgetting_started_8.gif?alt=media\&token=85f97180-fbe5-49ed-9f42-9bb64452d528)

## Проверка DELETE

Для того, чтобы убедиться, что созданная запись была удалена с сервера, создадим GET запрос  по URL записи с использованием динамической переменной, мы ожидаем, что при запросе получим ответ сервера: 404, поэтому создадим соответствующий Assertion узел:

1. Создайте узел типа [RequestStep](/0.0.1-beta.14/node-types/requeststep) с именем **checkIfNodeExists**
2. Тип запроса: GET
3. URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>
4. Выполните запрос и в зоне Response Area выберите пункт **Assertions** и добавьте новый [Assertion](/0.0.1-beta.14/node-types/assertion) узел, нажав ADD. Внесите данные узла:
   1. Actual value: `${$response.code}`
   2. Operator: `=`
   3. Expected value: `404`

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMifs1DC9bLBWd_0OX%2Fgetting_started_9.gif?alt=media\&token=2a4955ea-9330-482d-bfd4-79856fea6587)

## Заключение

В результате мы получили набор тестов для нашего сервера, которые можно последовательно выполнить, перейдите в узел **posts** и нажмите RUN.&#x20;

![Запуск сценария](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMijSU3AugGlYW8Hb9%2Fgetting_started_10.gif?alt=media\&token=19974399-a80a-4c9d-8929-1481ff85ddff)

## Видео инструкция

Посмотрите весь процесс создания сценария описанного в руководстве на видео

{% embed url="<https://youtu.be/Gyg_4w78KBo>" %}

## Код для импорта через [shared](/0.0.1-beta.14/other/import/shared)

{% file src="/files/-LiMgl1CXlo1QrHQ-pvL" %}
Быстрый страт Share код
{% endfile %}

## Скачать проект

Разархивируйте  в директорию проектов TestMace.

{% file src="/files/-LiMgePcyczxfcL4KgnN" %}
Быстрый старт
{% endfile %}


# Меню

![Меню](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMj8R2AA2HCwWecvf1%2F-LiMjTWmbJR1U94vw05W%2F2.png?alt=media\&token=9d1df541-693d-4a85-be17-5f4b9a4aab1c)

* **Undo и Redo** - отмена и повтор действий. На данный момент поддерживаются все действия связанные с изменением проектов и узлов.
* [**Cookies**](/0.0.1-beta.14/work-with/cookie) - диалог для работы с cookies.
* [**Environments**](/0.0.1-beta.14/variables/env) - конфигурация и выбор текущего environment.


# Обзор интерфейса

### Интерфейс приложения разделен на 3 глобальные группы <a href="#interfeis-prilozheniya-razdelen-na-3-globalnye-gruppy" id="interfeis-prilozheniya-razdelen-na-3-globalnye-gruppy"></a>

1. Дерево проекта
2. Область шаблонов
3. Главная область

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhRnoIjwW7Dhql0g3%2Fmain_screen_1.png?alt=media\&token=7ffe69a0-d600-46d0-a6be-68163828abf9)

### Главная область или область запроса так же разделена на группы <a href="#glavnaya-oblast-ili-oblast-zaprosa-tak-zhe-razdelena-na-gruppy" id="glavnaya-oblast-ili-oblast-zaprosa-tak-zhe-razdelena-na-gruppy"></a>

1. Тип запроса
2. URL
3. Запуск
4. Параметры запроса
5. Зона ответа от сервера

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhmH053dp3fjyobYv%2Frun%20screen.png?alt=media\&token=f7605fac-dd77-40c1-a4a7-eb21b3810a93)


# Черновики

{% hint style="info" %}
**Scratches — это черновики узлов , которые вы можете  вы переносить в основное дерево проекта**
{% endhint %}

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMj8R2AA2HCwWecvf1%2F-LiMk7xaroMnSbAqF1Lq%2Fscratches.gif?alt=media\&token=f2aa116b-6565-4c26-95e5-7f9fba5ce34c)


# Типы узлов

{% hint style="info" %}
Узел - это любой элемент дерева проекта или черновиков
{% endhint %}

### Типы узлов

* [**Project**](/0.0.1-beta.14/node-types/project)**.** Это корневой узел, создается автоматически при создании проекта. В остальном повторяет функциональные возможности Folder узла.
* [**Folder**](/0.0.1-beta.14/node-types/folder)**.** Позволяет группировать Folder и RequestStep узлы внутри себя.
* [**RequestStep**](/0.0.1-beta.14/node-types/requeststep). Это узел, с помощью которого можно сделать запрос. В качестве дочернего элемента он может иметь только один Assertion узел.
* [**Assertion**](/0.0.1-beta.14/node-types/assertion). Узел используется для написания тестов. Может быть дочерним узлом только для RequestStep узла.
* [**Script**](/0.0.1-beta.14/node-types/script). Позволяет запускать произвольный скрипт на языке JavaScript с возможностью обращения к API приложения.
* [**Link**](/0.0.1-beta.14/node-types/link). Позволяет сослаться на уже существующую ноду.
* [**Api description**](/0.0.1-beta.14/node-types/api-description)
  * [**ApiRootFolder**](/0.0.1-beta.14/node-types/api-description/apirootfolder)**.** Корневой элемент (папка) для описания API
  * [**ApiFolder**](/0.0.1-beta.14/node-types/folder)**.** Служит для объединения логически близких эндпоинтов при описании API (например, эндпоинты с одинаковыми url-ами но разными методами)
  * [**ApiRoute**](/0.0.1-beta.14/node-types/api-description/apiroute)**.** Описание конкретного эндпоинта
* [**Broken**](/0.0.1-beta.14/node-types/broken)**.**  Используется для описания узлов, загрузка которых завершилась с ошибкой. Не может быть создан вручную и не сохраняется в файловую систему.


# Горячие клавиши

Использование горячих клавиш в TestMace

| Назначение               | Сочетание клавиш   |
| ------------------------ | ------------------ |
| **Навигация**            |                    |
| Фокус на дерево проекта  | Ctrl + 1           |
| Фокус на шаблоны         | Ctrl + 2           |
| Фокус на главную область | Ctrl + 3           |
| Открыть настройки        | Ctrl + Alt + S     |
| **Табы**                 |                    |
| Предыдущий таб           | Ctrl + Shift + Tab |
| Следующий таб            | Ctrl + Tab         |
| Закрыть таб              | Ctrl + W           |
| Создать новый шаблон     | Ctrl + T           |
| **Дерево проекта**       |                    |
| Фокус на поле поиска     | Ctrl + F           |
| Открыть узел             | Enter              |
| Открыть меню узла        | Alt + Insert       |
| Удалить узел             | Delete             |
| Переименовать узел       | Ctrl + F6          |
| Следующий узел           | ↓                  |
| Предыдущий узел          | ↑                  |
| Развернуть узел          | →                  |
| Свернуть узел            | ←                  |
| **Проект**               |                    |
| Run Node                 | Ctrl + Enter       |
| Focus Url                | Ctrl + E           |
| Save Project             | Ctrl + S           |
| Save Project as          | Ctrl + Shift + S   |
| Open Project             | Ctrl + O           |
| Create New Project       | Ctrl + N           |
| Undo                     | Ctrl + Z           |
| Redo                     | Ctrl + Shift + Z   |


# Project

Узел типа **Project** - корневой элемент проекта. Он создается автоматически при создании нового проекта и в дальнейшем повторяет функционал [Folder](/0.0.1-beta.14/node-types/folder) узла. **Project** узел также не может быть создан вручную и не может использоваться в качестве потомка других типов узлов.

{% hint style="warning" %}
На данный момент переименование папки Project не поддерживается из приложения. Кроме того, переименование папки Project напрямую в файловой системе сломает проект.
{% endhint %}


# Folder

Данный тип узла используется для группировки других узлов. В качестве предков для данного типа узла могут выступать [Project](/0.0.1-beta.14/node-types/project) и **Folder** узлы. В дереве проекта узел выглядит следующим образом:

![Вид Folder узла в дереве](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMkb3-DX1GM-t41kVp%2F-LiMmTIIcnPTqxcvqNKY%2Ff_1.png?alt=media\&token=be6e7ec3-e670-49f7-bbc5-6e441ec56e9b)

В дереве для данного типа узла доступны следующие пункты меню:

![Контекстное меню для Folder узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMkb3-DX1GM-t41kVp%2F-LiMmVgGhUcgkI5BfQ3f%2FF_2.png?alt=media\&token=965e0b09-8ea5-4833-ada7-8a79412da056)

* **Add node.** Добавление узла-потомка. В подменю можно выбрать тип узла.
* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название **NodeName \[Copy \[number]]**.
* **Remove node.** Удалить узел.
* **Run.** Запустить узел.
* [**Share**](/0.0.1-beta.14/other/import/shared)**.** Поделиться узлом. При это в буфере обмена создается ссылка, которая содержит всю информацию о текущем узле.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

Открытие узла открывается двойным кликом по узлу в дереве. Вкладка **Folder** узла выглядит следующим образом:

![Вкладка с открытым Folder узлом](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMkb3-DX1GM-t41kVp%2F-LiMmZZV7lGYhAkNysCD%2Ff_3.png?alt=media\&token=70509ecd-5aa5-4fa9-b719-643315e26a6c)

На скрине отмечены следующие области

1. Кнопка **Run** для запуска узлов внутри Folder узла
2. Панель управления
3. Кнопка **Headers** для задания наследуемых HTTP-заголовков
4. Кнопка **открытия** [**диалога переменных**](/0.0.1-beta.14/variables/user-variables)
5. Область **дочерних узлов**
6. Проверка на то, что узел имеет валидный SSL сертификат. Используется в качестве наследуемого параметра в [RequestStep](/0.0.1-beta.14/node-types/requeststep) узле
7. **Авторизация**

Рассмотрим данные области подробнее.

### Панель управления

Назначение кнопки **Run** описано выше. Стоит добавить, что при запуске узла кнопка меняет вид на следующий:

![Вид кнопки Run в процессе запуска узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMkb3-DX1GM-t41kVp%2F-LiMmaMjx53JO9Hq1Xmv%2Ff_4.png?alt=media\&token=b5028006-c46d-498b-809f-44e69d9dcfe9)

При нажатии на **Abort** можно прервать выполнение узла.

Кнопка **Headers** позволяет задать [наследуемые HTTP-заголовки](/0.0.1-beta.14/other/default-http-headers).

Редактирование переменных обсуждается в разделе [Пользовательские переменные](/0.0.1-beta.14/variables/user-variables).

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

**Folder** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат.

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Folder node",
      "const": "Folder",
      "type": "string"
    },
    "authData": {
      "$ref": "#/definitions/IAuthorizationData",
      "description": "Authorization parameters"
    },
    "requestData": {
      "$ref": "#/definitions/IRequestParametersData",
      "description": "Request parameters"
    },
    "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": [
    "authData",
    "children",
    "name",
    "requestData",
    "type",
    "variables"
  ],
  "definitions": {
    "IAuthorizationData": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "IRequestParametersData": {
      "type": "object",
      "properties": {
        "headers": {
          "description": "Headers",
          "type": "array",
          "items": {
            "$ref": "#/definitions/NameValueParam"
          }
        },
        "disabledInheritedHeaders": {
          "description": "Names of disabled headers",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "strictSSL": {
          "$ref": "#/definitions/StrictSSLOptions",
          "description": "Requires SSL certificates be valid"
        }
      },
      "required": [
        "disabledInheritedHeaders",
        "headers",
        "strictSSL"
      ]
    },
    "NameValueParam": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "value": {
          "type": "string"
        },
        "isChecked": {
          "type": "boolean"
        }
      },
      "required": [
        "name",
        "value"
      ]
    },
    "StrictSSLOptions": {
      "enum": [
        "Inherit",
        "No",
        "Yes"
      ],
      "type": "string"
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# RequestStep

**RequestStep** узел - это узел для отправки HTTP-запросов. Наш инструмент позволяет гибко сконфигурировать запрос и использовать его как отдельно, так и в составе сценария.&#x20;

### Представление RequestStep узла в дереве проекта

Для создания **RequestStep** узла необходимо в контекстном меню [Folder](/0.0.1-beta.14/node-types/folder) узла или [Project](/0.0.1-beta.14/node-types/project) узла выбрать пункт **Add node** -> **RequestStep**.&#x20;

В дереве проекта **RequestStep** узел выглядит следующим образом

![Вид RequestStep узла в дереве](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMn8brxTqg9NyauFGQ%2Fr_1.png?alt=media\&token=bad90b90-b617-484a-be06-772296e84c6f)

Остановимся на узле поподробнее. Цвет левого верхнего кружка указывает на статус HTTP-запроса: серый - если запрос не выполнялся, зеленый - в случае успешного HTTP-кода (например, 200, 201 и т.д.), красный - в случае неудачного HTTP-кода (например, 404, 500 и т.д.). Цвет иконки листочка указывает на статус выполнения дочернего [Assertion](/0.0.1-beta.14/node-types/assertion) узла: серый - если запуск не выполнялся, зеленый - в случае если после запуска, [Assertion](/0.0.1-beta.14/node-types/assertion) узел либо отсутствует, либо существует и его выполнение завершилось успешно, красный - в случае, если выполнение [Assertion](/0.0.1-beta.14/node-types/assertion) узла завершилось с ошибкой (не все проверки были пройдены).

В дереве для данного типа узла доступны следующие пункты меню:

![Контекстное меню для RequestStep узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnC-lWL3HbKt7n8v6%2Fr_2.png?alt=media\&token=f7c7f321-6640-4a8f-878f-a45b3e97dc74)

* **Add node.** Добавление узла-потомка. В подменю можно выбрать тип узла.
* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название NodeName \[Copy \[number]].
* **Remove node.** Удалить узел.
* **Run.** Запустить узел.
* [**Share**](/0.0.1-beta.14/other/import/shared)**.** Поделиться узлом. При это в буфере обмена создается ссылка, которая содержит всю информацию о текущем узле.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

### Описание вкладки RequestStep узла

При создании **RequestStep** узла (или при двойном клике по уже существующему) открывается вкладка данного узла. Выглядит она следующим образом:

![Вкладка RequestStep узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnEvykjaSi-HmvyaO%2Fr_3.png?alt=media\&token=16228eaa-d70d-4745-ad8c-5532c8f5b6e8)

Рассмотрим подробнее каждую из частей интерфейса.&#x20;

#### Секция конфигурирования запроса

Верхняя часть запроса выглядит следующим образом:

![Верхняя часть запроса](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnHqzZyYcsjZwlpwR%2Fr_4.png?alt=media\&token=2c24d661-d1c9-4da2-b0bf-9dae21081de2)

На скрине выше отмечены следующие пункты

1. Метод запроса. На данный момент поддерживаются следующие методы:
   * **GET** — получение ресурса
   * **POST** — создание ресурса
   * **PUT** — обновление ресурса
   * **DELETE** — удаление ресурса
   * **PATCH** — для частичного изменения ресурса
   * **OPTIONS** — для описания параметров соединения с ресурсом
2. Поле для URL.
3. Кнопка для запуска запроса
4. Кнопка [редактирования переменных](/0.0.1-beta.14/variables/user-variables)

Ниже представлена панель редактирования заголовков, query параметров, авторизации и тела запроса. Так выглядит данная панель для POST запросов:

![Панель редактирования параметров запроса](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnLAHkLfKFdOIj3XQ%2Fr_5.png?alt=media\&token=3857f903-abe2-44a4-a91a-f03827d78c31)

Данная панель организована в виде вкладок. На данный момент существуют следующие вкладки:

* **Headers** - для редактирования списка HTTP-заголовков
* **Query parameters** - для редактирования списка query параметров
* **Body** - для конфигурирования тела запроса
* **Authorization** - для конфигурирования [авторизаций](/0.0.1-beta.14/work-with/authorization).
* **Other** - конфигурирование прочих параметров запроса

Вкладки **Headers** и **Query** parameters с точки зрения интерфейса очень похожи - это обычные таблицы с возможностью [массового редактирования](/0.0.1-beta.14/other/bulk-table-editing) и отключением строк. Отдельно стоит добавить, что заголовки поддерживают механизм установки [HTTP-заголовков по умолчанию](/0.0.1-beta.14/other/default-http-headers).&#x20;

Вкладка **Other** выглядит следующим образом:

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnPKjfaH4wV8iveo2%2Fr_6.jpg?alt=media\&token=88df025b-8b5b-4eb5-8949-05235399c0fb)

На данный момент можно отредактировать параметр **Requires SSL certificates be valid** - проверять валидность SSL-сертификата узла. Параметр по умолчанию: **Inherit**, наследует значение родителя узла, если у родителя задан Inherit, параметр выключен. Возможные варианты:

* Yes — да
* No — нет
* Inherit — наследовать

Отдельно остановимся на вкладке **Body**, которая выглядит следующим образом:

![Вкладка Body](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnT7hfXfRdavga1tf%2Fr_7.png?alt=media\&token=9b1dde6f-51f5-4248-8460-ed5e21f55ddf)

В выпадающем списке можно выбрать тип тела. На данный момент поддерживаются следующие типы

* **JSON** - для отправки JSON данных. Сами данные редактируются в текстовом поле с подсветкой JSON-синтаксиса и с поддержкой [механизма переменных](/0.0.1-beta.14/variables/user-variables) . При отправке запроса в список HTTP-заголовков добавляется заголовок `Content-Type` со значением `application/json` .
* **Form data** - для редактирования `multipart/form-data` форм. Имеет табличный вид с возможностью [массового редактирования](/0.0.1-beta.14/other/bulk-table-editing) . В строках таблицы в качестве значения могут выступать как обычные строки, так и ссылки на файлы.
* **Form URL encoded** - для редактирования `application/x-www-form-urlencoded` форм. Имеет табличный вид с возможностью [массового редактирования](/0.0.1-beta.14/other/bulk-table-editing) .
* **File** - для отправки в теле содержимое файла.
* **XML** - для отправки XML данных. Сами данные редактируются в текстовом поле с подсветкой XML-синтаксиса и с поддержкой [механизма переменных](/0.0.1-beta.14/variables/user-variables) . При отправке запроса в список HTTP-заголовков добавляется заголовок `Content-Type` со значением `application/xml` .
* **Text** - для отправки текстовых данных. Сами данные редактируются в текстовом поле с поддержкой [механизма переменных](/0.0.1-beta.14/variables/user-variables) . При отправке запроса в список HTTP-заголовков добавляется заголовок `Content-Type` со значением `text/plain` .

#### Секция конфигурирования ответа

Давайте выполним запрос на url <https://testmace-stage.herokuapp.com/posts> и посмотрим, как выглядит секция ответа:

![Секция ответа RequestStep узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnXC3T2KRgRyj96nm%2Fr_8.png?alt=media\&token=94f12efb-b450-4ce2-805b-76b4d2d24327)

Верхняя часть секции показывает краткую информацию об ответе: код ответа с указанием, успешный он или нет, время выполнения запроса и размер ответа.

Нижняя область секции ответа разбита на несколько вкладок:

* **Response body** - содержит тело ответа, представленное различными способами. На данный момент имеются следующие представления тела ответа:
  * **Parsed**- ответ в виде дерева. Каждый лист дерева имеет контекстное меню для создания [Assertion](/0.0.1-beta.14/node-types/assertion) узлов и для работы с [динамическими переменными](/0.0.1-beta.14/variables/user-variables/dynamic-variables)
  * **JSON** - JSON-подсветка тела ответа. Существует только в случае, когда тело ответа пришло в формате json.
  * **XML -** XML-подсветка тела ответа. Существует только в случае, когда тело ответа пришло в формате XML.
  * **HTML** - HTML-подсветка тела ответа. Показывается в случае, если тело ответа - HTML-страница
  * **Text** - текстовое представление тела ответа без подсветки&#x20;
  * **Preview** - отрендеренный вариант тела ответа. Показывается в случае, если тело ответа - HTML-страница
* **Response headers** - список HTTP-заголовков ответа
* **Assertions** - список assertion-ов, которые содержатся в дочернем [Assertion](/0.0.1-beta.14/node-types/assertion) узле.

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

**RequestStep** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат:

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Folder node",
      "const": "RequestStep",
      "type": "string"
    },
    "assignVariables": {
      "description": "List of variables assignments",
      "type": "array",
      "items": {
        "$ref": "#/definitions/AssignVariable"
      },
      "default": []
    },
    "requestData": {
      "$ref": "#/definitions/IRequestData"
    },
    "authData": {
      "$ref": "#/definitions/IAuthorizationData",
      "description": "Authorization parameters"
    },
    "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": [
    "assignVariables",
    "authData",
    "children",
    "name",
    "requestData",
    "type",
    "variables"
  ],
  "definitions": {
    "AssignVariable": {
      "type": "object",
      "properties": {
        "path": {
          "description": "Path in $response variable (e.g. body.id)",
          "type": "string"
        },
        "assign": {
          "$ref": "#/definitions/NodeReference",
          "description": "Link on target node (one of parents)"
        },
        "variable": {
          "description": "Name of dynamic variable in target node",
          "type": "string"
        }
      },
      "required": [
        "assign",
        "path",
        "variable"
      ]
    },
    "NodeReference": {
      "type": "object",
      "properties": {
        "refNodePath": {
          "description": "Absolute path to node",
          "type": "string"
        },
        "type": {
          "description": "Marker of reference entity",
          "const": "reference",
          "type": "string",
          "default": "reference"
        }
      },
      "required": [
        "refNodePath",
        "type"
      ]
    },
    "IRequestData": {
      "type": "object",
      "properties": {
        "request": {
          "description": "Common request parameters",
          "type": "object",
          "properties": {
            "method": {
              "$ref": "#/definitions/RequestMethod",
              "description": "HTTP-method"
            },
            "url": {
              "type": "string"
            }
          },
          "required": [
            "method",
            "url"
          ]
        },
        "params": {
          "description": "Query parameters",
          "type": "array",
          "items": {
            "$ref": "#/definitions/NameValueParam"
          }
        },
        "body": {
          "$ref": "#/definitions/IRequestBody",
          "description": "Body parameters"
        },
        "headers": {
          "description": "Headers",
          "type": "array",
          "items": {
            "$ref": "#/definitions/NameValueParam"
          }
        },
        "disabledInheritedHeaders": {
          "description": "Names of disabled headers",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "strictSSL": {
          "$ref": "#/definitions/StrictSSLOptions",
          "description": "Requires SSL certificates be valid"
        }
      },
      "required": [
        "body",
        "disabledInheritedHeaders",
        "headers",
        "params",
        "request",
        "strictSSL"
      ]
    },
    "RequestMethod": {
      "enum": [
        "DELETE",
        "GET",
        "OPTIONS",
        "PATCH",
        "POST",
        "PUT"
      ],
      "type": "string"
    },
    "NameValueParam": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "value": {
          "type": "string"
        },
        "isChecked": {
          "type": "boolean"
        }
      },
      "required": [
        "name",
        "value"
      ]
    },
    "IRequestBody": {
      "type": "object",
      "properties": {
        "type": {
          "$ref": "#/definitions/RequestBodyType",
          "description": "Type of body"
        },
        "jsonBody": {
          "description": "JSON string of body",
          "type": "string"
        },
        "xmlBody": {
          "description": "XML string of body",
          "type": "string"
        },
        "textBody": {
          "type": "string"
        },
        "formData": {
          "description": "multipart/form-data form",
          "type": "array",
          "items": {
            "$ref": "#/definitions/RequestStepFormData"
          }
        },
        "formURLEncoded": {
          "description": "application/x-www-form-urlencoded form",
          "type": "array",
          "items": {
            "$ref": "#/definitions/NameValueParam"
          }
        },
        "file": {
          "description": "Link on file, which will be used as a content for body",
          "type": "string"
        }
      },
      "required": [
        "file",
        "formData",
        "formURLEncoded",
        "jsonBody",
        "textBody",
        "type",
        "xmlBody"
      ]
    },
    "RequestBodyType": {
      "enum": [
        "File",
        "FormData",
        "FormURLEncoded",
        "Json",
        "Text",
        "Xml"
      ],
      "type": "string"
    },
    "RequestStepFormData": {
      "type": "object",
      "properties": {
        "type": {
          "$ref": "#/definitions/FormDataField"
        },
        "name": {
          "type": "string"
        },
        "value": {
          "type": "string"
        },
        "isChecked": {
          "type": "boolean"
        }
      },
      "required": [
        "name",
        "type",
        "value"
      ]
    },
    "FormDataField": {
      "enum": [
        "File",
        "Text"
      ],
      "type": "string"
    },
    "StrictSSLOptions": {
      "enum": [
        "Inherit",
        "No",
        "Yes"
      ],
      "type": "string"
    },
    "IAuthorizationData": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# Assertion

**Assertion** узел - это узел, используемый для написания тестов. Каждый **Assertion** узел состоит из набора **Assertion**-ов - минимальных проверок различных утверждений. При запуске **Assertion** узла запускается проверка всех **Assertion**-ов. Если хотя бы одна проверка завершится с ошибкой, то выполнение всего **Assertion** узла завершается с ошибкой.&#x20;

**Assertion** узел может быть создан только как потомок [RequestStep](/0.0.1-beta.14/node-types/requeststep) узла. Причем [RequestStep](/0.0.1-beta.14/node-types/requeststep) узел может имет не более одного **Assertion** узла в качестве потомка.

Создать **Assertion** узел можно следующими способами: из дерева проекта в контекстном меню [RequestStep](/0.0.1-beta.14/node-types/requeststep) узла выбрать **Add node** -> **Assertion.** Либо в секции ответа [RequestStep](/0.0.1-beta.14/node-types/requeststep) узла во вкладке Assertion выбрать **+ CREATE NEW ASSERTION NODE**.

![Создание Assertion узла из секции ответа RequestStep узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoAyRH5uUfa-eq257%2Fa_1.png?alt=media\&token=bda458cb-838e-44f8-87b9-4cabc2425757)

В дереве проекта **Assertion** узел выглядит следующим образом:

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoECui6mwoRgeIDAa%2Fa_2.png?alt=media\&token=ce954185-2048-4557-b0dd-35ac6614d0a6)

Если запуск **Assertion** узла завершился успешно, то в дереве он принимает следующий вид:

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoFN4dUZ4-U8wBQWU%2Fa_3.png?alt=media\&token=874f8bb4-745a-4f46-80af-d172edaf0a52)

В случае, если запуск **Assertion** узла завершился с ошибкой, узел выглядит так:

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoGOvC0j_WBuSxzC_%2Fa_4.png?alt=media\&token=547ed1ef-2d22-402c-aa71-881a39ec06c8)

В дереве для данного типа узла доступны следующие пункты меню:

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoHh5OEJ4MWR_Og86%2Fa_5.png?alt=media\&token=63b7b2f7-9e27-424b-844d-170bb011036e)

* **Remove node.** Удалить узел.
* **Run.** Запустить узел.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

Вкладка с **Assertion** узлом выглядит следующим образом:

![Интерфейс вкладки Assertion узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoJoMRGGK3Z5hgVkS%2Fa_6.png?alt=media\&token=821ff8a4-2406-4a59-b449-8ed75fcb380b)

На скрине отмечены следующие области:

1. Панель управления
2. Панель настроек выбранного **Assertion**-а
3. Список **Assertion**-ов

На панели управления расположены следующие кнопки

* **RUN** - запуск списка **Assertion**-ов
* **FIX ERRORS** - исправление ошибок **Assertion**-ов где это возможно. Данная кнопка активируется в случае, если есть ошибки в **Assertion**-ах. Функционал исправления ошибок описан в разделах **Исправление ошибок** каждого из **Assertion**-ов.
* **DISABLE ERRORS** - выключение **Assertion**-ов, завершившихся с ошибкой. Отключенные **Assertion**-ы не будут участвовать в дальнейших запусках. Данная кнопка активируется в случае, если есть ошибки в **Assertion**-ах
* **+ ADD ASSERTION** - добавление **Assertion** в список

Ниже панели управления находится список **Assertion**-ов. Каждый элемент в данном списке выглядит следующим образом:

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoO8cHyDJOa7RFj4v%2Fa_7.png?alt=media\&token=0c7d1f73-fc66-4239-89de-b0fccf2dad07)

На скрине отмечены следующие области:

1. Подсветка статуса. Если **Assertion** не запускался, то его цвет серый, если запуск завершился с ошибкой - красный, если успешно - зеленый.
2. Иконка конкретного типа **Assertion**-а
3. Краткое текстовое представление **Assertion**-а
4. Удалить **Assertion**
5. Задизейблить **Assertion**. При этом не будет участвовать в последующих запусках
6. Запустить **Assertion**
7. Исправить **Assertion**

Заметим, что контролы 4, 5, 6 и 7 появляются при наведении на **Assertion**.

Интерфейс панели настроек выбранного **Assertion**-а зависит от выбранного **Assertion**-а. В следующих разделах мы подробно разберем каждый из **Assertion**-ов

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

**Assertion** узел хранится в файле \<nodename>.yml, где \<nodename> - название Assertion-а и имеет следующий формат:

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Assertion node",
      "const": "Assertion",
      "type": "string"
    },
    "assertions": {
      "description": "List of assertions",
      "type": "array",
      "items": {
        "$ref": "#/definitions/AbstractAssertion"
      },
      "default": []
    },
    "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": [
    "assertions",
    "children",
    "name",
    "type",
    "variables"
  ],
  "definitions": {
    "AbstractAssertion": {
      "oneOf": [
        {
          "$ref": "#/definitions/CompareAssertion"
        },
        {
          "$ref": "#/definitions/ContainsAssertion"
        },
        {
          "$ref": "#/definitions/XPathAssertion"
        },
        {
          "$ref": "#/definitions/ScriptAssertion"
        }
      ]
    },
    "CompareAssertion": {
      "type": "object",
      "properties": {
        "type": {
          "description": "Type of Compare assertion",
          "const": "compare",
          "type": "string"
        },
        "actualValue": {
          "description": "Actual value",
          "type": "string",
          "default": "${$response.body}"
        },
        "operator": {
          "$ref": "#/definitions/CompareOperator",
          "description": "Operator",
          "default": "equal"
        },
        "expectedValue": {
          "description": "Expected value",
          "type": "string"
        },
        "disabled": {
          "type": "boolean",
          "default": false
        }
      },
      "required": [
        "actualValue",
        "disabled",
        "expectedValue",
        "operator",
        "type"
      ]
    },
    "CompareOperator": {
      "enum": [
        "equal",
        "greater",
        "greater or equal",
        "less",
        "less or equal",
        "not equal"
      ],
      "type": "string"
    },
    "ContainsAssertion": {
      "type": "object",
      "properties": {
        "type": {
          "description": "Type of Contains assertion",
          "const": "contains",
          "type": "string"
        },
        "text": {
          "description": "Text to be searched",
          "type": "string",
          "default": "${$response.body}"
        },
        "value": {
          "description": "Value for search in text",
          "type": "string"
        },
        "disabled": {
          "type": "boolean",
          "default": false
        }
      },
      "required": [
        "disabled",
        "text",
        "type",
        "value"
      ]
    },
    "XPathAssertion": {
      "type": "object",
      "properties": {
        "type": {
          "description": "Type of Xpath assertion",
          "const": "xpath",
          "type": "string"
        },
        "text": {
          "description": "Text to be searched",
          "type": "string",
          "default": "${$response.body}"
        },
        "path": {
          "description": "XPath selector",
          "type": "string"
        },
        "expectedValue": {
          "description": "Expected value",
          "type": "string"
        },
        "disabled": {
          "type": "boolean",
          "default": false
        }
      },
      "required": [
        "disabled",
        "expectedValue",
        "path",
        "text",
        "type"
      ]
    },
    "ScriptAssertion": {
      "type": "object",
      "properties": {
        "type": {
          "description": "Type of Script assertion",
          "const": "script",
          "type": "string"
        },
        "script": {
          "description": "Assertion script",
          "type": "string",
          "default": "`function test(assertion, variables) {\n  // It should return true if test is passed\n  // return true;\n}`"
        },
        "disabled": {
          "type": "boolean",
          "default": false
        }
      },
      "required": [
        "disabled",
        "script",
        "type"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# Compare

**Compare assertion** служит для сравнения 2 значений. В данном виде **Assertion**-а есть понятие компаратора - операции, с помощью которой сравниваются значения. Есть следующие виды компараторов:

* **equal** - проверка на равенство значений
* **not equal** - проверка на неравенство значений
* **greater** - проверка на то, что текущее значение больше ожидаемого
* **greater or equal** - проверка на то, что текущее значение больше ожидаемого или  равно ему
* **less** - проверка на то, что текущее значение меньше ожидаемого
* **less or equal** - проверка на то, что текущее значение меньше ожидаемого или равно ему

Интерфейс **Compare assertion**-а выглядит следующим образом:

![Интерфейс Compare assertion-а](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMoTO-UrojOGzKuxKG%2F-LiMohRm-BVZ3WRYmQ5b%2Fc_1.png?alt=media\&token=604e96de-005e-45da-9634-f06d9d4b7920)

На данном скрине имеются следующие поля:

* **Actual value** - текущее значение
* **Operator** - компаратор из списка выше
* **Expected value** - ожидаемое значение

### Исправление ошибок

Алгоритм исправления ошибок зависит от каждого конкретного компаратора.

* **equal** - ожидаемому значению присваивается текущее значение
* **not equal** - компаратор меняется на **equal**
* **greater** - компаратор меняется на **greater or equal** и ожидаемому значению присваивается текущее значение
* **greater or equal** - ожидаемому значению присваивается текущее значение
* **less** - компаратор меняется на **less or equal** и ожидаемому значению присваивается текущее значение
* **less or equal** - ожидаемому значению присваивается текущее значение

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

В файле **Assertion** имеет тип `compare` , описание самого типа можно найти в документации к [файловому представлению Assertion](/0.0.1-beta.14/node-types/assertion#failovoe-predstavlenie) в определении `#/definitions/CompareAssertion` .


# Contains

**Contains assertion** служит для проверки вхождения подстроки в строку.

Данный **Assertion** имеет следующий интерфейс:

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMoTO-UrojOGzKuxKG%2F-LiMqA9pfs2Sw3YF9An6%2Fco_1.png?alt=media\&token=04fc6a08-efc3-4c2d-b342-2f8a052db27e)

Данный **Assertion** имеет следующие поля:

* **Text** - текст, где будет производиться поиск
* **Value** - значение для поиска

### Исправление ошибок

У данного **Assertion**-а нет механизма исправления ошибок

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

В файле **Assertion** имеет тип `contains` , описание самого типа можно найти в документации к [файловому представлению Assertion](/0.0.1-beta.14/node-types/assertion#failovoe-predstavlenie) в определении `#/definitions/ContainsAssertion` .


# Script

**Script assertion** позволяет написать проверочный скрипт на языке JavaScript. Сам скрипт представляет из себя функцию с названием `test`, которая на вход принимает объект assertion-а и объект с переменными (в формате ключ-значение). В случае, если функция возвращает `true` считается, что проверка прошла успешно. Если функция возвращает `false` или бросает исключение, то считается, что запуск **Script assertion**-а завершился с ошибкой.

Данный **Assertion** имеет следующий интерфейс:

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMoTO-UrojOGzKuxKG%2F-LiMqKk9m74eiUK08Xya%2Fs_1.png?alt=media\&token=25a71ee8-bd27-4835-a4e4-bcbae852655e)

Данный **Assertion** имеет только одно поле - **script**, в котором находится скрипт из описания выше

### Исправление ошибок

У данного **Assertion**-а нет механизма исправления ошибок

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

В файле **Assertion** имеет тип `script` , описание самого типа можно найти в документации к [файловому представлению Assertion](/0.0.1-beta.14/node-types/assertion#failovoe-predstavlenie) в определении `#/definitions/ScriptAssertion` .


# XPath

**XPath assertion** позволяет проверить значение по XPath-селектору.

Данный **assertion** имеет следующий интерфейс:

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMoTO-UrojOGzKuxKG%2F-LiMqigZk5Cy3AUJ9gxl%2Fx_1.png?alt=media\&token=152c1fe3-8854-4f26-81c9-c2e4a381ce19)

**XPath assertion** имеет следующие поля:

* **Text** - текст, где будет производиться поиск
* **Path** - XPath селектор
* **Expected value** - ожидаемое значение по данному селектору

### Исправление ошибок

При исправлении ошибки в данном виде **Assertion**-а ожидаемому значению присваивается значение, лежащее по селектору.

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

В файле **Assertion** имеет тип `xpath` , описание самого типа можно найти в документации к [файловому представлению Assertion](/0.0.1-beta.14/node-types/assertion#failovoe-predstavlenie) в определении `#/definitions/XPathAssertion` .


# Link

Узел типа Link (ссылка) предназначен для повторно использования других узлов: RequestStep (включая Assertion) и сценариев (Folder).

## Принцип действия&#x20;

После выбора вызываемого узла, **Link** узел предоставляет возможность переопределить значения его переменных. **Link** узел вызывает исполнение другого узла, передавая ему заданные пользователем переменные. После выполнения, динамические переменные вызванного узла, устанавливаются как динамические переменные родительской группы **Link** узла. Таким образом результат выполнения доступен из любого соседствующего узла **Link**.

#### Из Link узла можно сослаться на:

* [RequestStep](/0.0.1-beta.14/node-types/requeststep) узел
* [Folder](/0.0.1-beta.14/node-types/folder) узел

#### Нельзя сослаться на:

* Другой **Link** узел (в том числе на самого себя)
* На любого предка **Link** узла (т.к. это вызовет при запуске бесконечный цикл)

{% hint style="info" %}
&#x20;Link узел предоставляет возможность переопределить значения переменных узла родителя.
{% endhint %}

{% hint style="warning" %}
При удалении узла, на который ссылается Link узел, ссылка будет считаться потерянной и запуск будет невозможен пока не будет указана корректная ссылка.
{% endhint %}

## Узел родитель

Создайте узел родитель, на который нужно ссылаться, и задайте ему необходимые [статически определяемые переменные](/0.0.1-beta.14/variables/user-variables/static-variables), например `postID`. Значение переменной можно не указывать.

![Создание переменных для узла родителя](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrUP_I2wt8JRAOTIo%2Fl_1.jpg?alt=media\&token=0ddded72-bae2-44e2-ace5-54b585876324)

## Узел Link

Создайте **Link** узел и укажите родителя, после этого отобразятся все созданные переменные родителя. В качестве переопределяемого значения можно использовать любые переменные или статическое значение.&#x20;

![Создание Link узла и выбор родителя](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrYUzKPma0ErHXhNj%2Fl_2.gif?alt=media\&token=23bd3e83-5b06-4164-8ab1-509f065511fc)

## Пример сценария

Рассмотрим пример, в котором, в качестве **Link** узла будем вызывать [RequestStep](/0.0.1-beta.14/node-types/requeststep) узел для удаления записи.

### Создание узла родителя

1. Создайте [RequestStep](/0.0.1-beta.14/node-types/requeststep) узел с именем **deletePost**
2. Тип запроса DELETE
3. В качестве URL используйте[ https://testmace-stage.herokuapp.com/posts/${id}](< https://testmace-stage.herokuapp.com/posts/${id}>)
4. Создайте для этого узла [статически определяемую переменную](/0.0.1-beta.14/variables/user-variables/static-variables) `id` с пустым значением

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrbQNUc1uEfXxWXb-%2Fl_3.gif?alt=media\&token=ac7a97bf-ebec-446b-9572-9ed1fc258634)

### Создание сценария

* Создайте [Folder](/0.0.1-beta.14/node-types/folder) узел с именем **scenario**
* Добавьте в scenario[ RequestStep](/0.0.1-beta.14/node-types/requeststep) узел с именем **createPost**:&#x20;
  * тип запроса: POST
  * URL: [https://testmace-stage.herokuapp.com/posts/](< https://testmace-stage.herokuapp.com/posts/${id}>)
  * body запрос JSON `{"title":"will delete with link node"}`
  * Выполняем запрос и присваиваем `id` созданной записи [динамической переменной](/0.0.1-beta.14/variables/user-variables/dynamic-variables) postId для узла **Scenario**.

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrcoO2XM6ONc0CZsH%2Fl_4.gif?alt=media\&token=fd36a09f-0266-4ecf-9707-1031a711d9af)

* Далее создаем **Link** узел с именем **deleteLink**
  * В качества родителя указываем узел **project/deletePost**
  * Для переменной `id` родителя **deletePost** в Link узле указываем Overridden Value `${$dynamicVar.postId}`
* Создадим [RequestStep](/0.0.1-beta.14/node-types/requeststep) узел **checkIfExists** для проверки удаления записи
  * Тип запроса: GET
  * URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>
  * Ожидаемый ответ сервера 404.

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrduTdT4bc9kgalMN%2Fl_5.gif?alt=media\&token=3120d7e1-b3b8-4f45-be2a-520e55e855f9)

## Пример проект для импорта [через URL](/0.0.1-beta.14/other/import/shared)

{% file src="/files/-LiMr55F1c6QspuvzbcH" %}

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

**Link** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат.

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Link node",
      "const": "Link",
      "type": "string"
    },
    "linkedNode": {
      "$ref": "#/definitions/NodeReference",
      "description": "Link to node"
    },
    "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",
    "linkedNode",
    "name",
    "type",
    "variables"
  ],
  "definitions": {
    "NodeReference": {
      "type": "object",
      "properties": {
        "refNodePath": {
          "description": "Absolute path to node",
          "type": "string"
        },
        "type": {
          "description": "Marker of reference entity",
          "const": "reference",
          "type": "string",
          "default": "reference"
        }
      },
      "required": [
        "refNodePath",
        "type"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# API description

TestMace имеет мощный функционал описания API, включая импорта из Swagger 2.0/ Openapi  3.0. Реализован данный функционал посредством следующих узлов:

* [ApiRootFolder](/0.0.1-beta.14/node-types/api-description/apirootfolder) - корневой узел описания API
* [ApiFolder](/0.0.1-beta.14/node-types/api-description/apifolder) - узел для группировки других узлов API
* [ApiRoute](/0.0.1-beta.14/node-types/api-description/apiroute) - узел для описания конкретного эндпоинта

В следующих разделах мы подробнее познакомимся с функцией каждого из данных узлов


# ApiRootFolder

**ApiRootFolder** - это корневой узел поддерева описания API. Он, по аналогии с [Project](/0.0.1-beta.14/node-types/project) узлом, является корневым элементом, и в пределах поддерева описания API может быть может быть только один элемент данного типа. В остальном повторяет функционал [ApiFolder](/0.0.1-beta.14/node-types/api-description/apifolder) узла.

Создать данный узел можно одним из следующих способов

* Из контекстного меню [Project](/0.0.1-beta.14/node-types/project) узла
* Воспользовавшись импортом из форматов описания API

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

**ApiRootFolder** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат:

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of ApiRootFolder node",
      "const": "ApiRootFolder",
      "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",
    "type",
    "variables"
  ],
  "definitions": {
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# ApiFolder

**ApiFolder** узел, по аналогии с [Folder](/0.0.1-beta.14/node-types/folder) узлом, служит для группировки других типов узлов (в данном случае [ApiRoute](/0.0.1-beta.14/node-types/api-description/apiroute) узлов). &#x20;

Создать данный узел можно следующими способами:

* Из контекстного меню [ApiRootFolder](/0.0.1-beta.14/node-types/api-description/apirootfolder) узла
* Воспользовавшись импортом из форматов описания API

В дереве проекта **ApiFolder** узел имеет следующий вид:

![Вид ApiFolder узла в дереве проекта](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsBurAEw8jjEkJrtf%2Faf_1.png?alt=media\&token=680ed8d0-b230-4c56-a2fd-6dc021bb00fe)

Контекстное меню данного узла выглядит следующим образом:

![Контекстное меню ApiFolder узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsEDI1oLvGTZfTmYQ%2Faf_2.png?alt=media\&token=1cf07376-2887-4c2d-9ac9-90c413997f7d)

* **Add node.** Добавление узла-потомка. В подменю можно выбрать тип узла.
* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название NodeName \[Copy \[number]].
* **Remove node.** Удалить узел.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

Интерфейс вкладки данного узла выглядит следующим образом:

![Интерфейс вкладки ApiFolder узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsHryxF8VAVuXeS0_%2Faf_3.png?alt=media\&token=736707f8-b932-4edd-a1f4-51aa787cf8de)

На данном скрине отмечены следующие области

* Диалог управления [пользовательскими переменными](/0.0.1-beta.14/variables/user-variables)
* Список дочерних узлов

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

**ApiFolder** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат:

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of ApiFolder node",
      "const": "ApiFolder",
      "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",
    "type",
    "variables"
  ],
  "definitions": {
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# ApiRoute

Данный узел служит для описания интерфейса конкретного эндпоинта. Интерфейс схож с [RequestStep](/0.0.1-beta.14/node-types/requeststep) узлом. Это и не удивительно - в обоих случаях мы имеем дело с HTTP-запросами.

Основные возможности данного типа узлов:

* Возможность описания http-заголовков, query параметров, body параметров запроса и HTTP-кодов, HTTP-заголовков, body параметров ответа
* Использование типов для описания каждого из заголовков, query параметров, body параметров. Поддерживаются следующие типы: `string`, `number`, `integer`, `boolean`, `array` и `object`.
* Добавление описаний для каждой из сущностей
* Поддержка описания нескольких параметров тела запроса (в зависимости от content-type)
* Поддержка описания нескольких возможный ответов от сервера
* Создание запроса из описания
* Автодополнение урлов, HTTP-заголовков, query параметров и body параметров в [RequestStep](/0.0.1-beta.14/node-types/requeststep) узлах.

## Обзор интерфейса

Для создание **ApiRoute** узла необходимо в контекстном меню [ApiFolder](/0.0.1-beta.14/node-types/api-description/apifolder) узла выбрать **Add node** -> **ApiRoute.**

### **Вид узла в дереве проекта**

В дереве **ApiRoute** узел выглядит следующим образом:

![Вид ApiRoute узла в дереве проекта](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsjdLErhFxCQUpVzR%2Far_1.png?alt=media\&token=21b635ae-a97e-4358-b8f2-c2c95028108c)

В качестве иконки у данного вида узла выступает название HTTP-метода. Контекстное меню выглядит следующим образом:

![Контекстное меню ApiRoute узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMslz8Y5XicOHnnV8p%2Far_2.png?alt=media\&token=faa4b280-b90e-4ec8-911f-8080e90ce282)

* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название NodeName \[Copy \[number]].
* **Remove node.** Удалить узел.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

### Интерфейс вкладки

Вкладка **ApiRoute** узла выглядит следующим образом:

![Вкладка ApiRoute узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMspLCONT78JfocOc6%2Far_3.png?alt=media\&token=a997d9f9-afcf-4903-bb20-8fd792925559)

#### Области общих параметров запроса

Рассмотрим подробнее верхнюю часть данной вкладки:

![Верхняя часть таба ApiRoute узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsscrBJx53fsqf00u%2Far_4.png?alt=media\&token=8029abe1-0053-409c-a01d-1c769ce21204)

На скрине обозначены следующие области:

1. Http-метод. Данный список совпадает со списком методов из [RequestStep](/0.0.1-beta.14/node-types/requeststep) узла
2. Url с поддержкой [механизма переменных](/0.0.1-beta.14/variables/variables)
3. Кнопка открытия [диалога работы с переменными](/0.0.1-beta.14/variables/user-variables)
4. Кнопка создания запроса из текущего описания API
5. Текстовое описание запроса

#### Область описания параметров запросов

В левой нижней части расположена область описания запроса. Она разделена на 3 вкладки: **Headers**, **Query parameters** и **Body** для редактирования HTTP-заголовков, query параметров и параметров тела запроса соответственно.

Рассмотрим вкладку **Headers**. Ее содержимое представлено в табличном виде. Для редактирования заголовков доступны следующие поля:

* Название заголовка
* Тип значения заголовка (список типов описан выше)
* Описание

Поддерживаются все стандартные операции.

Вкладка **Query Parameters** используется для редактирования query параметров, в остальном по функционалу идентична вкладке **Headers**.

Как уже было сказано, в **ApiRoute** узле можно описать несколько тел для одного и того же запроса. Например, по одному и тому же эндпоинту могут приниматься как данные с `Content-Type` равным `application/json`, так и с `application/xml`. Вкладка **Body** разделена как раз по `content-type` на вкладки и имеет следующий вид:

![Вид вкладки Body интерфейса описания запроса](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsvmecyriXA8KhPQP%2Far_5.png?alt=media\&token=10f32ea0-49d8-49ae-8473-8d94a367ad3e)

На скрине отмечены следующие области:

1. Кнопка редактирования текущего `content-type`. При нажатии на нее данное поле подменяется на текстовое поле, где можно ввести интересующий `content-type`.
2. Кнопка удаления тела запроса
3. Кнопка добавления тела запроса
4. Текущий `content-type` узла
5. Область редактирования тела запроса

Область редактирования тела запроса меняется в зависимости от `content-type` по следующему правилу: если `content-type` равен `application/x-www-form-urlencoded` или `multipart/form-data`, то область редактирования принимает табличный вид (аналогичный табличной области в **Headers** вкладке), в противном случае - текстовый как на скрине выше. В текстовой области в качестве формата описания используется [OpenAPI](https://swagger.io/specification/#requestBodyObject).

#### Область описания параметров запросов

В правой нижней области интерфейса вкладки **ApiRoute** узла расположена области редактирования ответов от сервера. Как уже было сказано, TestMace поддерживает описание нескольких ответов в рамках одного эндпоинта. Интерфейс данной области выглядит следующим образом:

![Интерфейс редактирования ответов сервера](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMszNK7ApEdzbaBel_%2Far_6.png?alt=media\&token=b6ff2068-1344-4527-95e0-71d17a081074)

Данный интерфейс разделен на вкладки, отдельно для каждого ответа. В рамках вкладки каждого ответа можно редактировать код ответа, описание, а также HTTP-заголовки и тела ответа, интерфейсы которых идентичны таковым из области запроса.

## Интеграция с RequestStep узлом

TestMace имеет интеграцию с **ApiRoute** узлами в **RequestStep** узлах. На данный момент эта интеграция проявляется в автодополнении url, HTTP-заголовков, query параметров, параметров тела запросов **RequestStep** узлов. Причем, для url-ов в автодополнении участвуют всех url-ы **ApiRoute** узлов, тогда как для остальных параметров автодополнение работает по следующему алгоритму:

* Берутся метод и url данного **RequestStep** узла
* Ищутся все **ApiRoute** узлы с такими url и методом
* Осуществляется поиск по искомому параметру (например, по HTTP-заголовку) среди найденных **ApiRoute** узлов

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

**ApiRoute** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат.

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of ApiRoute node",
      "const": "ApiRoute",
      "type": "string"
    },
    "url": {
      "type": "string",
      "default": ""
    },
    "method": {
      "$ref": "#/definitions/RequestMethod"
    },
    "description": {
      "type": "string",
      "default": ""
    },
    "requests": {
      "$ref": "#/definitions/ApiRequests",
      "description": "List of requests"
    },
    "responses": {
      "description": "List of responses",
      "type": "array",
      "items": {
        "$ref": "#/definitions/ResponseParameters"
      },
      "default": []
    },
    "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",
    "description",
    "method",
    "name",
    "requests",
    "responses",
    "type",
    "url",
    "variables"
  ],
  "definitions": {
    "RequestMethod": {
      "enum": [
        "DELETE",
        "GET",
        "OPTIONS",
        "PATCH",
        "POST",
        "PUT"
      ],
      "type": "string"
    },
    "ApiRequests": {
      "type": "object",
      "properties": {
        "queryParameters": {
          "description": "List of query parameters",
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "headers": {
          "description": "List of headers",
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "cookies": {
          "description": "List of cookies",
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "bodies": {
          "description": "List of bodies",
          "type": "array",
          "items": {
            "$ref": "#/definitions/RequestParameters"
          },
          "default": []
        }
      },
      "required": [
        "bodies",
        "cookies",
        "headers",
        "queryParameters"
      ]
    },
    "QueryParameter": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "type": {
          "enum": [
            "array",
            "boolean",
            "integer",
            "number",
            "object",
            "string"
          ],
          "type": "string"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "name",
        "type"
      ]
    },
    "RequestParameters": {
      "type": "object",
      "properties": {
        "contentType": {
          "type": "string"
        },
        "schema": {
          "anyOf": [
            {
              "$ref": "#/definitions/SchemaRef"
            },
            {
              "$ref": "#/definitions/OneOf"
            },
            {
              "$ref": "#/definitions/AllOf"
            },
            {
              "$ref": "#/definitions/AnyOf"
            },
            {
              "$ref": "#/definitions/ObjectMember"
            },
            {
              "$ref": "#/definitions/ArrayMember"
            },
            {
              "$ref": "#/definitions/ScalarMember"
            }
          ]
        }
      },
      "required": [
        "contentType",
        "schema"
      ]
    },
    "SchemaRef": {
      "type": "object",
      "properties": {
        "$ref": {
          "type": "string"
        }
      },
      "required": [
        "$ref"
      ]
    },
    "OneOf": {
      "type": "object",
      "properties": {
        "oneOf": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/SchemaRef"
              },
              {
                "$ref": "#/definitions/OneOf"
              },
              {
                "$ref": "#/definitions/AllOf"
              },
              {
                "$ref": "#/definitions/AnyOf"
              },
              {
                "$ref": "#/definitions/ObjectMember"
              },
              {
                "$ref": "#/definitions/ArrayMember"
              },
              {
                "$ref": "#/definitions/ScalarMember"
              }
            ]
          }
        }
      },
      "required": [
        "oneOf"
      ]
    },
    "AllOf": {
      "type": "object",
      "properties": {
        "allOf": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/SchemaRef"
              },
              {
                "$ref": "#/definitions/OneOf"
              },
              {
                "$ref": "#/definitions/AllOf"
              },
              {
                "$ref": "#/definitions/AnyOf"
              },
              {
                "$ref": "#/definitions/ObjectMember"
              },
              {
                "$ref": "#/definitions/ArrayMember"
              },
              {
                "$ref": "#/definitions/ScalarMember"
              }
            ]
          }
        }
      },
      "required": [
        "allOf"
      ]
    },
    "AnyOf": {
      "type": "object",
      "properties": {
        "anyOf": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/SchemaRef"
              },
              {
                "$ref": "#/definitions/OneOf"
              },
              {
                "$ref": "#/definitions/AllOf"
              },
              {
                "$ref": "#/definitions/AnyOf"
              },
              {
                "$ref": "#/definitions/ObjectMember"
              },
              {
                "$ref": "#/definitions/ArrayMember"
              },
              {
                "$ref": "#/definitions/ScalarMember"
              }
            ]
          }
        }
      },
      "required": [
        "anyOf"
      ]
    },
    "ObjectMember": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "object"
          ]
        },
        "properties": {
          "$ref": "#/definitions/SchemaMember"
        },
        "required": {
          "type": "boolean"
        },
        "additionalProperties": {
          "$ref": "#/definitions/ScalarMember"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "SchemaMember": {
      "type": "object",
      "additionalProperties": {
        "anyOf": [
          {
            "$ref": "#/definitions/SchemaRef"
          },
          {
            "$ref": "#/definitions/OneOf"
          },
          {
            "$ref": "#/definitions/AllOf"
          },
          {
            "$ref": "#/definitions/AnyOf"
          },
          {
            "$ref": "#/definitions/ObjectMember"
          },
          {
            "$ref": "#/definitions/ArrayMember"
          },
          {
            "$ref": "#/definitions/ScalarMember"
          }
        ]
      }
    },
    "ArrayMember": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "array"
          ]
        },
        "items": {
          "anyOf": [
            {
              "$ref": "#/definitions/SchemaRef"
            },
            {
              "$ref": "#/definitions/OneOf"
            },
            {
              "$ref": "#/definitions/AllOf"
            },
            {
              "$ref": "#/definitions/AnyOf"
            },
            {
              "$ref": "#/definitions/ObjectMember"
            },
            {
              "$ref": "#/definitions/ArrayMember"
            },
            {
              "$ref": "#/definitions/ScalarMember"
            }
          ]
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "items",
        "type"
      ]
    },
    "ScalarMember": {
      "type": "object",
      "properties": {
        "type": {
          "$ref": "#/definitions/ScalarSchemaType"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "ScalarSchemaType": {
      "enum": [
        "boolean",
        "integer",
        "number",
        "string"
      ],
      "type": "string"
    },
    "ResponseParameters": {
      "type": "object",
      "properties": {
        "code": {
          "description": "Http-code (e.g. 200, 404)",
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "headers": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "content": {
          "$ref": "#/definitions/RequestParameters",
          "description": "Response body"
        }
      },
      "required": [
        "code",
        "content"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# Импорт описания API

TestMace позволяет не только вручную задокументировать API, но и импортировать уже существующую документацию. На данный момент поддерживается импорт из форматов Swagger 2.0 и OpenAPI 3.0.

Импортировать описание API можно из контекстного меню + проекта, выбрав **Import** -> **Swagger** (аналогичное меню есть и в области Scratches):

![Контекстное меню проекта](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMtKQIIq4b8Y7FT7Wb%2Fim_1.png?alt=media\&token=f5de1b2d-6c5d-4a97-9ef0-bbb3d6ebaeb4)

При этом открывается диалог следующего вида:

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMtMyJHFHO5eoh25UQ%2Fim_2.png?alt=media\&token=2b3fb94a-3346-4a9d-9898-a0ce07d24361)

Как видите, на данный момент поддерживается как импорт из файла, так и загрузка API с удаленного сервера по URL. После выбора источника и нажатия на кнопку **OK** в дерево добавляется импортированное описание.

### Обновление описания API

Помимо загрузки описания API, можно также обновить уже существующие описание API . Для этого из контекстного меню [ApiRootFolder](/0.0.1-beta.14/node-types/api-description/apirootfolder) узла необходимо выбрать **Update api.** При этом откроется диалог как при импорте API. Стоит отметить, что все изменения в описании API, сделанные вручную, будут перетерты после обновления.


# Broken

При открытии проекта могут возникнуть ситуации, когда некоторые узлы не могут быть загружены. Примером такой ситуации является наличие merge конфликтов. В таких случаях проект загружает все возможные узлы, однако после открытия проекта пользователю показывается такое предупреждение:

![Предупреждение в случае наличия в проекте незагруженных узлов](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMte0JJQ45gAj9tq8k%2Fb_1.png?alt=media\&token=aa82e45e-4b0c-4c57-8cf7-87ca7db22450)

А в загруженном проекте появляются такие узлы:

![Вид Broken узла в дереве](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMtisxrwZeSwW-Wbb8%2Fb_2.png?alt=media\&token=cfa3609b-a880-4fdb-825b-96367bdec0d2)

Это **Broken** узел. Он не может быть создан вручную, а появляется, если при загрузке определенного узла произошли ошибки. Контекстное меню данного узла выглядит следующим образом:

![Контекстное меню Broken узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMtlMptczUpzeTB5vN%2Fb_3.png?alt=media\&token=2f0882f2-0ce7-4e62-94f4-16f8060f4d17)

* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

**Broken** узел не может быть открыть во вкладке и не от него нельзя создать каких-либо потомков. Основное предназначение - помочь пользователю исправить ошибку.


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


# Пользовательские переменные

Раздел “Переменные” - это key-value хранилище для сохранения и повторного использования каких-либо данных. Зачастую используется для удаления дублирования и повышения читаемости: согласитесь, переменная с названием greetingUrl говорит о большем, чем просто строка <https://next.json-generator.com/api/json/get/EJvQVEVGL>.

Механизм переменных очень хорошо интегрирован во все части приложения и обладает следующими особенностями:

* Значения переменных могут быть строками, объектами и массивами и содержать ссылки на другие переменные.
* Переменные задаются для каждого узла и наследуются от узлов родителей.
* Значение переменных может ссылаться на другие переменные.
* Имена [встроенных переменных](/0.0.1-beta.14/variables/variables) начинаются с $.

### Использование переменных

Использовать переменные можно в любых строковых параметрах узлов. Примерами таких параметров могут служить url, название заголовка, токен авторизации и многое многое другое. Для того, чтобы использовать переменную необходимо использовать следующий формат `${variableName}`, где `variableName` - это ссылка на переменную. Вот несколько примеров.

* `${id}`
* `${$dynamicVar.id}`
* `${$response.body.name}`

В полях параметров узлов можно комбинировать строки и ссылки на переменные. Например, в качестве url вы можете использовать следующую строку `http://${host}/posts/${$dynamicVar.id}`

Для обращения к элементу массива, которых сохранен в переменной, можно воспользоваться следующим синтаксисом `${variableName[index]}` . Например, для обращения к id третьей сущности из ответа необходимо написать `${$response.body[2].id}` . Обратите внимание, что индексация начинается с нуля.&#x20;

Для переменных работает автодополнение

![Автодополнение переменных](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMuFFKgZGs5cuIEhIy%2Fuv_1.gif?alt=media\&token=8c92811d-3c4f-48b8-a6d6-79a92b0aca68)

и подсветка значения переменной при наведении на нее

![Подсветка значения переменной](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMuIDuHPhY4ieNJGmf%2Fuv_2.png?alt=media\&token=4dc3116c-e6dd-4a31-9adc-04aca846f866)

В интерфейсе каждого узла есть кнопка variables с помощью которой вызывается диалог  переменных. Выглядит данная кнопка следующим образом:

![Кнопка открытия диалога переменных](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMuLP7hf6Kl1GHtlIx%2Fuv_3.png?alt=media\&token=4eccb436-af9f-4405-b44e-af200e6dd516)

Данная кнопка существует выглядит одинаково для всех типов узлов. В следующих разделах мы подробнее рассмотрим механизм работы с переменными.


# Статически определяемые переменные

Пользователь имеет возможность определять собственные переменные, которые привязываются к определенному узлу. Названия переменных не могут начинаться с символа $ т.к. в соответствии с соглашением данный формат зарезервирован для [встроенных переменных](/0.0.1-beta.14/variables/variables). Также механизм переменных поддерживает наследование переменных от предков и переопределение их в потомках.

Для редактирования переменных необходимо вызвать [диалог переменных](/0.0.1-beta.14/variables/user-variables). Во вкладке Variables вы можете увидеть таблицу переменных, принадлежащих только данному узлу. Вкладка выглядит следующим образом:

![Диалог редактирования пользовательских переменных](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMudFmHEnWhUGdjgqS%2Fs_1.png?alt=media\&token=890c90d6-bfbd-4d11-bff4-12cf95f3b3ff)

В значении переменных можно также обращаться к другим переменным. Использую переменные, пример выше можно представить следующим образом:

![Использование ссылок на переменные при определении значений переменных](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMufFtsw7xs5ywiCey%2Fs_2.png?alt=media\&token=64bd4818-7285-4e13-8828-4aa677eb907d)


# Динамические переменные

Динамические переменные - это переменные, значения которых определяются во время выполнения сценария. Сохранение авторизационных токенов, идентификаторов вновь созданных сущностей - вот яркие варианты использования данного механизма. Он состоит их двух частей - Variable assignment и собственно динамических переменных.

### Variable assignment

Это создание привязки части запроса к какой-либо динамической переменной. На данный момент данную привязку можно сделать только в [RequestStep](/0.0.1-beta.14/node-types/requeststep) узле. Для иллюстрации давайте создадим запрос который создает новый пост и сохраним id созданного постав в динамическую переменную.

Создаем запрос и выполняем его. К примеру, давайте сделаем запрос на POST <https://testmace-stage.herokuapp.com/posts>, с телом `{"title":"Our cool post!"}` . В данном случае RequestStep узел выглядит так:

![RequestStep после выполнения запроса](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMv1-_1PBbcv_9qnro%2Fd_1.png?alt=media\&token=40002d5b-a894-46e1-a0a5-96996fb0b052)

Теперь из parsed response на параметр id из контекстного меню вызовем диалог присваивания динамической переменной.

![Вид контекстного меню](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMv3_gPF04RLw6OEjw%2Fd_2.png?alt=media\&token=d07e0d86-2652-4cf0-96f7-7bb7f743b1e6)

Выберем пункт Assign to variable. Откроется диалог присваивания переменной

![Диалог присвоения динамической переменной](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMv6iwCGaSI3xglCyW%2Fd_3.png?alt=media\&token=7f0cc565-89f7-491e-9a5f-59529ed51285)

В данном диалоге отмечены следующие пункты

1. Путь в переменной `$request`, из которого будет браться значение
2. Выпадающий список предков, которым можно назначить динамическую переменную
3. Текущее значение по данному пути
4. Название динамической переменной

Создадим переменную с именем `id` в данном узле.

После присвоения динамической переменной ее можно найти в списке динамических переменных того узла, где производилось присвоение, т.е, в [RequestStep](/0.0.1-beta.14/node-types/requeststep) узле. Список динамических переменных можно найти в [диалоге переменных](/0.0.1-beta.14/variables/user-variables) на вкладке Dynamic variables.

![Список динамических переменных RequestStep узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMv9b3IDvlZpwkDk_M%2Fd_4.png?alt=media\&token=01d78d68-b1ce-4c00-aaad-e4a879f43c4d)

### Использование динамических переменных

Все динамические переменные, доступные для конкретного узла, хранятся в переменной `$dynamicVar`. Например, чтобы сослаться на переменную `id`, созданную выше, необходимо написать `$dynamicVar.id`. Как и в случае с другими переменными, данный вид переменных поддерживает наследование и переопределение в потомках.


# Встроенные переменные

Встроенные переменные - это переменные специального назначения, которые нельзя переопределить. Использовать их можно также, как и обычные переменные.

* `$parent` - ссылка на узел-предка
* `$prevStep` - ссылка на предыдущий узел в рамках [Folder](/0.0.1-beta.14/node-types/folder) узла
* `$nextStep` - ссылка на следующий узел в рамках [Folder](/0.0.1-beta.14/node-types/folder) узла
* `$dynamicVar` - объект [динамических переменных](/0.0.1-beta.14/variables/user-variables/dynamic-variables)
* `$response` - ссылка на response в [RequestStep узле](/0.0.1-beta.14/node-types/requeststep)
* `$env` - объект [переменных окружения](/0.0.1-beta.14/variables/env)
* `$systemVar`- объект для доступа к системным переменным окружения


# Переменные окружения

Позволяют в один клик переключать значения переменных используемых в проекте.

Механизм переменных окружения позволяет создавать переключаемые переменные, например, для переключения **stage** и **prod** сред.

### Создание переменных окружения

В примере мы создадим одну переменную serverUrl для сред stage и prod.

1. Нажмите на значок настройки переменных окружения.
2. Во всплывающем окне создайте новое окружение нажав на "Add enviroment" с именем stage.
   * Создайте переменную serverUrl, в качестве значения переменной укажите адрес stage сервера.
3. Добавьте prod окружение  нажав на "Add enviroment".
   * Создайте переменную serverUrl, в качестве значения переменной укажите адрес prod сервера.

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMvdgtIENqEafXv0x-%2Fenv_1.gif?alt=media\&token=3f0b2a72-b1d3-446c-991a-96c7efa57d58)

### Импорт окружения из Postman

TestMace позволяет импортировать окружения из [Postman](https://learning.getpostman.com/docs/postman/environments_and_globals/manage_environments/). Для этого необходимо нажать на кнопку **+ Import environment**, которая находится в диалоге редактирования переменных окружения под списком доступных окружений

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_qpPCSEz_TL29pZRd%2F-Ll_tGF0qb6nQSiMCCSs%2FKSpgFN9.png?alt=media\&token=f5339d86-8a8c-4423-a937-d278967bbf1d)

После нажатия на кнопку **+ Import environment** всплывает диалог, в котором необходимо ввести путь до файла.&#x20;

### Использование переменных окружения

Для использования переключаемых переменных обращайтесь к`${$env.%VARIABLE%}.`Заменим во всех узлах значение url нашей переменной:`${$env.serverUrl}` Теперь в любой момент, вы можете переключить значения этой переменной.

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMvepOZAOjDp9BnQy0%2Fenv_2.gif?alt=media\&token=da5b25f7-2f1d-447a-8d70-eaa9179e3037)

#### Где можно использовать переменные?

Переменные окружения (также, как и обычные переменные) можно использовать в любом строковом поле узла.

### Локальные окружения

Локальные окружения отличаются от обычных только тем, что не сохраняются в файлы проекта, а хранятся в локальном хранилище приложения. Данный вид окружений рекомендуется использовать для локальных и приватных данных. К таким данным могут относиться логины, пароли, API-токены и т.д.&#x20;

В сайдбаре локальные окружения находятся в нижней части. Каждое локальное окружение имеет  префикс `local`, чтобы явно отличать их от обычных окружений.

![Диалог переменных окружения с локальными окружениями](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LmEwBwnJ7PFKqey4cJE%2F-LmEzXkrXXuni1wYU0a0%2Fscreenshot_2.png?alt=media\&token=35902c45-5c10-4334-bc79-2cebcfde5968)

Используя механизм drag-and-drop локальные окружения можно превращать в обычные и наоборот.

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LmEwBwnJ7PFKqey4cJE%2F-LmF-6mF5bOdlv_y0aEc%2FPeek%202019-08-14%2016-00.gif?alt=media\&token=09236135-fc0e-4dd0-90f9-8f5a08e8bdf8)


# Cookie

Cookie  — небольшой фрагмент данных, который отправляется веб-сервером и хранится на компьютере пользователя.

## Создание Cookie

TestMace позволяет управлять Cookie для хостов. Нажмите на кнопку "Cookie" в верхнем меню для вызова модального окна настройки Cookie. Откроется список всех существующих записей, для создания новой нажмите кнопку add и заполните поля:

|    Тип поля   | Значение                                                                                                                                             |
| :-----------: | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|    **Key**    | Имя cookie                                                                                                                                           |
|   **Value**   | Значение cookie                                                                                                                                      |
|   **Domain**  | Устанавливает домен, в рамках которого действует cookie                                                                                              |
|    **Path**   | Устанавливает путь на сайте, в рамках которого действует cookie                                                                                      |
|  **Expires**  | Устанавливает дату истечения срока хранения cookie. Дата должна быть представлена в формате, который возвращает метод `toGMTString()` объекта `Date` |
|   **Secure**  | Отмеченный селектор указывает, что для пересылки cookie на сервер следует использовать SSL                                                           |
| **Http only** | Отмеченный селектор только для тех cookie, к которым не требуется обращаться через JavaScript.                                                       |

Так же имеется возможность создания Cookie из row string, например:

`isLogged=1; Expires=31/12/2019 00:00:00; Domain=testmace-stage.herokuapp.com; Path=/posts/; Secure;`

![Создание Cookie](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMvpzdt46slJDWDMiT%2F-LiMwA-ywJWH809fT6CZ%2Fcoo_1.jpg?alt=media\&token=531eae1f-1bfd-4b15-9610-41a272dc11b1)

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

Запланировано в следующем релизе.

## Удаление Cookie

Откройте окно управления Cookie и нажмите на символ корзины напротив записи подлежащей удалению.

![Удаление Cookie](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMvpzdt46slJDWDMiT%2F-LiMwEE6tBK7J9cf34nj%2Fcoo_2.jpg?alt=media\&token=455b4851-6dd6-4b38-8f93-7a21dc1ca970)


# Авторизация

Проверка, что вам разрешен доступ к запрашиваемому ресурсу.

## Типы авторизации

* [No auth ](/0.0.1-beta.14/work-with/authorization#no-auth)
* [Inherit from parent ](/0.0.1-beta.14/work-with/authorization#inherit-from-parent)
* [Basic auth ](/0.0.1-beta.14/work-with/authorization#basic-auth)
* [Bearer auth](/0.0.1-beta.14/work-with/authorization#bearer-auth)&#x20;
* [Digest Auth ](/0.0.1-beta.14/work-with/authorization#digest-auth)
* [OAuth 1.0](/0.0.1-beta.14/work-with/authorization#oauth-1-0)

{% hint style="info" %}
В качестве параметров авторизации: Username, Password, Token и др. можно использовать [переменные окружения](/0.0.1-beta.14/variables/env).
{% endhint %}

## No auth&#x20;

Используйте «No Auth», если для отправки запроса не нужна авторизация.

## Inherit from parent&#x20;

**Значение по умолчанию**, свойства авторизации наследуются от узла родителя. Если параметры авторизации не заданы у родителя будет использоваться тип "[No auth](/0.0.1-beta.14/work-with/authorization#no-auth)".

## Basic auth

Используется, если для отправки запроса нужен логин и пароль.

#### Использование Basic auth

Откройте запрос и выберите вкладку «Authorization», выберите тип «Basic auth». В появившихся полях укажите Username и Password.&#x20;

![Использование Basic auth](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwJlX--4fwrhxafXO%2F-LiMwdhd85FeLhiWFzYx%2Fau_1.jpg?alt=media\&token=bc366b8e-c8c9-4e27-814b-8f535fe5bc17)

## Bearer auth&#x20;

Bearer auth  - авторизация через токен. Любой пользователь с токеном-носителем может использовать его для доступа к ресурсам.

#### Использование Bearer auth

Откройте запрос и выберите вкладку «Authorization», выберите тип «Bearer auth». В появившемся поле укажите Token.&#x20;

![Использование Bearer auth](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwJlX--4fwrhxafXO%2F-LiMwg3YpGdpuXjrg8FD%2Fau_2.jpg?alt=media\&token=6edd377d-74eb-4c4f-9482-69f10a00248e)

## Digest Auth&#x20;

Данный метод отправляет хеш-сумму логина, пароля, адреса сервера и случайных данных, и предоставляет больший уровень защиты, чем базовая аутентификация, при которой данные отправляются в открытом виде.

#### Использование Digest Auth

Откройте запрос и выберите вкладку «Authorization», выберите тип «Basic auth». В появившихся полях укажите Username и Password.&#x20;

![Digest Auth с использованием переменных окружения](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwJlX--4fwrhxafXO%2F-LiMwiePJL3t9a9w8Dnc%2Fau_3.jpg?alt=media\&token=e8bbe6cb-a258-433b-b9bd-58bf6964c981)

## OAuth 1.0

Позволяет получить доступ к защищённым ресурсам без необходимости передавать логин и пароль.

#### Использование OAuth 1.0

Откройте запрос и выберите вкладку «Authorization», выберите тип «OAuth 1.0». В появившихся полях укажите данные доступа.

#### Таблица поддерживаемых параметров для OAuth 1.0 в TestMace

| **Параметры**    | Описание                                                   |
| ---------------- | ---------------------------------------------------------- |
| Consumer Key     | Ключ                                                       |
| Consumer Secret  | Код ключа                                                  |
| Access Token     | Токен                                                      |
| Token Secret     | Код токена                                                 |
| Signature Method | Метод шифрования сигнатуры: PLAINTEXT, HMAC-SHA1, RSA-SHA1 |
| Version          | 1.0                                                        |
| Realm            | Хост на который отсылается запрос                          |

![Использование OAuth 1.0](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwJlX--4fwrhxafXO%2F-LiMwlvxgQWs30K7peld%2Fau_4.jpg?alt=media\&token=acaaba8e-5d05-45d8-a739-8df9baf385ea)


# Proxy

Настройка proxy находится в разделе File -> Settings. Включите поддержку proxy "Enable Proxy" и введите значения Proxy переменных.

{% hint style="info" %}

#### **Управление proxy осуществляется при помощи следующих переменных:**

* **http\_proxy** — адрес proxy для запросов без SSL
* **https\_proxy** —  адрес proxy для запросов с SSL
* **no\_proxy** — список хостов через запятую, для которых не нужно использовать proxy

#### **Примеры значений no\_proxy:**

* **`*google.com`** - не передавать запросы HTTP / HTTPS в Google.&#x20;
* **`google.com:443`** - не отправлять HTTPS-запросы в Google, но отправлять HTTP-запросы в Google.&#x20;
* **`google.com:443, yahoo.com:80`** - не передавать HTTPS-запросы в Google и не передавать HTTP-запросы в Yahoo!
* **`*`**- полностью игнорировать переменные окружения https\_proxy / http\_proxy.
  {% endhint %}

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMx8Gow0mVdGoJYS6w%2Fsett_1.jpg?alt=media\&token=2a9d6dd5-c61f-4012-846c-c948f877444c)


# Массовое редактирование таблиц

Некоторые таблицы в приложении поддерживают массовое редактирование. Подобные таблицы имеют сверху кнопку **BULK EDIT**. При переходе в данный режим редактирования содержимое таблицы преобразуется в текстовое представление - значения в строке разделяются соединяются по символу **:,** а строки разделяются по символу перевода строки. Для отключения строки необходимо в начале строки поставить **//.**

Рассмотрим для примера редактирование заголовков в RequestStep узле, который поддерживает массовое редактирование. Так выглядит обычный режим редактирования списка заголовков.

![Стандартный режим редактирования HTTP-заголовков запроса](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMxVS6YPB-QxAIGpCx%2Ft_1.png?alt=media\&token=89a68aac-3c1c-441f-a993-26f623f297d9)

При нажатии на **BULK EDIT** виджет приобретает следующий вид.

![Режим массового редактирования заголовков](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMxY0pET0qTS-gR0T9%2Ft_2.png?alt=media\&token=f754deff-fc0a-4105-8b56-462c10da4b02)

Можем заметить, что значения в пределах строки разделены символом двоеточия, а сами строки разделены переводами строк. Давайте попробуем отключить первую строку. Для этого напишем в начале //.

![Отключение строки в режиме массового редактирования](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMx_MFhsikGdlCF6zq%2Ft_3.png?alt=media\&token=ada590d8-04f4-48fc-9d96-e48570a83325)

И перейдем в табличный вид нажатием на кнопку **TABLE EDIT**. Таблица будет выглядеть следующим образом

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMxbAzOOLrLJicRgYH%2Ft_4.png?alt=media\&token=01d76cf7-72af-4202-a722-eaeae734122f)

Видим, что в первой строке галочка отключена, следовательно, сама строка не будет участвовать в запросе.


# Импорт & Экспорт

В данном разделе мы подробно рассмотрим функционал меню проекта **Import**. Вызвать его можно нажатие на кнопку **+** в верхней части дерева проекта (либо в верхней части панели **Scratches**). Выглядит данное меню следующим образом:

![Контекстное меню Import](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMxodaQagPkXIOxIdO%2Fi_1.png?alt=media\&token=93660fe8-586d-445c-9a9e-896b488fec8f)

Меню **Import** состоит из следующих пунктов:

* [**Shared**](/0.0.1-beta.14/other/import/shared) - загрузка экспортированных ранее узлов
* [**cURL**](/0.0.1-beta.14/other/import/curl) - импорт запроса из cURL
* [**Swagger**](/0.0.1-beta.14/other/import/swagger) - импорт описания API из [Swagger/OpenAPI](https://swagger.io/specification/)
* [**Postman**](/0.0.1-beta.14/other/import/postman) - импорт коллекций из [Postman](https://learning.getpostman.com/docs/postman/collections/sharing_collections/)

В следующих подразделах мы рассмотрим подробнее каждый из данных пунктов.


# Shared

TestMace имеет удобный способ поделиться узлами и целыми поддеревьями проекта. Чтобы импортировать поддерево необходимо в контекстном меню интересующего узла выбрать **Share**.

В качестве примера рассмотрим экспорт проекта из "[Быстрого старта](/0.0.1-beta.14)".&#x20;

![Shared экспорт](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMyaFTxhXcnwjELntO%2Fshared_1.gif?alt=media\&token=cd1d7fdb-cbe0-42fd-9c98-1cff38e062c3)

При этом в буфер обмена копируется URL вида `testmace://....`.

Теперь можно импортировать данный url в интересующий вас узел. Для этого есть два способа:

* импорт из контекстного меню проекта **Import** -> **Shared**
* импорт из контекстного меню [Folder](/0.0.1-beta.14/node-types/folder) или [Project](/0.0.1-beta.14/node-types/project) узла **Import** -> **Shared**

Диалог импорта выглядит следующим образом:

![Диалог импорта узла](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMydc-Y9FfNGUqrUMF%2Fshared_2.png?alt=media\&token=5049c0fa-848f-41d8-a23c-b81798780d3a)

В поле **Name** есть возможность задания имени корневого узла импортируемого поддерева. В поле **URL** необходимо задать ранее экспортированный url. Если при импорте поддерева имя корневого узла уже существует в списке детей предка, то имя будет иметь вид NodeName \[Copy \[number]].

Сам процесс импорта проиллюстрирован ниже:

![Shared импорт](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMyg_AfU5UbXN_wb5_%2Fshared_3.gif?alt=media\&token=398bdb30-800b-42b5-af48-ddb3ef0889b8)


# cURL

[cURL](https://curl.haxx.se/) - это инструмент командный строки, который позволяет взаимодействовать с сервисами с помощью различных протоколов с синтаксисом URL. На данный момент он широко используется в том числе и для отсылки HTTP-запросов через командную строку. TestMace позволяет импортировать команду curl с параметрами в [RequestStep](/0.0.1-beta.14/node-types/requeststep) запрос.

Есть два способа импорта запроса из cURL:

* импорт из контекстного меню проекта **Import** -> **cURL**
* импорт из контекстного меню [Folder](/0.0.1-beta.14/node-types/folder) или [Project](/0.0.1-beta.14/node-types/project) узла **Import** -> **cURL**

При этом открывается диалоговое окно следующего вида:

![Диалоговое окно импорта из cURL](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMyuoOuZ63Z9l2N0kE%2F-LiMz55YfLrDslKi1R0k%2Fcurl_1.png?alt=media\&token=901155b9-89c7-4a93-8c9c-239bf432e1e3)

В данном окне необходимо задать имя нового [RequestStep](/0.0.1-beta.14/node-types/requeststep) узла и команду для импорта.

Рассмотрим для примера случай, когда запрос в виде cURL копируется из списка запросов браузера

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMyuoOuZ63Z9l2N0kE%2F-LiMz6LRqAWaIJM8pu60%2Fcurl_2.gif?alt=media\&token=f011d3fe-9454-48ac-a90f-f24a6a19d9a7)


# Swagger

Импорт из Swagger/OpenAPI подробно рассмотрен в разделе [Импорт описания API](/0.0.1-beta.14/node-types/api-description/api-desc-import)


# Postman

Postman имеет возможность [поделиться коллекцией запросов](https://learning.getpostman.com/docs/postman/collections/sharing_collections/). TestMace поддерживает импорт данного формата. Импортировать Postman коллекции можно следующим образом:

* импорт из контекстного меню проекта **Import** -> **Postman**
* импорт из контекстного меню [Folder](/0.0.1-beta.14/node-types/folder) или [Project](/0.0.1-beta.14/node-types/project) узла **Import** -> **Postman**

При этом открывается диалог следующего вида:

![Импорт коллекции из Postman ](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMyuoOuZ63Z9l2N0kE%2F-LiMzPgGrK8utn3ObmGq%2Fpostman_1.png?alt=media\&token=1d2c772f-9777-4e2f-b878-bce12efe174f)

Здесь необходимо указать путь до файла с импортированной коллекцией. Если при импорте поддерева имя корневого узла уже существует в списке детей предка, то имя будет иметь вид NodeName \[Copy \[number]].


# HTTP-заголовки по умолчанию

Folder и Project узлы имеют возможность устанавливать HTTP-заголовки, которые наследуются потомками и подставляются в запросах RequestStep узлов по умолчанию. Рассмотрим возможности задания и использования заголовков по умолчанию.

### Определение HTTP-заголовков по умолчанию

Заголовки по умолчанию определяются в Folder узле. Для это в панели инструментов Folder узла необходимо нажать на кнопку **Headers**

![](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMyuoOuZ63Z9l2N0kE%2F-LiMzgKB_FUHGyPh4HhD%2Fh_1.png?alt=media\&token=b4d1e8b3-b186-43be-be11-a47738ab2934)

При этом откроется диалог редактирования HTTP-заголовков по умолчанию.

![Диалог редактирования HTTP-заголовков по умолчанию](https://1448546621-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMyuoOuZ63Z9l2N0kE%2F-LiMzhW7Do7qiNgv46vK%2Fh_2.png?alt=media\&token=e75069a7-5440-40dc-a43f-a4927654638a)

В верхней части мы видим нередактируемый список заголовков, унаследованных от предков. В нижней части расположены заголовки, принадлежащие данному Folder узлу. Помимо добавления, удаления и редактирования (в том числе [массового редактирования](/0.0.1-beta.14/other/bulk-table-editing)) есть возможность отключения заголовков, то есть в итоговом запросе отключенный заголовок фигурировать не будет. Состояние заголовков (включен/отключен) также наследуется.&#x20;

Имеется возможность переопределения заголовков в потомках. Например, определение заголовка `RootDefaultHeader1` со значением `Hello, TestMace` переопределит унаследованный заголовок и в потомках текущего Folder узла значение заголовка `RootDefaultHeader1` будет `Hello, TestMace` . Отметим, что само значение `RootDefaultHeader1`  у **предка** текущего Folder узла останется неизменным, `Hello, world` .

### Использование заголовков по умолчанию

Заголовки по умолчанию используются в запросах RequestStep узлов. Они подставляются автоматически и не требуют участия пользователя. Интерфейс редактирования заголовков в RequestStep узле схож с таковым из Folder узла.

### Хранение заголовков по умолчанию в файловой системе

Обратитесь к описанию формата хранения [Folder](/0.0.1-beta.14/node-types/folder) узла. В частности, для хранения списка заголовков используется поле `requestData.headers` а для хранения отключенных заголовков используется `requestData.disabledInheritedHeaders` поле. Для [RequestStep](/0.0.1-beta.14/node-types/requeststep) узла формат аналогичен.


# Быстрый старт

Данное руководство позволит вам быстро освоить интерфейс и основные функции TestMace.

{% hint style="info" %}
В этом руководстве мы протестируем работу back-end сервера для записей типа post на следующем сценарии:

* запросим у сервера все имеющиеся записи
* добавим новую запись
* проверим корректное добавление записи
* обновим только что созданную запись и проверим корректность обновления через ответ от сервера
* запросим обновленную запись от сервера
* проверим, что на сервере запись действительно обновлена
* удалим запись
* проверим, что на сервере запись не существует

**Для этого нам потребуется не более 10 минут, после запуска программы.**
{% endhint %}

## Установка TestMace

Скачать TestMace можно по ссылкам ниже или с сайта <https://client.testmace.com>

* Windows <https://client.testmace.com/download/?os=windows>&#x20;
* Mac OS <https://client.testmace.com/download/?os=mac>
* Linux <https://client.testmace.com/download/?os=linux>

Запустите скачанный файл  и следуйте инструкциям инсталлятора, во время установки будет предложено выбрать директорию установки приложения.

{% hint style="warning" %}
*Для установки TestMace на Windows запустите инсталлятор **с правами администратора.***
{% endhint %}

По завершению установки запустите приложение. Перед вами откроется новый проект.&#x20;

## Обзор интерфейса

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhRnoIjwW7Dhql0g3%2Fmain_screen_1.png?alt=media\&token=7ffe69a0-d600-46d0-a6be-68163828abf9)

## Ваш первый GET запрос

Для создания первого запроса создайте новую вкладку нажав на **+**. При этом в зоне "Scrathes Area" будет создан узел с названием **Scratch 1**. Вставьте в поле URL адрес: <https://testmace-stage.herokuapp.com/posts>. Можно сразу протестировать ответ сервера из "Scrathes Area" или перенести наш черновик в проект. Для удобства переименуйте этот узел, дав ему название **getPosts**.&#x20;

{% hint style="info" %}
Обратите внимание, что все изменения в проекте сохраняются автоматически в режиме реального времени.
{% endhint %}

![Создание шаблона GET запроса](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhWmHEyt7Wg_pwGOK%2Fgetting_started_1.gif?alt=media\&token=a449b957-5d13-4714-bd85-ffdf0a8506de)

Создайте в проекте узел типа [Folder](/0.0.1-beta.16/node-types/folder) с названием **posts** и перенесите созданный черновик **getPosts** из "Scratch Area" в "Project Area".

![Создание Folder узла и перенос шаблона GET запроса](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhbUocmpVlEgJv8Wx%2Fgetting_started_2.gif?alt=media\&token=98edc4c3-659c-45f8-bb60-14fc441b0161)

Откройте двойным кликом созданный запрос **getPosts** и выполните его нажав на кнопку "Run".

![Запуск GET запроса](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhh6Qu8HogBVo8YVV%2Fgetting_started_3.gif?alt=media\&token=2994c506-2517-4eb5-8d5b-0cfdac3e46ef)

Мы видим, что запрос выполнен успешно, в **Response Area** получен список существующих записей.  Давайте рассмотрим этот экран подробнее:

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhmH053dp3fjyobYv%2Frun%20screen.png?alt=media\&token=f7605fac-dd77-40c1-a4a7-eb21b3810a93)

{% hint style="info" %}

#### Request parameters

Здесь вы можете указать http заголовки, а так же передать параметры запросу с автодополнением и использование переменных.

#### Request type

* **GET** — получение ресурса
* **POST** — создание ресурса
* **PUT** — обновление ресурса
* **DELETE** — удаление ресурса
* **PATCH** — для частичного изменения ресурса
* **OPTIONS** — для описания параметров соединения с ресурсом

#### URL

Поле URL поддерживает автодополнение, а так же использование переменных. Мы воспользуемся этими функциями чуть позже.&#x20;

#### Make Request

Выполнение запроса или группы запросов при запуске из корня проекта или ноды типа folder

#### Response area

Зона ответа сервера, вкладка Response Body может быть представлена в виде: Parsed, JSON, text. В соседних вкладках можно посмотреть Response Headers, а так же создать или посмотреть существующие Assertion узлы для запроса.
{% endhint %}

## POST запрос и Assertion

Давайте теперь добавим новую запись типа post на сервер, для этого нам нужно создать новый [RequestStep](/0.0.1-beta.16/node-types/requeststep) узел.&#x20;

{% hint style="info" %}
**Существует три способа добавления нового узла в проект:**

1. Мы можем создать черновик (Scratch) нажав на **+** и позже перенести его в проект используя Drag and Drop;&#x20;
2. Можно нажать правой кнопкой мыши по узлу родителю и выбрать **Add node -> Request step**;&#x20;
3. Можно нажать на кнопку **Add project node-> Add node -> Request step**.&#x20;
   {% endhint %}

Создайте новый узел любым из этих способов и задайте ему имя **createPost**.&#x20;

1. Выберите для этого узла "**Request type**" значением POST
2. В поле URL вставьте <https://testmace-stage.herokuapp.com/posts>
3. Во вкладке body выберите тип данных JSON и добавьте `{"title": "Testing post", "content": "Sendt via TestMace"}`
4. Выполните запрос нажав на кнопку RUN.&#x20;

Будет получен ответ об успешном добавлении записи, но нам нужно проверить, что запись добавлена корректно, для этого мы воспользуемся механизмом быстрого создания [Assertion](/0.0.1-beta.16/node-types/assertion) узлов. Мы сравним отправляемые данные с полученными от сервера.

В зоне "Response Area" в формате Parsed нажмите правой кнопкой мыши по **значению title**, которое мы передавали в  запросе, выберите **Create Assertion -> Compare -> Equal.** После этого узел [Assertion](/0.0.1-beta.16/node-types/assertion) будет создан и открыт, нам дополнительной настройки не требуется, поэтому закроем его. Аналогично создадим Assertion узел для значения Content.

А теперь запустим запрос **createPost** и интерфейс проинформирует нас об успешном выполнении теста. Это совсем не сложно, посмотрите анимацию ниже:

![POST запрос и создание Assertion](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMi-YplERQn7P7vAdh%2Fgetting_started_4.gif?alt=media\&token=72a8ead4-09d7-4042-bcf3-5dfc4baac62b)

### Динамические переменные

Для того, чтобы мы могли взаимодействовать с созданной нами записью на сервере, нужно передавать в последующие [Request step](/0.0.1-beta.16/node-types/requeststep) значение её **Id**. Создадим динамическую переменную **postId** и присвоим ей значение Id возвращаемое в записи после выполнения **CreatePost**.&#x20;

1. Кликните правой кнопкой мыши по значению **Id** в Response body ноды **CreatePost**,&#x20;
2. Выберите пункт **Assign to variable**.&#x20;
3. Во всплывающем окне в качестве ноды выберите директорию проекта **posts**, введите имя переменной: **postId** и нажмите **ОК**.

Для того чтобы обратиться к переменной используйте [встроенную переменную](/0.0.1-beta.16/variables/variables) `$dynamicVar`:

```
${$dynamicVar.postId}
```

![Создание динамической переменной](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMi7013WKadQVvXiGl%2Fgetting_started_5.gif?alt=media\&token=062fae05-2749-47ee-8cb9-f3ca2ebb949b)

## PUT запрос&#x20;

На этом этапе мы будем использовать запрос типа PUT. Обратимся  к записи созданной на предыдущем шаге при помощи динамической переменной: `${$dynamicVar.postId}` и обновим  значения записи **title** и **content**.

1. Создайте [RequestStep](/0.0.1-beta.16/node-types/requeststep) узел c именем **updatePost**
2. Request type выберите **PUT**
3. URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>
4. Body: `{"title": "Testing post updated", "content": "Updated via TestMace"}`
5. Выполним запрос и аналогично шагу **POST запрос**, создадим два [Assertion](/0.0.1-beta.16/node-types/assertion) узла для сравнения отправленных и полученных значений **title** и **content**.

![Создание PUT запроса](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMiCJFpZet2AU5b53U%2Fgetting_started_6.gif?alt=media\&token=f2afbe7f-c124-4766-a83f-f9a41eeba3fd)

## Проверка изменений

В некоторых случаях необходимо провести дополнительную проверку изменений записи, так как сервер может ответить на PUT запрос успешным выполнением, а при обращении через GET запрос мы получим старую запись.&#x20;

Для этого мы создадим GET запрос по URL записи с использованием динамической переменной:

1. Создайте новый [RequestStep](/0.0.1-beta.16/node-types/requeststep) узел с именем **getPost**
2. Тип запроса: GET
3. URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>
4. Выполните запрос и создайте 2 [Assertion](/0.0.1-beta.16/node-types/assertion) узла для сравнения данных **title** и **content**.

![Проверка изменений через GET запрос](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMiT5mOsq1gAMPerMW%2Fgetting_started_7.gif?alt=media\&token=5e59de9b-f62d-41bc-837b-64cc73fefb57)

## DELETE запрос

Следующий шаг - удаление созданной нами записи по URL записи с использованием динамической переменной:

1. Создайте узел типа [RequestStep](/0.0.1-beta.16/node-types/requeststep) с именем **deletePost**
2. Тип запроса: DELETE
3. URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>

![DELETE запрос](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMiZW7ZpmWWOjtKxmv%2Fgetting_started_8.gif?alt=media\&token=85f97180-fbe5-49ed-9f42-9bb64452d528)

## Проверка DELETE

Для того, чтобы убедиться, что созданная запись была удалена с сервера, создадим GET запрос  по URL записи с использованием динамической переменной, мы ожидаем, что при запросе получим ответ сервера: 404, поэтому создадим соответствующий Assertion узел:

1. Создайте узел типа [RequestStep](/0.0.1-beta.16/node-types/requeststep) с именем **checkIfNodeExists**
2. Тип запроса: GET
3. URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>
4. Выполните запрос и в зоне Response Area выберите пункт **Assertions** и добавьте новый [Assertion](/0.0.1-beta.16/node-types/assertion) узел, нажав ADD. Внесите данные узла:
   1. Actual value: `${$response.code}`
   2. Operator: `=`
   3. Expected value: `404`

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMifs1DC9bLBWd_0OX%2Fgetting_started_9.gif?alt=media\&token=2a4955ea-9330-482d-bfd4-79856fea6587)

## Заключение

В результате мы получили набор тестов для нашего сервера, которые можно последовательно выполнить, перейдите в узел **posts** и нажмите RUN.&#x20;

![Запуск сценария](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMijSU3AugGlYW8Hb9%2Fgetting_started_10.gif?alt=media\&token=19974399-a80a-4c9d-8929-1481ff85ddff)

## Видео инструкция

Посмотрите весь процесс создания сценария описанного в руководстве на видео

{% embed url="<https://youtu.be/Gyg_4w78KBo>" %}

## Код для импорта через [shared](/0.0.1-beta.16/other/import/shared)

{% file src="/files/-LiMgl1CXlo1QrHQ-pvL" %}
Быстрый страт Share код
{% endfile %}

## Скачать проект

Разархивируйте  в директорию проектов TestMace.

{% file src="/files/-LiMgePcyczxfcL4KgnN" %}
Быстрый старт
{% endfile %}


# Меню

![Меню](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMj8R2AA2HCwWecvf1%2F-LiMjTWmbJR1U94vw05W%2F2.png?alt=media\&token=9d1df541-693d-4a85-be17-5f4b9a4aab1c)

* **Undo и Redo** - отмена и повтор действий. На данный момент поддерживаются все действия связанные с изменением проектов и узлов.
* [**Cookies**](/0.0.1-beta.16/work-with/cookie) - диалог для работы с cookies.
* [**Environments**](/0.0.1-beta.16/variables/env) - конфигурация и выбор текущего environment.


# Обзор интерфейса

### Интерфейс приложения разделен на 3 глобальные группы <a href="#interfeis-prilozheniya-razdelen-na-3-globalnye-gruppy" id="interfeis-prilozheniya-razdelen-na-3-globalnye-gruppy"></a>

1. Дерево проекта
2. Область шаблонов
3. Главная область

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhRnoIjwW7Dhql0g3%2Fmain_screen_1.png?alt=media\&token=7ffe69a0-d600-46d0-a6be-68163828abf9)

### Главная область или область запроса так же разделена на группы <a href="#glavnaya-oblast-ili-oblast-zaprosa-tak-zhe-razdelena-na-gruppy" id="glavnaya-oblast-ili-oblast-zaprosa-tak-zhe-razdelena-na-gruppy"></a>

1. Тип запроса
2. URL
3. Запуск
4. Параметры запроса
5. Зона ответа от сервера

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhmH053dp3fjyobYv%2Frun%20screen.png?alt=media\&token=f7605fac-dd77-40c1-a4a7-eb21b3810a93)


# Черновики

{% hint style="info" %}
**Scratches — это черновики узлов , которые вы можете  вы переносить в основное дерево проекта**
{% endhint %}

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMj8R2AA2HCwWecvf1%2F-LiMk7xaroMnSbAqF1Lq%2Fscratches.gif?alt=media\&token=f2aa116b-6565-4c26-95e5-7f9fba5ce34c)


# Типы узлов

{% hint style="info" %}
Узел - это любой элемент дерева проекта или черновиков
{% endhint %}

### Типы узлов

* [**Project**](/0.0.1-beta.16/node-types/project)**.** Это корневой узел, создается автоматически при создании проекта. В остальном повторяет функциональные возможности Folder узла.
* [**Folder**](/0.0.1-beta.16/node-types/folder)**.** Позволяет группировать Folder и RequestStep узлы внутри себя.
* [**RequestStep**](/0.0.1-beta.16/node-types/requeststep). Это узел, с помощью которого можно сделать запрос. В качестве дочернего элемента он может иметь только один Assertion узел.
* [**Assertion**](/0.0.1-beta.16/node-types/assertion). Узел используется для написания тестов. Может быть дочерним узлом только для RequestStep узла.
* [**Script**](/0.0.1-beta.16/node-types/script). Позволяет запускать произвольный скрипт на языке JavaScript с возможностью обращения к API приложения.
* [**Link**](/0.0.1-beta.16/node-types/link). Позволяет сослаться на уже существующую ноду.
* [**Api description**](/0.0.1-beta.16/node-types/api-description)
  * [**ApiRootFolder**](/0.0.1-beta.16/node-types/api-description/apirootfolder)**.** Корневой элемент (папка) для описания API
  * [**ApiFolder**](/0.0.1-beta.16/node-types/folder)**.** Служит для объединения логически близких эндпоинтов при описании API (например, эндпоинты с одинаковыми url-ами но разными методами)
  * [**ApiRoute**](/0.0.1-beta.16/node-types/api-description/apiroute)**.** Описание конкретного эндпоинта
* [**Broken**](/0.0.1-beta.16/node-types/broken)**.**  Используется для описания узлов, загрузка которых завершилась с ошибкой. Не может быть создан вручную и не сохраняется в файловую систему.


# Горячие клавиши

Использование горячих клавиш в TestMace

| Назначение               | Сочетание клавиш   |
| ------------------------ | ------------------ |
| **Навигация**            |                    |
| Фокус на дерево проекта  | Ctrl + 1           |
| Фокус на шаблоны         | Ctrl + 2           |
| Фокус на главную область | Ctrl + 3           |
| Открыть настройки        | Ctrl + Alt + S     |
| **Табы**                 |                    |
| Предыдущий таб           | Ctrl + Shift + Tab |
| Следующий таб            | Ctrl + Tab         |
| Закрыть таб              | Ctrl + W           |
| Создать новый шаблон     | Ctrl + T           |
| **Дерево проекта**       |                    |
| Фокус на поле поиска     | Ctrl + F           |
| Открыть узел             | Enter              |
| Открыть меню узла        | Alt + Insert       |
| Удалить узел             | Delete             |
| Переименовать узел       | Ctrl + F6          |
| Следующий узел           | ↓                  |
| Предыдущий узел          | ↑                  |
| Развернуть узел          | →                  |
| Свернуть узел            | ←                  |
| **Проект**               |                    |
| Run Node                 | Ctrl + Enter       |
| Focus Url                | Ctrl + E           |
| Save Project             | Ctrl + S           |
| Save Project as          | Ctrl + Shift + S   |
| Open Project             | Ctrl + O           |
| Create New Project       | Ctrl + N           |
| Undo                     | Ctrl + Z           |
| Redo                     | Ctrl + Shift + Z   |


# Project

Узел типа **Project** - корневой элемент проекта. Он создается автоматически при создании нового проекта и в дальнейшем повторяет функционал [Folder](/0.0.1-beta.16/node-types/folder) узла. **Project** узел также не может быть создан вручную и не может использоваться в качестве потомка других типов узлов.

{% hint style="warning" %}
На данный момент переименование папки Project не поддерживается из приложения. Кроме того, переименование папки Project напрямую в файловой системе сломает проект.
{% endhint %}


# Folder

Данный тип узла используется для группировки других узлов. В качестве предков для данного типа узла могут выступать [Project](/0.0.1-beta.16/node-types/project) и **Folder** узлы. В дереве проекта узел выглядит следующим образом:

![Вид Folder узла в дереве](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMkb3-DX1GM-t41kVp%2F-LiMmTIIcnPTqxcvqNKY%2Ff_1.png?alt=media\&token=be6e7ec3-e670-49f7-bbc5-6e441ec56e9b)

В дереве для данного типа узла доступны следующие пункты меню:

![Контекстное меню для Folder узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMkb3-DX1GM-t41kVp%2F-LiMmVgGhUcgkI5BfQ3f%2FF_2.png?alt=media\&token=965e0b09-8ea5-4833-ada7-8a79412da056)

* **Add node.** Добавление узла-потомка. В подменю можно выбрать тип узла.
* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название **NodeName \[Copy \[number]]**.
* **Remove node.** Удалить узел.
* **Run.** Запустить узел.
* [**Share**](/0.0.1-beta.16/other/import/shared)**.** Поделиться узлом. При это в буфере обмена создается ссылка, которая содержит всю информацию о текущем узле.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

Открытие узла открывается двойным кликом по узлу в дереве. Вкладка **Folder** узла выглядит следующим образом:

![Вкладка с открытым Folder узлом](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMkb3-DX1GM-t41kVp%2F-LiMmZZV7lGYhAkNysCD%2Ff_3.png?alt=media\&token=70509ecd-5aa5-4fa9-b719-643315e26a6c)

На скрине отмечены следующие области

1. Кнопка **Run** для запуска узлов внутри Folder узла
2. Панель управления
3. Кнопка **Headers** для задания наследуемых HTTP-заголовков
4. Кнопка **открытия** [**диалога переменных**](/0.0.1-beta.16/variables/user-variables)
5. Область **дочерних узлов**
6. Проверка на то, что узел имеет валидный SSL сертификат. Используется в качестве наследуемого параметра в [RequestStep](/0.0.1-beta.16/node-types/requeststep) узле
7. **Авторизация**

Рассмотрим данные области подробнее.

### Панель управления

Назначение кнопки **Run** описано выше. Стоит добавить, что при запуске узла кнопка меняет вид на следующий:

![Вид кнопки Run в процессе запуска узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMkb3-DX1GM-t41kVp%2F-LiMmaMjx53JO9Hq1Xmv%2Ff_4.png?alt=media\&token=b5028006-c46d-498b-809f-44e69d9dcfe9)

При нажатии на **Abort** можно прервать выполнение узла.

Кнопка **Headers** позволяет задать [наследуемые HTTP-заголовки](/0.0.1-beta.16/other/default-http-headers).

Редактирование переменных обсуждается в разделе [Пользовательские переменные](/0.0.1-beta.16/variables/user-variables).

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

**Folder** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат.

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Folder node",
      "const": "Folder",
      "type": "string"
    },
    "authData": {
      "$ref": "#/definitions/IAuthorizationData",
      "description": "Authorization parameters"
    },
    "requestData": {
      "$ref": "#/definitions/IRequestParametersData",
      "description": "Request parameters"
    },
    "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": [
    "authData",
    "children",
    "name",
    "requestData",
    "type",
    "variables"
  ],
  "definitions": {
    "IAuthorizationData": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "IRequestParametersData": {
      "type": "object",
      "properties": {
        "headers": {
          "description": "Headers",
          "type": "array",
          "items": {
            "$ref": "#/definitions/NameValueParam"
          }
        },
        "disabledInheritedHeaders": {
          "description": "Names of disabled headers",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "strictSSL": {
          "$ref": "#/definitions/StrictSSLOptions",
          "description": "Requires SSL certificates be valid"
        }
      },
      "required": [
        "disabledInheritedHeaders",
        "headers",
        "strictSSL"
      ]
    },
    "NameValueParam": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "value": {
          "type": "string"
        },
        "isChecked": {
          "type": "boolean"
        }
      },
      "required": [
        "name",
        "value"
      ]
    },
    "StrictSSLOptions": {
      "enum": [
        "Inherit",
        "No",
        "Yes"
      ],
      "type": "string"
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# RequestStep

**RequestStep** узел - это узел для отправки HTTP-запросов. Наш инструмент позволяет гибко сконфигурировать запрос и использовать его как отдельно, так и в составе сценария.&#x20;

### Представление RequestStep узла в дереве проекта

Для создания **RequestStep** узла необходимо в контекстном меню [Folder](/0.0.1-beta.16/node-types/folder) узла или [Project](/0.0.1-beta.16/node-types/project) узла выбрать пункт **Add node** -> **RequestStep**.&#x20;

В дереве проекта **RequestStep** узел выглядит следующим образом

![Вид RequestStep узла в дереве](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMn8brxTqg9NyauFGQ%2Fr_1.png?alt=media\&token=bad90b90-b617-484a-be06-772296e84c6f)

Остановимся на узле поподробнее. Цвет левого верхнего кружка указывает на статус HTTP-запроса: серый - если запрос не выполнялся, зеленый - в случае успешного HTTP-кода (например, 200, 201 и т.д.), красный - в случае неудачного HTTP-кода (например, 404, 500 и т.д.). Цвет иконки листочка указывает на статус выполнения дочернего [Assertion](/0.0.1-beta.16/node-types/assertion) узла: серый - если запуск не выполнялся, зеленый - в случае если после запуска, [Assertion](/0.0.1-beta.16/node-types/assertion) узел либо отсутствует, либо существует и его выполнение завершилось успешно, красный - в случае, если выполнение [Assertion](/0.0.1-beta.16/node-types/assertion) узла завершилось с ошибкой (не все проверки были пройдены).

В дереве для данного типа узла доступны следующие пункты меню:

![Контекстное меню для RequestStep узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnC-lWL3HbKt7n8v6%2Fr_2.png?alt=media\&token=f7c7f321-6640-4a8f-878f-a45b3e97dc74)

* **Add node.** Добавление узла-потомка. В подменю можно выбрать тип узла.
* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название NodeName \[Copy \[number]].
* **Remove node.** Удалить узел.
* **Run.** Запустить узел.
* [**Share**](/0.0.1-beta.16/other/import/shared)**.** Поделиться узлом. При это в буфере обмена создается ссылка, которая содержит всю информацию о текущем узле.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

### Описание вкладки RequestStep узла

При создании **RequestStep** узла (или при двойном клике по уже существующему) открывается вкладка данного узла. Выглядит она следующим образом:

![Вкладка RequestStep узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnEvykjaSi-HmvyaO%2Fr_3.png?alt=media\&token=16228eaa-d70d-4745-ad8c-5532c8f5b6e8)

Рассмотрим подробнее каждую из частей интерфейса.&#x20;

#### Секция конфигурирования запроса

Верхняя часть запроса выглядит следующим образом:

![Верхняя часть запроса](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnHqzZyYcsjZwlpwR%2Fr_4.png?alt=media\&token=2c24d661-d1c9-4da2-b0bf-9dae21081de2)

На скрине выше отмечены следующие пункты

1. Метод запроса. На данный момент поддерживаются следующие методы:
   * **GET** — получение ресурса
   * **POST** — создание ресурса
   * **PUT** — обновление ресурса
   * **DELETE** — удаление ресурса
   * **PATCH** — для частичного изменения ресурса
   * **OPTIONS** — для описания параметров соединения с ресурсом
2. Поле для URL.
3. Кнопка для запуска запроса
4. Кнопка [редактирования переменных](/0.0.1-beta.16/variables/user-variables)

Ниже представлена панель редактирования заголовков, query параметров, авторизации и тела запроса. Так выглядит данная панель для POST запросов:

![Панель редактирования параметров запроса](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnLAHkLfKFdOIj3XQ%2Fr_5.png?alt=media\&token=3857f903-abe2-44a4-a91a-f03827d78c31)

Данная панель организована в виде вкладок. На данный момент существуют следующие вкладки:

* **Headers** - для редактирования списка HTTP-заголовков
* **Query parameters** - для редактирования списка query параметров
* **Body** - для конфигурирования тела запроса
* **Authorization** - для конфигурирования [авторизаций](/0.0.1-beta.16/work-with/authorization).
* **Other** - конфигурирование прочих параметров запроса

Вкладки **Headers** и **Query** parameters с точки зрения интерфейса очень похожи - это обычные таблицы с возможностью [массового редактирования](/0.0.1-beta.16/other/bulk-table-editing) и отключением строк. Отдельно стоит добавить, что заголовки поддерживают механизм установки [HTTP-заголовков по умолчанию](/0.0.1-beta.16/other/default-http-headers).&#x20;

Вкладка **Other** выглядит следующим образом:

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnPKjfaH4wV8iveo2%2Fr_6.jpg?alt=media\&token=88df025b-8b5b-4eb5-8949-05235399c0fb)

На данный момент можно отредактировать параметр **Requires SSL certificates be valid** - проверять валидность SSL-сертификата узла. Параметр по умолчанию: **Inherit**, наследует значение родителя узла, если у родителя задан Inherit, параметр выключен. Возможные варианты:

* Yes — да
* No — нет
* Inherit — наследовать

Отдельно остановимся на вкладке **Body**, которая выглядит следующим образом:

![Вкладка Body](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnT7hfXfRdavga1tf%2Fr_7.png?alt=media\&token=9b1dde6f-51f5-4248-8460-ed5e21f55ddf)

В выпадающем списке можно выбрать тип тела. На данный момент поддерживаются следующие типы

* **JSON** - для отправки JSON данных. Сами данные редактируются в текстовом поле с подсветкой JSON-синтаксиса и с поддержкой [механизма переменных](/0.0.1-beta.16/variables/user-variables) . При отправке запроса в список HTTP-заголовков добавляется заголовок `Content-Type` со значением `application/json` .
* **Form data** - для редактирования `multipart/form-data` форм. Имеет табличный вид с возможностью [массового редактирования](/0.0.1-beta.16/other/bulk-table-editing) . В строках таблицы в качестве значения могут выступать как обычные строки, так и ссылки на файлы.
* **Form URL encoded** - для редактирования `application/x-www-form-urlencoded` форм. Имеет табличный вид с возможностью [массового редактирования](/0.0.1-beta.16/other/bulk-table-editing) .
* **File** - для отправки в теле содержимое файла.
* **XML** - для отправки XML данных. Сами данные редактируются в текстовом поле с подсветкой XML-синтаксиса и с поддержкой [механизма переменных](/0.0.1-beta.16/variables/user-variables) . При отправке запроса в список HTTP-заголовков добавляется заголовок `Content-Type` со значением `application/xml` .
* **Text** - для отправки текстовых данных. Сами данные редактируются в текстовом поле с поддержкой [механизма переменных](/0.0.1-beta.16/variables/user-variables) . При отправке запроса в список HTTP-заголовков добавляется заголовок `Content-Type` со значением `text/plain` .

#### Секция конфигурирования ответа

Давайте выполним запрос на url <https://testmace-stage.herokuapp.com/posts> и посмотрим, как выглядит секция ответа:

![Секция ответа RequestStep узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnXC3T2KRgRyj96nm%2Fr_8.png?alt=media\&token=94f12efb-b450-4ce2-805b-76b4d2d24327)

Верхняя часть секции показывает краткую информацию об ответе: код ответа с указанием, успешный он или нет, время выполнения запроса и размер ответа.

Нижняя область секции ответа разбита на несколько вкладок:

* **Response body** - содержит тело ответа, представленное различными способами. На данный момент имеются следующие представления тела ответа:
  * **Parsed**- ответ в виде дерева. Каждый лист дерева имеет контекстное меню для создания [Assertion](/0.0.1-beta.16/node-types/assertion) узлов и для работы с [динамическими переменными](/0.0.1-beta.16/variables/user-variables/dynamic-variables)
  * **JSON** - JSON-подсветка тела ответа. Существует только в случае, когда тело ответа пришло в формате json.
  * **XML -** XML-подсветка тела ответа. Существует только в случае, когда тело ответа пришло в формате XML.
  * **HTML** - HTML-подсветка тела ответа. Показывается в случае, если тело ответа - HTML-страница
  * **Text** - текстовое представление тела ответа без подсветки&#x20;
  * **Preview** - отрендеренный вариант тела ответа. Показывается в случае, если тело ответа - HTML-страница
* **Response headers** - список HTTP-заголовков ответа
* **Assertions** - список assertion-ов, которые содержатся в дочернем [Assertion](/0.0.1-beta.16/node-types/assertion) узле.

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

**RequestStep** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат:

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Folder node",
      "const": "RequestStep",
      "type": "string"
    },
    "assignVariables": {
      "description": "List of variables assignments",
      "type": "array",
      "items": {
        "$ref": "#/definitions/AssignVariable"
      },
      "default": []
    },
    "requestData": {
      "$ref": "#/definitions/IRequestData"
    },
    "authData": {
      "$ref": "#/definitions/IAuthorizationData",
      "description": "Authorization parameters"
    },
    "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": [
    "assignVariables",
    "authData",
    "children",
    "name",
    "requestData",
    "type",
    "variables"
  ],
  "definitions": {
    "AssignVariable": {
      "type": "object",
      "properties": {
        "path": {
          "description": "Path in $response variable (e.g. body.id)",
          "type": "string"
        },
        "assign": {
          "$ref": "#/definitions/NodeReference",
          "description": "Link on target node (one of parents)"
        },
        "variable": {
          "description": "Name of dynamic variable in target node",
          "type": "string"
        }
      },
      "required": [
        "assign",
        "path",
        "variable"
      ]
    },
    "NodeReference": {
      "type": "object",
      "properties": {
        "refNodePath": {
          "description": "Absolute path to node",
          "type": "string"
        },
        "type": {
          "description": "Marker of reference entity",
          "const": "reference",
          "type": "string",
          "default": "reference"
        }
      },
      "required": [
        "refNodePath",
        "type"
      ]
    },
    "IRequestData": {
      "type": "object",
      "properties": {
        "request": {
          "description": "Common request parameters",
          "type": "object",
          "properties": {
            "method": {
              "$ref": "#/definitions/RequestMethod",
              "description": "HTTP-method"
            },
            "url": {
              "type": "string"
            }
          },
          "required": [
            "method",
            "url"
          ]
        },
        "params": {
          "description": "Query parameters",
          "type": "array",
          "items": {
            "$ref": "#/definitions/NameValueParam"
          }
        },
        "body": {
          "$ref": "#/definitions/IRequestBody",
          "description": "Body parameters"
        },
        "headers": {
          "description": "Headers",
          "type": "array",
          "items": {
            "$ref": "#/definitions/NameValueParam"
          }
        },
        "disabledInheritedHeaders": {
          "description": "Names of disabled headers",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "strictSSL": {
          "$ref": "#/definitions/StrictSSLOptions",
          "description": "Requires SSL certificates be valid"
        }
      },
      "required": [
        "body",
        "disabledInheritedHeaders",
        "headers",
        "params",
        "request",
        "strictSSL"
      ]
    },
    "RequestMethod": {
      "enum": [
        "DELETE",
        "GET",
        "OPTIONS",
        "PATCH",
        "POST",
        "PUT"
      ],
      "type": "string"
    },
    "NameValueParam": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "value": {
          "type": "string"
        },
        "isChecked": {
          "type": "boolean"
        }
      },
      "required": [
        "name",
        "value"
      ]
    },
    "IRequestBody": {
      "type": "object",
      "properties": {
        "type": {
          "$ref": "#/definitions/RequestBodyType",
          "description": "Type of body"
        },
        "jsonBody": {
          "description": "JSON string of body",
          "type": "string"
        },
        "xmlBody": {
          "description": "XML string of body",
          "type": "string"
        },
        "textBody": {
          "type": "string"
        },
        "formData": {
          "description": "multipart/form-data form",
          "type": "array",
          "items": {
            "$ref": "#/definitions/RequestStepFormData"
          }
        },
        "formURLEncoded": {
          "description": "application/x-www-form-urlencoded form",
          "type": "array",
          "items": {
            "$ref": "#/definitions/NameValueParam"
          }
        },
        "file": {
          "description": "Link on file, which will be used as a content for body",
          "type": "string"
        }
      },
      "required": [
        "file",
        "formData",
        "formURLEncoded",
        "jsonBody",
        "textBody",
        "type",
        "xmlBody"
      ]
    },
    "RequestBodyType": {
      "enum": [
        "File",
        "FormData",
        "FormURLEncoded",
        "Json",
        "Text",
        "Xml"
      ],
      "type": "string"
    },
    "RequestStepFormData": {
      "type": "object",
      "properties": {
        "type": {
          "$ref": "#/definitions/FormDataField"
        },
        "name": {
          "type": "string"
        },
        "value": {
          "type": "string"
        },
        "isChecked": {
          "type": "boolean"
        }
      },
      "required": [
        "name",
        "type",
        "value"
      ]
    },
    "FormDataField": {
      "enum": [
        "File",
        "Text"
      ],
      "type": "string"
    },
    "StrictSSLOptions": {
      "enum": [
        "Inherit",
        "No",
        "Yes"
      ],
      "type": "string"
    },
    "IAuthorizationData": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# Assertion

**Assertion** узел - это узел, используемый для написания тестов. Каждый **Assertion** узел состоит из набора **Assertion**-ов - минимальных проверок различных утверждений. При запуске **Assertion** узла запускается проверка всех **Assertion**-ов. Если хотя бы одна проверка завершится с ошибкой, то выполнение всего **Assertion** узла завершается с ошибкой.&#x20;

**Assertion** узел может быть создан только как потомок [RequestStep](/0.0.1-beta.16/node-types/requeststep) узла. Причем [RequestStep](/0.0.1-beta.16/node-types/requeststep) узел может имет не более одного **Assertion** узла в качестве потомка.

Создать **Assertion** узел можно следующими способами: из дерева проекта в контекстном меню [RequestStep](/0.0.1-beta.16/node-types/requeststep) узла выбрать **Add node** -> **Assertion.** Либо в секции ответа [RequestStep](/0.0.1-beta.16/node-types/requeststep) узла во вкладке Assertion выбрать **+ CREATE NEW ASSERTION NODE**.

![Создание Assertion узла из секции ответа RequestStep узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoAyRH5uUfa-eq257%2Fa_1.png?alt=media\&token=bda458cb-838e-44f8-87b9-4cabc2425757)

В дереве проекта **Assertion** узел выглядит следующим образом:

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoECui6mwoRgeIDAa%2Fa_2.png?alt=media\&token=ce954185-2048-4557-b0dd-35ac6614d0a6)

Если запуск **Assertion** узла завершился успешно, то в дереве он принимает следующий вид:

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoFN4dUZ4-U8wBQWU%2Fa_3.png?alt=media\&token=874f8bb4-745a-4f46-80af-d172edaf0a52)

В случае, если запуск **Assertion** узла завершился с ошибкой, узел выглядит так:

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoGOvC0j_WBuSxzC_%2Fa_4.png?alt=media\&token=547ed1ef-2d22-402c-aa71-881a39ec06c8)

В дереве для данного типа узла доступны следующие пункты меню:

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoHh5OEJ4MWR_Og86%2Fa_5.png?alt=media\&token=63b7b2f7-9e27-424b-844d-170bb011036e)

* **Remove node.** Удалить узел.
* **Run.** Запустить узел.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

Вкладка с **Assertion** узлом выглядит следующим образом:

![Интерфейс вкладки Assertion узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoJoMRGGK3Z5hgVkS%2Fa_6.png?alt=media\&token=821ff8a4-2406-4a59-b449-8ed75fcb380b)

На скрине отмечены следующие области:

1. Панель управления
2. Панель настроек выбранного **Assertion**-а
3. Список **Assertion**-ов

На панели управления расположены следующие кнопки

* **RUN** - запуск списка **Assertion**-ов
* **FIX ERRORS** - исправление ошибок **Assertion**-ов где это возможно. Данная кнопка активируется в случае, если есть ошибки в **Assertion**-ах. Функционал исправления ошибок описан в разделах **Исправление ошибок** каждого из **Assertion**-ов.
* **DISABLE ERRORS** - выключение **Assertion**-ов, завершившихся с ошибкой. Отключенные **Assertion**-ы не будут участвовать в дальнейших запусках. Данная кнопка активируется в случае, если есть ошибки в **Assertion**-ах
* **+ ADD ASSERTION** - добавление **Assertion** в список

Ниже панели управления находится список **Assertion**-ов. Каждый элемент в данном списке выглядит следующим образом:

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMncFSF5eW52WiS8EV%2F-LiMoO8cHyDJOa7RFj4v%2Fa_7.png?alt=media\&token=0c7d1f73-fc66-4239-89de-b0fccf2dad07)

На скрине отмечены следующие области:

1. Подсветка статуса. Если **Assertion** не запускался, то его цвет серый, если запуск завершился с ошибкой - красный, если успешно - зеленый.
2. Иконка конкретного типа **Assertion**-а
3. Краткое текстовое представление **Assertion**-а
4. Удалить **Assertion**
5. Задизейблить **Assertion**. При этом не будет участвовать в последующих запусках
6. Запустить **Assertion**
7. Исправить **Assertion**

Заметим, что контролы 4, 5, 6 и 7 появляются при наведении на **Assertion**.

Интерфейс панели настроек выбранного **Assertion**-а зависит от выбранного **Assertion**-а. В следующих разделах мы подробно разберем каждый из **Assertion**-ов

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

**Assertion** узел хранится в файле \<nodename>.yml, где \<nodename> - название Assertion-а и имеет следующий формат:

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Assertion node",
      "const": "Assertion",
      "type": "string"
    },
    "assertions": {
      "description": "List of assertions",
      "type": "array",
      "items": {
        "$ref": "#/definitions/AbstractAssertion"
      },
      "default": []
    },
    "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": [
    "assertions",
    "children",
    "name",
    "type",
    "variables"
  ],
  "definitions": {
    "AbstractAssertion": {
      "oneOf": [
        {
          "$ref": "#/definitions/CompareAssertion"
        },
        {
          "$ref": "#/definitions/ContainsAssertion"
        },
        {
          "$ref": "#/definitions/XPathAssertion"
        },
        {
          "$ref": "#/definitions/ScriptAssertion"
        }
      ]
    },
    "CompareAssertion": {
      "type": "object",
      "properties": {
        "type": {
          "description": "Type of Compare assertion",
          "const": "compare",
          "type": "string"
        },
        "actualValue": {
          "description": "Actual value",
          "type": "string",
          "default": "${$response.body}"
        },
        "operator": {
          "$ref": "#/definitions/CompareOperator",
          "description": "Operator",
          "default": "equal"
        },
        "expectedValue": {
          "description": "Expected value",
          "type": "string"
        },
        "disabled": {
          "type": "boolean",
          "default": false
        }
      },
      "required": [
        "actualValue",
        "disabled",
        "expectedValue",
        "operator",
        "type"
      ]
    },
    "CompareOperator": {
      "enum": [
        "equal",
        "greater",
        "greater or equal",
        "less",
        "less or equal",
        "not equal"
      ],
      "type": "string"
    },
    "ContainsAssertion": {
      "type": "object",
      "properties": {
        "type": {
          "description": "Type of Contains assertion",
          "const": "contains",
          "type": "string"
        },
        "text": {
          "description": "Text to be searched",
          "type": "string",
          "default": "${$response.body}"
        },
        "value": {
          "description": "Value for search in text",
          "type": "string"
        },
        "disabled": {
          "type": "boolean",
          "default": false
        }
      },
      "required": [
        "disabled",
        "text",
        "type",
        "value"
      ]
    },
    "XPathAssertion": {
      "type": "object",
      "properties": {
        "type": {
          "description": "Type of Xpath assertion",
          "const": "xpath",
          "type": "string"
        },
        "text": {
          "description": "Text to be searched",
          "type": "string",
          "default": "${$response.body}"
        },
        "path": {
          "description": "XPath selector",
          "type": "string"
        },
        "expectedValue": {
          "description": "Expected value",
          "type": "string"
        },
        "disabled": {
          "type": "boolean",
          "default": false
        }
      },
      "required": [
        "disabled",
        "expectedValue",
        "path",
        "text",
        "type"
      ]
    },
    "ScriptAssertion": {
      "type": "object",
      "properties": {
        "type": {
          "description": "Type of Script assertion",
          "const": "script",
          "type": "string"
        },
        "script": {
          "description": "Assertion script",
          "type": "string",
          "default": "`function test(assertion, variables) {\n  // It should return true if test is passed\n  // return true;\n}`"
        },
        "disabled": {
          "type": "boolean",
          "default": false
        }
      },
      "required": [
        "disabled",
        "script",
        "type"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# Compare

**Compare assertion** служит для сравнения 2 значений. В данном виде **Assertion**-а есть понятие компаратора - операции, с помощью которой сравниваются значения. Есть следующие виды компараторов:

* **equal** - проверка на равенство значений
* **not equal** - проверка на неравенство значений
* **greater** - проверка на то, что текущее значение больше ожидаемого
* **greater or equal** - проверка на то, что текущее значение больше ожидаемого или  равно ему
* **less** - проверка на то, что текущее значение меньше ожидаемого
* **less or equal** - проверка на то, что текущее значение меньше ожидаемого или равно ему

Интерфейс **Compare assertion**-а выглядит следующим образом:

![Интерфейс Compare assertion-а](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMoTO-UrojOGzKuxKG%2F-LiMohRm-BVZ3WRYmQ5b%2Fc_1.png?alt=media\&token=604e96de-005e-45da-9634-f06d9d4b7920)

На данном скрине имеются следующие поля:

* **Actual value** - текущее значение
* **Operator** - компаратор из списка выше
* **Expected value** - ожидаемое значение

### Исправление ошибок

Алгоритм исправления ошибок зависит от каждого конкретного компаратора.

* **equal** - ожидаемому значению присваивается текущее значение
* **not equal** - компаратор меняется на **equal**
* **greater** - компаратор меняется на **greater or equal** и ожидаемому значению присваивается текущее значение
* **greater or equal** - ожидаемому значению присваивается текущее значение
* **less** - компаратор меняется на **less or equal** и ожидаемому значению присваивается текущее значение
* **less or equal** - ожидаемому значению присваивается текущее значение

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

В файле **Assertion** имеет тип `compare` , описание самого типа можно найти в документации к [файловому представлению Assertion](/0.0.1-beta.16/node-types/assertion#failovoe-predstavlenie) в определении `#/definitions/CompareAssertion` .


# Contains

**Contains assertion** служит для проверки вхождения подстроки в строку.

Данный **Assertion** имеет следующий интерфейс:

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMoTO-UrojOGzKuxKG%2F-LiMqA9pfs2Sw3YF9An6%2Fco_1.png?alt=media\&token=04fc6a08-efc3-4c2d-b342-2f8a052db27e)

Данный **Assertion** имеет следующие поля:

* **Text** - текст, где будет производиться поиск
* **Value** - значение для поиска

### Исправление ошибок

У данного **Assertion**-а нет механизма исправления ошибок

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

В файле **Assertion** имеет тип `contains` , описание самого типа можно найти в документации к [файловому представлению Assertion](/0.0.1-beta.16/node-types/assertion#failovoe-predstavlenie) в определении `#/definitions/ContainsAssertion` .


# Script

**Script assertion** позволяет написать проверочный скрипт на языке JavaScript. Сам скрипт представляет из себя функцию с названием `test`, которая на вход принимает объект assertion-а и объект с переменными (в формате ключ-значение). В случае, если функция возвращает `true` считается, что проверка прошла успешно. Если функция возвращает `false` или бросает исключение, то считается, что запуск **Script assertion**-а завершился с ошибкой.

Данный **Assertion** имеет следующий интерфейс:

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMoTO-UrojOGzKuxKG%2F-LiMqKk9m74eiUK08Xya%2Fs_1.png?alt=media\&token=25a71ee8-bd27-4835-a4e4-bcbae852655e)

Данный **Assertion** имеет только одно поле - **script**, в котором находится скрипт из описания выше

### Исправление ошибок

У данного **Assertion**-а нет механизма исправления ошибок

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

В файле **Assertion** имеет тип `script` , описание самого типа можно найти в документации к [файловому представлению Assertion](/0.0.1-beta.16/node-types/assertion#failovoe-predstavlenie) в определении `#/definitions/ScriptAssertion` .


# XPath

**XPath assertion** позволяет проверить значение по XPath-селектору.

Данный **assertion** имеет следующий интерфейс:

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMoTO-UrojOGzKuxKG%2F-LiMqigZk5Cy3AUJ9gxl%2Fx_1.png?alt=media\&token=152c1fe3-8854-4f26-81c9-c2e4a381ce19)

**XPath assertion** имеет следующие поля:

* **Text** - текст, где будет производиться поиск
* **Path** - XPath селектор
* **Expected value** - ожидаемое значение по данному селектору

### Исправление ошибок

При исправлении ошибки в данном виде **Assertion**-а ожидаемому значению присваивается значение, лежащее по селектору.

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

В файле **Assertion** имеет тип `xpath` , описание самого типа можно найти в документации к [файловому представлению Assertion](/0.0.1-beta.16/node-types/assertion#failovoe-predstavlenie) в определении `#/definitions/XPathAssertion` .


# Link

Узел типа Link (ссылка) предназначен для повторно использования других узлов: RequestStep (включая Assertion) и сценариев (Folder).

## Принцип действия&#x20;

После выбора вызываемого узла, **Link** узел предоставляет возможность переопределить значения его переменных. **Link** узел вызывает исполнение другого узла, передавая ему заданные пользователем переменные. После выполнения, динамические переменные вызванного узла, устанавливаются как динамические переменные родительской группы **Link** узла. Таким образом результат выполнения доступен из любого соседствующего узла **Link**.

#### Из Link узла можно сослаться на:

* [RequestStep](/0.0.1-beta.16/node-types/requeststep) узел
* [Folder](/0.0.1-beta.16/node-types/folder) узел

#### Нельзя сослаться на:

* Другой **Link** узел (в том числе на самого себя)
* На любого предка **Link** узла (т.к. это вызовет при запуске бесконечный цикл)

{% hint style="info" %}
&#x20;Link узел предоставляет возможность переопределить значения переменных узла родителя.
{% endhint %}

{% hint style="warning" %}
При удалении узла, на который ссылается Link узел, ссылка будет считаться потерянной и запуск будет невозможен пока не будет указана корректная ссылка.
{% endhint %}

## Узел родитель

Создайте узел родитель, на который нужно ссылаться, и задайте ему необходимые [статически определяемые переменные](/0.0.1-beta.16/variables/user-variables/static-variables), например `postID`. Значение переменной можно не указывать.

![Создание переменных для узла родителя](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrUP_I2wt8JRAOTIo%2Fl_1.jpg?alt=media\&token=0ddded72-bae2-44e2-ace5-54b585876324)

## Узел Link

Создайте **Link** узел и укажите родителя, после этого отобразятся все созданные переменные родителя. В качестве переопределяемого значения можно использовать любые переменные или статическое значение.&#x20;

![Создание Link узла и выбор родителя](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrYUzKPma0ErHXhNj%2Fl_2.gif?alt=media\&token=23bd3e83-5b06-4164-8ab1-509f065511fc)

## Пример сценария

Рассмотрим пример, в котором, в качестве **Link** узла будем вызывать [RequestStep](/0.0.1-beta.16/node-types/requeststep) узел для удаления записи.

### Создание узла родителя

1. Создайте [RequestStep](/0.0.1-beta.16/node-types/requeststep) узел с именем **deletePost**
2. Тип запроса DELETE
3. В качестве URL используйте[ https://testmace-stage.herokuapp.com/posts/${id}](< https://testmace-stage.herokuapp.com/posts/${id}>)
4. Создайте для этого узла [статически определяемую переменную](/0.0.1-beta.16/variables/user-variables/static-variables) `id` с пустым значением

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrbQNUc1uEfXxWXb-%2Fl_3.gif?alt=media\&token=ac7a97bf-ebec-446b-9572-9ed1fc258634)

### Создание сценария

* Создайте [Folder](/0.0.1-beta.16/node-types/folder) узел с именем **scenario**
* Добавьте в scenario[ RequestStep](/0.0.1-beta.16/node-types/requeststep) узел с именем **createPost**:&#x20;
  * тип запроса: POST
  * URL: [https://testmace-stage.herokuapp.com/posts/](< https://testmace-stage.herokuapp.com/posts/${id}>)
  * body запрос JSON `{"title":"will delete with link node"}`
  * Выполняем запрос и присваиваем `id` созданной записи [динамической переменной](/0.0.1-beta.16/variables/user-variables/dynamic-variables) postId для узла **Scenario**.

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrcoO2XM6ONc0CZsH%2Fl_4.gif?alt=media\&token=fd36a09f-0266-4ecf-9707-1031a711d9af)

* Далее создаем **Link** узел с именем **deleteLink**
  * В качества родителя указываем узел **project/deletePost**
  * Для переменной `id` родителя **deletePost** в Link узле указываем Overridden Value `${$dynamicVar.postId}`
* Создадим [RequestStep](/0.0.1-beta.16/node-types/requeststep) узел **checkIfExists** для проверки удаления записи
  * Тип запроса: GET
  * URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>
  * Ожидаемый ответ сервера 404.

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrduTdT4bc9kgalMN%2Fl_5.gif?alt=media\&token=3120d7e1-b3b8-4f45-be2a-520e55e855f9)

## Пример проект для импорта [через URL](/0.0.1-beta.16/other/import/shared)

{% file src="/files/-LiMr55F1c6QspuvzbcH" %}

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

**Link** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат.

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Link node",
      "const": "Link",
      "type": "string"
    },
    "linkedNode": {
      "$ref": "#/definitions/NodeReference",
      "description": "Link to node"
    },
    "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",
    "linkedNode",
    "name",
    "type",
    "variables"
  ],
  "definitions": {
    "NodeReference": {
      "type": "object",
      "properties": {
        "refNodePath": {
          "description": "Absolute path to node",
          "type": "string"
        },
        "type": {
          "description": "Marker of reference entity",
          "const": "reference",
          "type": "string",
          "default": "reference"
        }
      },
      "required": [
        "refNodePath",
        "type"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# API description

TestMace имеет мощный функционал описания API, включая импорта из Swagger 2.0/ Openapi  3.0. Реализован данный функционал посредством следующих узлов:

* [ApiRootFolder](/0.0.1-beta.16/node-types/api-description/apirootfolder) - корневой узел описания API
* [ApiFolder](/0.0.1-beta.16/node-types/api-description/apifolder) - узел для группировки других узлов API
* [ApiRoute](/0.0.1-beta.16/node-types/api-description/apiroute) - узел для описания конкретного эндпоинта

В следующих разделах мы подробнее познакомимся с функцией каждого из данных узлов


# ApiRootFolder

**ApiRootFolder** - это корневой узел поддерева описания API. Он, по аналогии с [Project](/0.0.1-beta.16/node-types/project) узлом, является корневым элементом, и в пределах поддерева описания API может быть может быть только один элемент данного типа. В остальном повторяет функционал [ApiFolder](/0.0.1-beta.16/node-types/api-description/apifolder) узла.

Создать данный узел можно одним из следующих способов

* Из контекстного меню [Project](/0.0.1-beta.16/node-types/project) узла
* Воспользовавшись импортом из форматов описания API

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

**ApiRootFolder** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат:

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of ApiRootFolder node",
      "const": "ApiRootFolder",
      "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",
    "type",
    "variables"
  ],
  "definitions": {
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# ApiFolder

**ApiFolder** узел, по аналогии с [Folder](/0.0.1-beta.16/node-types/folder) узлом, служит для группировки других типов узлов (в данном случае [ApiRoute](/0.0.1-beta.16/node-types/api-description/apiroute) узлов). &#x20;

Создать данный узел можно следующими способами:

* Из контекстного меню [ApiRootFolder](/0.0.1-beta.16/node-types/api-description/apirootfolder) узла
* Воспользовавшись импортом из форматов описания API

В дереве проекта **ApiFolder** узел имеет следующий вид:

![Вид ApiFolder узла в дереве проекта](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsBurAEw8jjEkJrtf%2Faf_1.png?alt=media\&token=680ed8d0-b230-4c56-a2fd-6dc021bb00fe)

Контекстное меню данного узла выглядит следующим образом:

![Контекстное меню ApiFolder узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsEDI1oLvGTZfTmYQ%2Faf_2.png?alt=media\&token=1cf07376-2887-4c2d-9ac9-90c413997f7d)

* **Add node.** Добавление узла-потомка. В подменю можно выбрать тип узла.
* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название NodeName \[Copy \[number]].
* **Remove node.** Удалить узел.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

Интерфейс вкладки данного узла выглядит следующим образом:

![Интерфейс вкладки ApiFolder узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsHryxF8VAVuXeS0_%2Faf_3.png?alt=media\&token=736707f8-b932-4edd-a1f4-51aa787cf8de)

На данном скрине отмечены следующие области

* Диалог управления [пользовательскими переменными](/0.0.1-beta.16/variables/user-variables)
* Список дочерних узлов

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

**ApiFolder** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат:

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of ApiFolder node",
      "const": "ApiFolder",
      "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",
    "type",
    "variables"
  ],
  "definitions": {
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# ApiRoute

Данный узел служит для описания интерфейса конкретного эндпоинта. Интерфейс схож с [RequestStep](/0.0.1-beta.16/node-types/requeststep) узлом. Это и не удивительно - в обоих случаях мы имеем дело с HTTP-запросами.

Основные возможности данного типа узлов:

* Возможность описания http-заголовков, query параметров, body параметров запроса и HTTP-кодов, HTTP-заголовков, body параметров ответа
* Использование типов для описания каждого из заголовков, query параметров, body параметров. Поддерживаются следующие типы: `string`, `number`, `integer`, `boolean`, `array` и `object`.
* Добавление описаний для каждой из сущностей
* Поддержка описания нескольких параметров тела запроса (в зависимости от content-type)
* Поддержка описания нескольких возможный ответов от сервера
* Создание запроса из описания
* Автодополнение урлов, HTTP-заголовков, query параметров и body параметров в [RequestStep](/0.0.1-beta.16/node-types/requeststep) узлах.

## Обзор интерфейса

Для создание **ApiRoute** узла необходимо в контекстном меню [ApiFolder](/0.0.1-beta.16/node-types/api-description/apifolder) узла выбрать **Add node** -> **ApiRoute.**

### **Вид узла в дереве проекта**

В дереве **ApiRoute** узел выглядит следующим образом:

![Вид ApiRoute узла в дереве проекта](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsjdLErhFxCQUpVzR%2Far_1.png?alt=media\&token=21b635ae-a97e-4358-b8f2-c2c95028108c)

В качестве иконки у данного вида узла выступает название HTTP-метода. Контекстное меню выглядит следующим образом:

![Контекстное меню ApiRoute узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMslz8Y5XicOHnnV8p%2Far_2.png?alt=media\&token=faa4b280-b90e-4ec8-911f-8080e90ce282)

* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название NodeName \[Copy \[number]].
* **Remove node.** Удалить узел.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

### Интерфейс вкладки

Вкладка **ApiRoute** узла выглядит следующим образом:

![Вкладка ApiRoute узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMspLCONT78JfocOc6%2Far_3.png?alt=media\&token=a997d9f9-afcf-4903-bb20-8fd792925559)

#### Области общих параметров запроса

Рассмотрим подробнее верхнюю часть данной вкладки:

![Верхняя часть таба ApiRoute узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsscrBJx53fsqf00u%2Far_4.png?alt=media\&token=8029abe1-0053-409c-a01d-1c769ce21204)

На скрине обозначены следующие области:

1. Http-метод. Данный список совпадает со списком методов из [RequestStep](/0.0.1-beta.16/node-types/requeststep) узла
2. Url с поддержкой [механизма переменных](/0.0.1-beta.16/variables/variables)
3. Кнопка открытия [диалога работы с переменными](/0.0.1-beta.16/variables/user-variables)
4. Кнопка создания запроса из текущего описания API
5. Текстовое описание запроса

#### Область описания параметров запросов

В левой нижней части расположена область описания запроса. Она разделена на 3 вкладки: **Headers**, **Query parameters** и **Body** для редактирования HTTP-заголовков, query параметров и параметров тела запроса соответственно.

Рассмотрим вкладку **Headers**. Ее содержимое представлено в табличном виде. Для редактирования заголовков доступны следующие поля:

* Название заголовка
* Тип значения заголовка (список типов описан выше)
* Описание

Поддерживаются все стандартные операции.

Вкладка **Query Parameters** используется для редактирования query параметров, в остальном по функционалу идентична вкладке **Headers**.

Как уже было сказано, в **ApiRoute** узле можно описать несколько тел для одного и того же запроса. Например, по одному и тому же эндпоинту могут приниматься как данные с `Content-Type` равным `application/json`, так и с `application/xml`. Вкладка **Body** разделена как раз по `content-type` на вкладки и имеет следующий вид:

![Вид вкладки Body интерфейса описания запроса](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsvmecyriXA8KhPQP%2Far_5.png?alt=media\&token=10f32ea0-49d8-49ae-8473-8d94a367ad3e)

На скрине отмечены следующие области:

1. Кнопка редактирования текущего `content-type`. При нажатии на нее данное поле подменяется на текстовое поле, где можно ввести интересующий `content-type`.
2. Кнопка удаления тела запроса
3. Кнопка добавления тела запроса
4. Текущий `content-type` узла
5. Область редактирования тела запроса

Область редактирования тела запроса меняется в зависимости от `content-type` по следующему правилу: если `content-type` равен `application/x-www-form-urlencoded` или `multipart/form-data`, то область редактирования принимает табличный вид (аналогичный табличной области в **Headers** вкладке), в противном случае - текстовый как на скрине выше. В текстовой области в качестве формата описания используется [OpenAPI](https://swagger.io/specification/#requestBodyObject).

#### Область описания параметров запросов

В правой нижней области интерфейса вкладки **ApiRoute** узла расположена области редактирования ответов от сервера. Как уже было сказано, TestMace поддерживает описание нескольких ответов в рамках одного эндпоинта. Интерфейс данной области выглядит следующим образом:

![Интерфейс редактирования ответов сервера](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMszNK7ApEdzbaBel_%2Far_6.png?alt=media\&token=b6ff2068-1344-4527-95e0-71d17a081074)

Данный интерфейс разделен на вкладки, отдельно для каждого ответа. В рамках вкладки каждого ответа можно редактировать код ответа, описание, а также HTTP-заголовки и тела ответа, интерфейсы которых идентичны таковым из области запроса.

## Интеграция с RequestStep узлом

TestMace имеет интеграцию с **ApiRoute** узлами в **RequestStep** узлах. На данный момент эта интеграция проявляется в автодополнении url, HTTP-заголовков, query параметров, параметров тела запросов **RequestStep** узлов. Причем, для url-ов в автодополнении участвуют всех url-ы **ApiRoute** узлов, тогда как для остальных параметров автодополнение работает по следующему алгоритму:

* Берутся метод и url данного **RequestStep** узла
* Ищутся все **ApiRoute** узлы с такими url и методом
* Осуществляется поиск по искомому параметру (например, по HTTP-заголовку) среди найденных **ApiRoute** узлов

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

**ApiRoute** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат.

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of ApiRoute node",
      "const": "ApiRoute",
      "type": "string"
    },
    "url": {
      "type": "string",
      "default": ""
    },
    "method": {
      "$ref": "#/definitions/RequestMethod"
    },
    "description": {
      "type": "string",
      "default": ""
    },
    "requests": {
      "$ref": "#/definitions/ApiRequests",
      "description": "List of requests"
    },
    "responses": {
      "description": "List of responses",
      "type": "array",
      "items": {
        "$ref": "#/definitions/ResponseParameters"
      },
      "default": []
    },
    "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",
    "description",
    "method",
    "name",
    "requests",
    "responses",
    "type",
    "url",
    "variables"
  ],
  "definitions": {
    "RequestMethod": {
      "enum": [
        "DELETE",
        "GET",
        "OPTIONS",
        "PATCH",
        "POST",
        "PUT"
      ],
      "type": "string"
    },
    "ApiRequests": {
      "type": "object",
      "properties": {
        "queryParameters": {
          "description": "List of query parameters",
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "headers": {
          "description": "List of headers",
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "cookies": {
          "description": "List of cookies",
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "bodies": {
          "description": "List of bodies",
          "type": "array",
          "items": {
            "$ref": "#/definitions/RequestParameters"
          },
          "default": []
        }
      },
      "required": [
        "bodies",
        "cookies",
        "headers",
        "queryParameters"
      ]
    },
    "QueryParameter": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "type": {
          "enum": [
            "array",
            "boolean",
            "integer",
            "number",
            "object",
            "string"
          ],
          "type": "string"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "name",
        "type"
      ]
    },
    "RequestParameters": {
      "type": "object",
      "properties": {
        "contentType": {
          "type": "string"
        },
        "schema": {
          "anyOf": [
            {
              "$ref": "#/definitions/SchemaRef"
            },
            {
              "$ref": "#/definitions/OneOf"
            },
            {
              "$ref": "#/definitions/AllOf"
            },
            {
              "$ref": "#/definitions/AnyOf"
            },
            {
              "$ref": "#/definitions/ObjectMember"
            },
            {
              "$ref": "#/definitions/ArrayMember"
            },
            {
              "$ref": "#/definitions/ScalarMember"
            }
          ]
        }
      },
      "required": [
        "contentType",
        "schema"
      ]
    },
    "SchemaRef": {
      "type": "object",
      "properties": {
        "$ref": {
          "type": "string"
        }
      },
      "required": [
        "$ref"
      ]
    },
    "OneOf": {
      "type": "object",
      "properties": {
        "oneOf": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/SchemaRef"
              },
              {
                "$ref": "#/definitions/OneOf"
              },
              {
                "$ref": "#/definitions/AllOf"
              },
              {
                "$ref": "#/definitions/AnyOf"
              },
              {
                "$ref": "#/definitions/ObjectMember"
              },
              {
                "$ref": "#/definitions/ArrayMember"
              },
              {
                "$ref": "#/definitions/ScalarMember"
              }
            ]
          }
        }
      },
      "required": [
        "oneOf"
      ]
    },
    "AllOf": {
      "type": "object",
      "properties": {
        "allOf": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/SchemaRef"
              },
              {
                "$ref": "#/definitions/OneOf"
              },
              {
                "$ref": "#/definitions/AllOf"
              },
              {
                "$ref": "#/definitions/AnyOf"
              },
              {
                "$ref": "#/definitions/ObjectMember"
              },
              {
                "$ref": "#/definitions/ArrayMember"
              },
              {
                "$ref": "#/definitions/ScalarMember"
              }
            ]
          }
        }
      },
      "required": [
        "allOf"
      ]
    },
    "AnyOf": {
      "type": "object",
      "properties": {
        "anyOf": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/SchemaRef"
              },
              {
                "$ref": "#/definitions/OneOf"
              },
              {
                "$ref": "#/definitions/AllOf"
              },
              {
                "$ref": "#/definitions/AnyOf"
              },
              {
                "$ref": "#/definitions/ObjectMember"
              },
              {
                "$ref": "#/definitions/ArrayMember"
              },
              {
                "$ref": "#/definitions/ScalarMember"
              }
            ]
          }
        }
      },
      "required": [
        "anyOf"
      ]
    },
    "ObjectMember": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "object"
          ]
        },
        "properties": {
          "$ref": "#/definitions/SchemaMember"
        },
        "required": {
          "type": "boolean"
        },
        "additionalProperties": {
          "$ref": "#/definitions/ScalarMember"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "SchemaMember": {
      "type": "object",
      "additionalProperties": {
        "anyOf": [
          {
            "$ref": "#/definitions/SchemaRef"
          },
          {
            "$ref": "#/definitions/OneOf"
          },
          {
            "$ref": "#/definitions/AllOf"
          },
          {
            "$ref": "#/definitions/AnyOf"
          },
          {
            "$ref": "#/definitions/ObjectMember"
          },
          {
            "$ref": "#/definitions/ArrayMember"
          },
          {
            "$ref": "#/definitions/ScalarMember"
          }
        ]
      }
    },
    "ArrayMember": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "array"
          ]
        },
        "items": {
          "anyOf": [
            {
              "$ref": "#/definitions/SchemaRef"
            },
            {
              "$ref": "#/definitions/OneOf"
            },
            {
              "$ref": "#/definitions/AllOf"
            },
            {
              "$ref": "#/definitions/AnyOf"
            },
            {
              "$ref": "#/definitions/ObjectMember"
            },
            {
              "$ref": "#/definitions/ArrayMember"
            },
            {
              "$ref": "#/definitions/ScalarMember"
            }
          ]
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "items",
        "type"
      ]
    },
    "ScalarMember": {
      "type": "object",
      "properties": {
        "type": {
          "$ref": "#/definitions/ScalarSchemaType"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "ScalarSchemaType": {
      "enum": [
        "boolean",
        "integer",
        "number",
        "string"
      ],
      "type": "string"
    },
    "ResponseParameters": {
      "type": "object",
      "properties": {
        "code": {
          "description": "Http-code (e.g. 200, 404)",
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "headers": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "content": {
          "$ref": "#/definitions/RequestParameters",
          "description": "Response body"
        }
      },
      "required": [
        "code",
        "content"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# Импорт описания API

TestMace позволяет не только вручную задокументировать API, но и импортировать уже существующую документацию. На данный момент поддерживается импорт из форматов Swagger 2.0 и OpenAPI 3.0.

Импортировать описание API можно из контекстного меню + проекта, выбрав **Import** -> **Swagger** (аналогичное меню есть и в области Scratches):

![Контекстное меню проекта](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMtKQIIq4b8Y7FT7Wb%2Fim_1.png?alt=media\&token=f5de1b2d-6c5d-4a97-9ef0-bbb3d6ebaeb4)

При этом открывается диалог следующего вида:

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMtMyJHFHO5eoh25UQ%2Fim_2.png?alt=media\&token=2b3fb94a-3346-4a9d-9898-a0ce07d24361)

Как видите, на данный момент поддерживается как импорт из файла, так и загрузка API с удаленного сервера по URL. После выбора источника и нажатия на кнопку **OK** в дерево добавляется импортированное описание.

### Обновление описания API

Помимо загрузки описания API, можно также обновить уже существующие описание API . Для этого из контекстного меню [ApiRootFolder](/0.0.1-beta.16/node-types/api-description/apirootfolder) узла необходимо выбрать **Update api.** При этом откроется диалог как при импорте API. Стоит отметить, что все изменения в описании API, сделанные вручную, будут перетерты после обновления.


# Broken

При открытии проекта могут возникнуть ситуации, когда некоторые узлы не могут быть загружены. Примером такой ситуации является наличие merge конфликтов. В таких случаях проект загружает все возможные узлы, однако после открытия проекта пользователю показывается такое предупреждение:

![Предупреждение в случае наличия в проекте незагруженных узлов](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMte0JJQ45gAj9tq8k%2Fb_1.png?alt=media\&token=aa82e45e-4b0c-4c57-8cf7-87ca7db22450)

А в загруженном проекте появляются такие узлы:

![Вид Broken узла в дереве](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMtisxrwZeSwW-Wbb8%2Fb_2.png?alt=media\&token=cfa3609b-a880-4fdb-825b-96367bdec0d2)

Это **Broken** узел. Он не может быть создан вручную, а появляется, если при загрузке определенного узла произошли ошибки. Контекстное меню данного узла выглядит следующим образом:

![Контекстное меню Broken узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMtlMptczUpzeTB5vN%2Fb_3.png?alt=media\&token=2f0882f2-0ce7-4e62-94f4-16f8060f4d17)

* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

**Broken** узел не может быть открыть во вкладке и не от него нельзя создать каких-либо потомков. Основное предназначение - помочь пользователю исправить ошибку.


# Script

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

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

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

Окно редактирования узла разделено на две области - окно редактирования кода и окно консольного вывода. Для скрытия консоли нажмите на кнопку <img src="https://1795169151-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&amp;token=0b3a10fc-2c8a-40fa-a68c-5a8850f777e9" alt="" data-size="original"> .

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

* <img src="https://1795169151-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&amp;token=68cd8189-e348-46b5-91a8-14eac49912b2" alt="" data-size="original">/ <img src="https://1795169151-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&amp;token=75ba2757-b83a-4008-9e31-24722a1a4701" alt="" data-size="original"> - переключение между режимами сохранения результатов выполнения в консоли. <img src="https://1795169151-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&amp;token=68cd8189-e348-46b5-91a8-14eac49912b2" alt="" data-size="original"> - очистка консоли перед каждым запуском скрипта, <img src="https://1795169151-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&amp;token=75ba2757-b83a-4008-9e31-24722a1a4701" alt="" data-size="original"> - накопление результатов запуска.
* <img src="https://1795169151-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&amp;token=67103e9a-79e3-448e-99d6-463f5b9d2a9a" alt="" data-size="original"> - автоматическая прокрутка к последней строке вывода консоли
* <img src="https://1795169151-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&amp;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://1795169151-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://1795169151-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://1795169151-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://1795169151-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://1795169151-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://1795169151-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://1795169151-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://1795169151-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#"
}
```


# Пользовательские переменные

Раздел “Переменные” - это key-value хранилище для сохранения и повторного использования каких-либо данных. Зачастую используется для удаления дублирования и повышения читаемости: согласитесь, переменная с названием greetingUrl говорит о большем, чем просто строка <https://next.json-generator.com/api/json/get/EJvQVEVGL>.

Механизм переменных очень хорошо интегрирован во все части приложения и обладает следующими особенностями:

* Значения переменных могут быть строками, объектами и массивами и содержать ссылки на другие переменные.
* Переменные задаются для каждого узла и наследуются от узлов родителей.
* Значение переменных может ссылаться на другие переменные.
* Имена [встроенных переменных](/0.0.1-beta.16/variables/variables) начинаются с $.

### Использование переменных

Использовать переменные можно в любых строковых параметрах узлов. Примерами таких параметров могут служить url, название заголовка, токен авторизации и многое многое другое. Для того, чтобы использовать переменную необходимо использовать следующий формат `${variableName}`, где `variableName` - это ссылка на переменную. Вот несколько примеров.

* `${id}`
* `${$dynamicVar.id}`
* `${$response.body.name}`

В полях параметров узлов можно комбинировать строки и ссылки на переменные. Например, в качестве url вы можете использовать следующую строку `http://${host}/posts/${$dynamicVar.id}`

Для обращения к элементу массива, которых сохранен в переменной, можно воспользоваться следующим синтаксисом `${variableName[index]}` . Например, для обращения к id третьей сущности из ответа необходимо написать `${$response.body[2].id}` . Обратите внимание, что индексация начинается с нуля.&#x20;

Для переменных работает автодополнение

![Автодополнение переменных](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMuFFKgZGs5cuIEhIy%2Fuv_1.gif?alt=media\&token=8c92811d-3c4f-48b8-a6d6-79a92b0aca68)

и подсветка значения переменной при наведении на нее

![Подсветка значения переменной](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMuIDuHPhY4ieNJGmf%2Fuv_2.png?alt=media\&token=4dc3116c-e6dd-4a31-9adc-04aca846f866)

В интерфейсе каждого узла есть кнопка variables с помощью которой вызывается диалог  переменных. Выглядит данная кнопка следующим образом:

![Кнопка открытия диалога переменных](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMuLP7hf6Kl1GHtlIx%2Fuv_3.png?alt=media\&token=4eccb436-af9f-4405-b44e-af200e6dd516)

Данная кнопка существует выглядит одинаково для всех типов узлов. В следующих разделах мы подробнее рассмотрим механизм работы с переменными.


# Статически определяемые переменные

Пользователь имеет возможность определять собственные переменные, которые привязываются к определенному узлу. Названия переменных не могут начинаться с символа $ т.к. в соответствии с соглашением данный формат зарезервирован для [встроенных переменных](/0.0.1-beta.16/variables/variables). Также механизм переменных поддерживает наследование переменных от предков и переопределение их в потомках.

Для редактирования переменных необходимо вызвать [диалог переменных](/0.0.1-beta.16/variables/user-variables). Во вкладке Variables вы можете увидеть таблицу переменных, принадлежащих только данному узлу. Вкладка выглядит следующим образом:

![Диалог редактирования пользовательских переменных](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMudFmHEnWhUGdjgqS%2Fs_1.png?alt=media\&token=890c90d6-bfbd-4d11-bff4-12cf95f3b3ff)

В значении переменных можно также обращаться к другим переменным. Использую переменные, пример выше можно представить следующим образом:

![Использование ссылок на переменные при определении значений переменных](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMufFtsw7xs5ywiCey%2Fs_2.png?alt=media\&token=64bd4818-7285-4e13-8828-4aa677eb907d)


# Динамические переменные

Динамические переменные - это переменные, значения которых определяются во время выполнения сценария. Сохранение авторизационных токенов, идентификаторов вновь созданных сущностей - вот яркие варианты использования данного механизма. Он состоит их двух частей - Variable assignment и собственно динамических переменных.

### Variable assignment

Это создание привязки части запроса к какой-либо динамической переменной. На данный момент данную привязку можно сделать только в [RequestStep](/0.0.1-beta.16/node-types/requeststep) узле. Для иллюстрации давайте создадим запрос который создает новый пост и сохраним id созданного постав в динамическую переменную.

Создаем запрос и выполняем его. К примеру, давайте сделаем запрос на POST <https://testmace-stage.herokuapp.com/posts>, с телом `{"title":"Our cool post!"}` . В данном случае RequestStep узел выглядит так:

![RequestStep после выполнения запроса](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMv1-_1PBbcv_9qnro%2Fd_1.png?alt=media\&token=40002d5b-a894-46e1-a0a5-96996fb0b052)

Теперь из parsed response на параметр id из контекстного меню вызовем диалог присваивания динамической переменной.

![Вид контекстного меню](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMv3_gPF04RLw6OEjw%2Fd_2.png?alt=media\&token=d07e0d86-2652-4cf0-96f7-7bb7f743b1e6)

Выберем пункт Assign to variable. Откроется диалог присваивания переменной

![Диалог присвоения динамической переменной](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMv6iwCGaSI3xglCyW%2Fd_3.png?alt=media\&token=7f0cc565-89f7-491e-9a5f-59529ed51285)

В данном диалоге отмечены следующие пункты

1. Путь в переменной `$request`, из которого будет браться значение
2. Выпадающий список предков, которым можно назначить динамическую переменную
3. Текущее значение по данному пути
4. Название динамической переменной

Создадим переменную с именем `id` в данном узле.

После присвоения динамической переменной ее можно найти в списке динамических переменных того узла, где производилось присвоение, т.е, в [RequestStep](/0.0.1-beta.16/node-types/requeststep) узле. Список динамических переменных можно найти в [диалоге переменных](/0.0.1-beta.16/variables/user-variables) на вкладке Dynamic variables.

![Список динамических переменных RequestStep узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMv9b3IDvlZpwkDk_M%2Fd_4.png?alt=media\&token=01d78d68-b1ce-4c00-aaad-e4a879f43c4d)

### Использование динамических переменных

Все динамические переменные, доступные для конкретного узла, хранятся в переменной `$dynamicVar`. Например, чтобы сослаться на переменную `id`, созданную выше, необходимо написать `$dynamicVar.id`. Как и в случае с другими переменными, данный вид переменных поддерживает наследование и переопределение в потомках.


# Встроенные переменные

Встроенные переменные - это переменные специального назначения, которые нельзя переопределить. Использовать их можно также, как и обычные переменные.

* `$parent` - ссылка на узел-предка
* `$prevStep` - ссылка на предыдущий узел в рамках [Folder](/0.0.1-beta.16/node-types/folder) узла
* `$nextStep` - ссылка на следующий узел в рамках [Folder](/0.0.1-beta.16/node-types/folder) узла
* `$dynamicVar` - объект [динамических переменных](/0.0.1-beta.16/variables/user-variables/dynamic-variables)
* `$response` - ссылка на response в [RequestStep узле](/0.0.1-beta.16/node-types/requeststep)
* `$env` - объект [переменных окружения](/0.0.1-beta.16/variables/env)
* `$systemVar`- объект для доступа к системным переменным окружения


# Переменные окружения

Позволяют в один клик переключать значения переменных используемых в проекте.

Механизм переменных окружения позволяет создавать переключаемые переменные, например, для переключения **stage** и **prod** сред.

### Создание переменных окружения

В примере мы создадим одну переменную serverUrl для сред stage и prod.

1. Нажмите на значок настройки переменных окружения.
2. Во всплывающем окне создайте новое окружение нажав на "Add enviroment" с именем stage.
   * Создайте переменную serverUrl, в качестве значения переменной укажите адрес stage сервера.
3. Добавьте prod окружение  нажав на "Add enviroment".
   * Создайте переменную serverUrl, в качестве значения переменной укажите адрес prod сервера.

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMvdgtIENqEafXv0x-%2Fenv_1.gif?alt=media\&token=3f0b2a72-b1d3-446c-991a-96c7efa57d58)

### Импорт окружения из Postman

TestMace позволяет импортировать окружения из [Postman](https://learning.getpostman.com/docs/postman/environments_and_globals/manage_environments/). Для этого необходимо нажать на кнопку **+ Import environment**, которая находится в диалоге редактирования переменных окружения под списком доступных окружений

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Ll_qpPCSEz_TL29pZRd%2F-Ll_tGF0qb6nQSiMCCSs%2FKSpgFN9.png?alt=media\&token=f5339d86-8a8c-4423-a937-d278967bbf1d)

После нажатия на кнопку **+ Import environment** всплывает диалог, в котором необходимо ввести путь до файла.&#x20;

### Использование переменных окружения

Для использования переключаемых переменных обращайтесь к`${$env.%VARIABLE%}.`Заменим во всех узлах значение url нашей переменной:`${$env.serverUrl}` Теперь в любой момент, вы можете переключить значения этой переменной.

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMtpiZOkqva1t-DrvG%2F-LiMvepOZAOjDp9BnQy0%2Fenv_2.gif?alt=media\&token=da5b25f7-2f1d-447a-8d70-eaa9179e3037)

#### Где можно использовать переменные?

Переменные окружения (также, как и обычные переменные) можно использовать в любом строковом поле узла.

### Локальные окружения

Локальные окружения отличаются от обычных только тем, что не сохраняются в файлы проекта, а хранятся в локальном хранилище приложения. Данный вид окружений рекомендуется использовать для локальных и приватных данных. К таким данным могут относиться логины, пароли, API-токены и т.д.&#x20;

В сайдбаре локальные окружения находятся в нижней части. Каждое локальное окружение имеет  префикс `local`, чтобы явно отличать их от обычных окружений.

![Диалог переменных окружения с локальными окружениями](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LmEwBwnJ7PFKqey4cJE%2F-LmEzXkrXXuni1wYU0a0%2Fscreenshot_2.png?alt=media\&token=35902c45-5c10-4334-bc79-2cebcfde5968)

Используя механизм drag-and-drop локальные окружения можно превращать в обычные и наоборот.

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LmEwBwnJ7PFKqey4cJE%2F-LmF-6mF5bOdlv_y0aEc%2FPeek%202019-08-14%2016-00.gif?alt=media\&token=09236135-fc0e-4dd0-90f9-8f5a08e8bdf8)


# Cookie

Cookie  — небольшой фрагмент данных, который отправляется веб-сервером и хранится на компьютере пользователя.

## Создание Cookie

TestMace позволяет управлять Cookie для хостов. Нажмите на кнопку "Cookie" в верхнем меню для вызова модального окна настройки Cookie. Откроется список всех существующих записей, для создания новой нажмите кнопку add и заполните поля:

|    Тип поля   | Значение                                                                                                                                             |
| :-----------: | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|    **Key**    | Имя cookie                                                                                                                                           |
|   **Value**   | Значение cookie                                                                                                                                      |
|   **Domain**  | Устанавливает домен, в рамках которого действует cookie                                                                                              |
|    **Path**   | Устанавливает путь на сайте, в рамках которого действует cookie                                                                                      |
|  **Expires**  | Устанавливает дату истечения срока хранения cookie. Дата должна быть представлена в формате, который возвращает метод `toGMTString()` объекта `Date` |
|   **Secure**  | Отмеченный селектор указывает, что для пересылки cookie на сервер следует использовать SSL                                                           |
| **Http only** | Отмеченный селектор только для тех cookie, к которым не требуется обращаться через JavaScript.                                                       |

Так же имеется возможность создания Cookie из row string, например:

`isLogged=1; Expires=31/12/2019 00:00:00; Domain=testmace-stage.herokuapp.com; Path=/posts/; Secure;`

![Создание Cookie](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMvpzdt46slJDWDMiT%2F-LiMwA-ywJWH809fT6CZ%2Fcoo_1.jpg?alt=media\&token=531eae1f-1bfd-4b15-9610-41a272dc11b1)

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

Запланировано в следующем релизе.

## Удаление Cookie

Откройте окно управления Cookie и нажмите на символ корзины напротив записи подлежащей удалению.

![Удаление Cookie](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMvpzdt46slJDWDMiT%2F-LiMwEE6tBK7J9cf34nj%2Fcoo_2.jpg?alt=media\&token=455b4851-6dd6-4b38-8f93-7a21dc1ca970)


# Авторизация

Проверка, что вам разрешен доступ к запрашиваемому ресурсу.

## Типы авторизации

* [No auth ](/0.0.1-beta.16/work-with/authorization#no-auth)
* [Inherit from parent ](/0.0.1-beta.16/work-with/authorization#inherit-from-parent)
* [Basic auth ](/0.0.1-beta.16/work-with/authorization#basic-auth)
* [Bearer auth](/0.0.1-beta.16/work-with/authorization#bearer-auth)&#x20;
* [Digest Auth ](/0.0.1-beta.16/work-with/authorization#digest-auth)
* [OAuth 1.0](/0.0.1-beta.16/work-with/authorization#oauth-1-0)

{% hint style="info" %}
В качестве параметров авторизации: Username, Password, Token и др. можно использовать [переменные окружения](/0.0.1-beta.16/variables/env).
{% endhint %}

## No auth&#x20;

Используйте «No Auth», если для отправки запроса не нужна авторизация.

## Inherit from parent&#x20;

**Значение по умолчанию**, свойства авторизации наследуются от узла родителя. Если параметры авторизации не заданы у родителя будет использоваться тип "[No auth](/0.0.1-beta.16/work-with/authorization#no-auth)".

## Basic auth

Используется, если для отправки запроса нужен логин и пароль.

#### Использование Basic auth

Откройте запрос и выберите вкладку «Authorization», выберите тип «Basic auth». В появившихся полях укажите Username и Password.&#x20;

![Использование Basic auth](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwJlX--4fwrhxafXO%2F-LiMwdhd85FeLhiWFzYx%2Fau_1.jpg?alt=media\&token=bc366b8e-c8c9-4e27-814b-8f535fe5bc17)

## Bearer auth&#x20;

Bearer auth  - авторизация через токен. Любой пользователь с токеном-носителем может использовать его для доступа к ресурсам.

#### Использование Bearer auth

Откройте запрос и выберите вкладку «Authorization», выберите тип «Bearer auth». В появившемся поле укажите Token.&#x20;

![Использование Bearer auth](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwJlX--4fwrhxafXO%2F-LiMwg3YpGdpuXjrg8FD%2Fau_2.jpg?alt=media\&token=6edd377d-74eb-4c4f-9482-69f10a00248e)

## Digest Auth&#x20;

Данный метод отправляет хеш-сумму логина, пароля, адреса сервера и случайных данных, и предоставляет больший уровень защиты, чем базовая аутентификация, при которой данные отправляются в открытом виде.

#### Использование Digest Auth

Откройте запрос и выберите вкладку «Authorization», выберите тип «Basic auth». В появившихся полях укажите Username и Password.&#x20;

![Digest Auth с использованием переменных окружения](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwJlX--4fwrhxafXO%2F-LiMwiePJL3t9a9w8Dnc%2Fau_3.jpg?alt=media\&token=e8bbe6cb-a258-433b-b9bd-58bf6964c981)

## OAuth 1.0

Позволяет получить доступ к защищённым ресурсам без необходимости передавать логин и пароль.

#### Использование OAuth 1.0

Откройте запрос и выберите вкладку «Authorization», выберите тип «OAuth 1.0». В появившихся полях укажите данные доступа.

#### Таблица поддерживаемых параметров для OAuth 1.0 в TestMace

| **Параметры**    | Описание                                                   |
| ---------------- | ---------------------------------------------------------- |
| Consumer Key     | Ключ                                                       |
| Consumer Secret  | Код ключа                                                  |
| Access Token     | Токен                                                      |
| Token Secret     | Код токена                                                 |
| Signature Method | Метод шифрования сигнатуры: PLAINTEXT, HMAC-SHA1, RSA-SHA1 |
| Version          | 1.0                                                        |
| Realm            | Хост на который отсылается запрос                          |

![Использование OAuth 1.0](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwJlX--4fwrhxafXO%2F-LiMwlvxgQWs30K7peld%2Fau_4.jpg?alt=media\&token=acaaba8e-5d05-45d8-a739-8df9baf385ea)


# Proxy

Настройка proxy находится в разделе File -> Settings. Включите поддержку proxy "Enable Proxy" и введите значения Proxy переменных.

{% hint style="info" %}

#### **Управление proxy осуществляется при помощи следующих переменных:**

* **http\_proxy** — адрес proxy для запросов без SSL
* **https\_proxy** —  адрес proxy для запросов с SSL
* **no\_proxy** — список хостов через запятую, для которых не нужно использовать proxy

#### **Примеры значений no\_proxy:**

* **`*google.com`** - не передавать запросы HTTP / HTTPS в Google.&#x20;
* **`google.com:443`** - не отправлять HTTPS-запросы в Google, но отправлять HTTP-запросы в Google.&#x20;
* **`google.com:443, yahoo.com:80`** - не передавать HTTPS-запросы в Google и не передавать HTTP-запросы в Yahoo!
* **`*`**- полностью игнорировать переменные окружения https\_proxy / http\_proxy.
  {% endhint %}

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMx8Gow0mVdGoJYS6w%2Fsett_1.jpg?alt=media\&token=2a9d6dd5-c61f-4012-846c-c948f877444c)


# Массовое редактирование таблиц

Некоторые таблицы в приложении поддерживают массовое редактирование. Подобные таблицы имеют сверху кнопку **BULK EDIT**. При переходе в данный режим редактирования содержимое таблицы преобразуется в текстовое представление - значения в строке разделяются соединяются по символу **:,** а строки разделяются по символу перевода строки. Для отключения строки необходимо в начале строки поставить **//.**

Рассмотрим для примера редактирование заголовков в RequestStep узле, который поддерживает массовое редактирование. Так выглядит обычный режим редактирования списка заголовков.

![Стандартный режим редактирования HTTP-заголовков запроса](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMxVS6YPB-QxAIGpCx%2Ft_1.png?alt=media\&token=89a68aac-3c1c-441f-a993-26f623f297d9)

При нажатии на **BULK EDIT** виджет приобретает следующий вид.

![Режим массового редактирования заголовков](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMxY0pET0qTS-gR0T9%2Ft_2.png?alt=media\&token=f754deff-fc0a-4105-8b56-462c10da4b02)

Можем заметить, что значения в пределах строки разделены символом двоеточия, а сами строки разделены переводами строк. Давайте попробуем отключить первую строку. Для этого напишем в начале //.

![Отключение строки в режиме массового редактирования](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMx_MFhsikGdlCF6zq%2Ft_3.png?alt=media\&token=ada590d8-04f4-48fc-9d96-e48570a83325)

И перейдем в табличный вид нажатием на кнопку **TABLE EDIT**. Таблица будет выглядеть следующим образом

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMxbAzOOLrLJicRgYH%2Ft_4.png?alt=media\&token=01d76cf7-72af-4202-a722-eaeae734122f)

Видим, что в первой строке галочка отключена, следовательно, сама строка не будет участвовать в запросе.


# Импорт & Экспорт

В данном разделе мы подробно рассмотрим функционал меню проекта **Import**. Вызвать его можно нажатие на кнопку **+** в верхней части дерева проекта (либо в верхней части панели **Scratches**). Выглядит данное меню следующим образом:

![Контекстное меню Import](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMxodaQagPkXIOxIdO%2Fi_1.png?alt=media\&token=93660fe8-586d-445c-9a9e-896b488fec8f)

Меню **Import** состоит из следующих пунктов:

* [**Shared**](/0.0.1-beta.16/other/import/shared) - загрузка экспортированных ранее узлов
* [**cURL**](/0.0.1-beta.16/other/import/curl) - импорт запроса из cURL
* [**Swagger**](/0.0.1-beta.16/other/import/swagger) - импорт описания API из [Swagger/OpenAPI](https://swagger.io/specification/)
* [**Postman**](/0.0.1-beta.16/other/import/postman) - импорт коллекций из [Postman](https://learning.getpostman.com/docs/postman/collections/sharing_collections/)

В следующих подразделах мы рассмотрим подробнее каждый из данных пунктов.


# Shared

TestMace имеет удобный способ поделиться узлами и целыми поддеревьями проекта. Чтобы импортировать поддерево необходимо в контекстном меню интересующего узла выбрать **Share**.

В качестве примера рассмотрим экспорт проекта из "[Быстрого старта](/0.0.1-beta.16)".&#x20;

![Shared экспорт](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMyaFTxhXcnwjELntO%2Fshared_1.gif?alt=media\&token=cd1d7fdb-cbe0-42fd-9c98-1cff38e062c3)

При этом в буфер обмена копируется URL вида `testmace://....`.

Теперь можно импортировать данный url в интересующий вас узел. Для этого есть два способа:

* импорт из контекстного меню проекта **Import** -> **Shared**
* импорт из контекстного меню [Folder](/0.0.1-beta.16/node-types/folder) или [Project](/0.0.1-beta.16/node-types/project) узла **Import** -> **Shared**

Диалог импорта выглядит следующим образом:

![Диалог импорта узла](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMydc-Y9FfNGUqrUMF%2Fshared_2.png?alt=media\&token=5049c0fa-848f-41d8-a23c-b81798780d3a)

В поле **Name** есть возможность задания имени корневого узла импортируемого поддерева. В поле **URL** необходимо задать ранее экспортированный url. Если при импорте поддерева имя корневого узла уже существует в списке детей предка, то имя будет иметь вид NodeName \[Copy \[number]].

Сам процесс импорта проиллюстрирован ниже:

![Shared импорт](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMwrJP_C5mDsvflAID%2F-LiMyg_AfU5UbXN_wb5_%2Fshared_3.gif?alt=media\&token=398bdb30-800b-42b5-af48-ddb3ef0889b8)


# cURL

[cURL](https://curl.haxx.se/) - это инструмент командный строки, который позволяет взаимодействовать с сервисами с помощью различных протоколов с синтаксисом URL. На данный момент он широко используется в том числе и для отсылки HTTP-запросов через командную строку. TestMace позволяет импортировать команду curl с параметрами в [RequestStep](/0.0.1-beta.16/node-types/requeststep) запрос.

Есть два способа импорта запроса из cURL:

* импорт из контекстного меню проекта **Import** -> **cURL**
* импорт из контекстного меню [Folder](/0.0.1-beta.16/node-types/folder) или [Project](/0.0.1-beta.16/node-types/project) узла **Import** -> **cURL**

При этом открывается диалоговое окно следующего вида:

![Диалоговое окно импорта из cURL](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMyuoOuZ63Z9l2N0kE%2F-LiMz55YfLrDslKi1R0k%2Fcurl_1.png?alt=media\&token=901155b9-89c7-4a93-8c9c-239bf432e1e3)

В данном окне необходимо задать имя нового [RequestStep](/0.0.1-beta.16/node-types/requeststep) узла и команду для импорта.

Рассмотрим для примера случай, когда запрос в виде cURL копируется из списка запросов браузера

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMyuoOuZ63Z9l2N0kE%2F-LiMz6LRqAWaIJM8pu60%2Fcurl_2.gif?alt=media\&token=f011d3fe-9454-48ac-a90f-f24a6a19d9a7)


# Swagger

Импорт из Swagger/OpenAPI подробно рассмотрен в разделе [Импорт описания API](/0.0.1-beta.16/node-types/api-description/api-desc-import)


# Postman

Postman имеет возможность [поделиться коллекцией запросов](https://learning.getpostman.com/docs/postman/collections/sharing_collections/). TestMace поддерживает импорт данного формата. Импортировать Postman коллекции можно следующим образом:

* импорт из контекстного меню проекта **Import** -> **Postman**
* импорт из контекстного меню [Folder](/0.0.1-beta.16/node-types/folder) или [Project](/0.0.1-beta.16/node-types/project) узла **Import** -> **Postman**

При этом открывается диалог следующего вида:

![Импорт коллекции из Postman ](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMyuoOuZ63Z9l2N0kE%2F-LiMzPgGrK8utn3ObmGq%2Fpostman_1.png?alt=media\&token=1d2c772f-9777-4e2f-b878-bce12efe174f)

Здесь необходимо указать путь до файла с импортированной коллекцией. Если при импорте поддерева имя корневого узла уже существует в списке детей предка, то имя будет иметь вид NodeName \[Copy \[number]].


# HTTP-заголовки по умолчанию

Folder и Project узлы имеют возможность устанавливать HTTP-заголовки, которые наследуются потомками и подставляются в запросах RequestStep узлов по умолчанию. Рассмотрим возможности задания и использования заголовков по умолчанию.

### Определение HTTP-заголовков по умолчанию

Заголовки по умолчанию определяются в Folder узле. Для это в панели инструментов Folder узла необходимо нажать на кнопку **Headers**

![](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMyuoOuZ63Z9l2N0kE%2F-LiMzgKB_FUHGyPh4HhD%2Fh_1.png?alt=media\&token=b4d1e8b3-b186-43be-be11-a47738ab2934)

При этом откроется диалог редактирования HTTP-заголовков по умолчанию.

![Диалог редактирования HTTP-заголовков по умолчанию](https://1795169151-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMyuoOuZ63Z9l2N0kE%2F-LiMzhW7Do7qiNgv46vK%2Fh_2.png?alt=media\&token=e75069a7-5440-40dc-a43f-a4927654638a)

В верхней части мы видим нередактируемый список заголовков, унаследованных от предков. В нижней части расположены заголовки, принадлежащие данному Folder узлу. Помимо добавления, удаления и редактирования (в том числе [массового редактирования](/0.0.1-beta.16/other/bulk-table-editing)) есть возможность отключения заголовков, то есть в итоговом запросе отключенный заголовок фигурировать не будет. Состояние заголовков (включен/отключен) также наследуется.&#x20;

Имеется возможность переопределения заголовков в потомках. Например, определение заголовка `RootDefaultHeader1` со значением `Hello, TestMace` переопределит унаследованный заголовок и в потомках текущего Folder узла значение заголовка `RootDefaultHeader1` будет `Hello, TestMace` . Отметим, что само значение `RootDefaultHeader1`  у **предка** текущего Folder узла останется неизменным, `Hello, world` .

### Использование заголовков по умолчанию

Заголовки по умолчанию используются в запросах RequestStep узлов. Они подставляются автоматически и не требуют участия пользователя. Интерфейс редактирования заголовков в RequestStep узле схож с таковым из Folder узла.

### Хранение заголовков по умолчанию в файловой системе

Обратитесь к описанию формата хранения [Folder](/0.0.1-beta.16/node-types/folder) узла. В частности, для хранения списка заголовков используется поле `requestData.headers` а для хранения отключенных заголовков используется `requestData.disabledInheritedHeaders` поле. Для [RequestStep](/0.0.1-beta.16/node-types/requeststep) узла формат аналогичен.


# Быстрый старт

Данное руководство позволит вам быстро освоить интерфейс и основные функции TestMace.

{% hint style="info" %}
В этом руководстве мы протестируем работу back-end сервера для записей типа post на следующем сценарии:

* запросим у сервера все имеющиеся записи
* добавим новую запись
* проверим корректное добавление записи
* обновим только что созданную запись и проверим корректность обновления через ответ от сервера
* запросим обновленную запись от сервера
* проверим, что на сервере запись действительно обновлена
* удалим запись
* проверим, что на сервере запись не существует

**Для этого нам потребуется не более 10 минут, после запуска программы.**
{% endhint %}

## Установка TestMace

Скачать TestMace можно по ссылкам ниже или с сайта <https://client.testmace.com>

* Windows <https://client.testmace.com/download/?os=windows>&#x20;
* Mac OS <https://client.testmace.com/download/?os=mac>
* Linux <https://client.testmace.com/download/?os=linux>

Запустите скачанный файл  и следуйте инструкциям инсталлятора, во время установки будет предложено выбрать директорию установки приложения.

{% hint style="warning" %}
*Для установки TestMace на Windows запустите инсталлятор **с правами администратора.***
{% endhint %}

По завершению установки запустите приложение. Перед вами откроется новый проект.&#x20;

## Обзор интерфейса

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lvej9kSTR5zIj5eqAT6%2F-LvejCCMEOC2u95BBA49%2Fmain%20screen.jpg?alt=media\&token=b31121b3-89e6-4899-88e0-a1b0e5b51ca0)

## Ваш первый GET запрос

Для создания первого запроса создайте новую вкладку нажав на **+**. При этом в зоне "Scrathes Area" будет создан узел с названием **Scratch 1**. Вставьте в поле URL адрес: <https://testmace-stage.herokuapp.com/posts>. Можно сразу протестировать ответ сервера из "Scrathes Area" или перенести наш черновик в проект. Для удобства переименуйте этот узел, дав ему название **getPosts**.&#x20;

{% hint style="info" %}
Обратите внимание, что все изменения в проекте сохраняются автоматически в режиме реального времени.
{% endhint %}

![Создание шаблона GET запроса](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhWmHEyt7Wg_pwGOK%2Fgetting_started_1.gif?alt=media\&token=a449b957-5d13-4714-bd85-ffdf0a8506de)

Создайте в проекте узел типа [Folder](/node-types/folder) с названием **posts** и перенесите созданный черновик **getPosts** из "Scratch Area" в "Project Area".

![Создание Folder узла и перенос шаблона GET запроса](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhbUocmpVlEgJv8Wx%2Fgetting_started_2.gif?alt=media\&token=98edc4c3-659c-45f8-bb60-14fc441b0161)

Откройте двойным кликом созданный запрос **getPosts** и выполните его нажав на кнопку "Run".

![Запуск GET запроса](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhh6Qu8HogBVo8YVV%2Fgetting_started_3.gif?alt=media\&token=2994c506-2517-4eb5-8d5b-0cfdac3e46ef)

Мы видим, что запрос выполнен успешно, в **Response Area** получен список существующих записей.  Давайте рассмотрим этот экран подробнее:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMhmH053dp3fjyobYv%2Frun%20screen.png?alt=media\&token=f7605fac-dd77-40c1-a4a7-eb21b3810a93)

{% hint style="info" %}

#### Request parameters

Здесь вы можете указать http заголовки, а так же передать параметры запросу с автодополнением и использование переменных.

#### Request type

* **GET** — получение ресурса
* **POST** — создание ресурса
* **PUT** — обновление ресурса
* **DELETE** — удаление ресурса
* **PATCH** — для частичного изменения ресурса
* **OPTIONS** — для описания параметров соединения с ресурсом

#### URL

Поле URL поддерживает автодополнение, а так же использование переменных. Мы воспользуемся этими функциями чуть позже.&#x20;

#### Make Request

Выполнение запроса или группы запросов при запуске из корня проекта или ноды типа folder

#### Response area

Зона ответа сервера, вкладка Response Body может быть представлена в виде: Parsed, JSON, text. В соседних вкладках можно посмотреть Response Headers, а так же создать или посмотреть существующие Assertion узлы для запроса.
{% endhint %}

## POST запрос и Assertion

Давайте теперь добавим новую запись типа post на сервер, для этого нам нужно создать новый [RequestStep](/node-types/requeststep) узел.&#x20;

{% hint style="info" %}
**Существует три способа добавления нового узла в проект:**

1. Мы можем создать черновик (Scratch) нажав на **+** и позже перенести его в проект используя Drag and Drop;&#x20;
2. Можно нажать правой кнопкой мыши по узлу родителю и выбрать **Add node -> Request step**;&#x20;
3. Можно нажать на кнопку **Add project node-> Add node -> Request step**.&#x20;
   {% endhint %}

Создайте новый узел любым из этих способов и задайте ему имя **createPost**.&#x20;

1. Выберите для этого узла "**Request type**" значением POST
2. В поле URL вставьте <https://testmace-stage.herokuapp.com/posts>
3. Во вкладке body выберите тип данных JSON и добавьте `{"title": "Testing post", "content": "Sendt via TestMace"}`
4. Выполните запрос нажав на кнопку RUN.&#x20;

Будет получен ответ об успешном добавлении записи, но нам нужно проверить, что запись добавлена корректно, для этого мы воспользуемся механизмом быстрого создания [Assertion](/node-types/assertion) узлов. Мы сравним отправляемые данные с полученными от сервера.

В зоне "Response Area" в формате Parsed нажмите правой кнопкой мыши по **значению title**, которое мы передавали в  запросе, выберите **Create Assertion -> Compare -> Equal.** После этого узел [Assertion](/node-types/assertion) будет создан и открыт, нам дополнительной настройки не требуется, поэтому закроем его. Аналогично создадим Assertion узел для значения Content.

А теперь запустим запрос **createPost** и интерфейс проинформирует нас об успешном выполнении теста. Это совсем не сложно, посмотрите анимацию ниже:

![POST запрос и создание Assertion](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMi-YplERQn7P7vAdh%2Fgetting_started_4.gif?alt=media\&token=72a8ead4-09d7-4042-bcf3-5dfc4baac62b)

### Динамические переменные

Для того, чтобы мы могли взаимодействовать с созданной нами записью на сервере, нужно передавать в последующие [Request step](/node-types/requeststep) значение её **Id**. Создадим динамическую переменную **postId** и присвоим ей значение Id возвращаемое в записи после выполнения **CreatePost**.&#x20;

1. Кликните правой кнопкой мыши по значению **Id** в Response body ноды **CreatePost**,&#x20;
2. Выберите пункт **Assign to variable**.&#x20;
3. Во всплывающем окне в качестве ноды выберите директорию проекта **posts**, введите имя переменной: **postId** и нажмите **ОК**.

Для того чтобы обратиться к переменной используйте [встроенную переменную](/variables/variables) `$dynamicVar`:

```
${$dynamicVar.postId}
```

![Создание динамической переменной](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMi7013WKadQVvXiGl%2Fgetting_started_5.gif?alt=media\&token=062fae05-2749-47ee-8cb9-f3ca2ebb949b)

## PUT запрос&#x20;

На этом этапе мы будем использовать запрос типа PUT. Обратимся  к записи созданной на предыдущем шаге при помощи динамической переменной: `${$dynamicVar.postId}` и обновим  значения записи **title** и **content**.

1. Создайте [RequestStep](/node-types/requeststep) узел c именем **updatePost**
2. Request type выберите **PUT**
3. URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>
4. Body: `{"title": "Testing post updated", "content": "Updated via TestMace"}`
5. Выполним запрос и аналогично шагу **POST запрос**, создадим два [Assertion](/node-types/assertion) узла для сравнения отправленных и полученных значений **title** и **content**.

![Создание PUT запроса](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMiCJFpZet2AU5b53U%2Fgetting_started_6.gif?alt=media\&token=f2afbe7f-c124-4766-a83f-f9a41eeba3fd)

## Проверка изменений

В некоторых случаях необходимо провести дополнительную проверку изменений записи, так как сервер может ответить на PUT запрос успешным выполнением, а при обращении через GET запрос мы получим старую запись.&#x20;

Для этого мы создадим GET запрос по URL записи с использованием динамической переменной:

1. Создайте новый [RequestStep](/node-types/requeststep) узел с именем **getPost**
2. Тип запроса: GET
3. URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>
4. Выполните запрос и создайте 2 [Assertion](/node-types/assertion) узла для сравнения данных **title** и **content**.

![Проверка изменений через GET запрос](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMiT5mOsq1gAMPerMW%2Fgetting_started_7.gif?alt=media\&token=5e59de9b-f62d-41bc-837b-64cc73fefb57)

## DELETE запрос

Следующий шаг - удаление созданной нами записи по URL записи с использованием динамической переменной:

1. Создайте узел типа [RequestStep](/node-types/requeststep) с именем **deletePost**
2. Тип запроса: DELETE
3. URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>

![DELETE запрос](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMiZW7ZpmWWOjtKxmv%2Fgetting_started_8.gif?alt=media\&token=85f97180-fbe5-49ed-9f42-9bb64452d528)

## Проверка DELETE

Для того, чтобы убедиться, что созданная запись была удалена с сервера, создадим GET запрос  по URL записи с использованием динамической переменной, мы ожидаем, что при запросе получим ответ сервера: 404, поэтому создадим соответствующий Assertion узел:

1. Создайте узел типа [RequestStep](/node-types/requeststep) с именем **checkIfNodeExists**
2. Тип запроса: GET
3. URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>
4. Выполните запрос и в зоне Response Area выберите пункт **Assertions** и добавьте новый [Assertion](/node-types/assertion) узел, нажав ADD. Внесите данные узла:
   1. Actual value: `${$response.code}`
   2. Operator: `=`
   3. Expected value: `404`

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMifs1DC9bLBWd_0OX%2Fgetting_started_9.gif?alt=media\&token=2a4955ea-9330-482d-bfd4-79856fea6587)

## Заключение

В результате мы получили набор тестов для нашего сервера, которые можно последовательно выполнить, перейдите в узел **posts** и нажмите RUN.&#x20;

![Запуск сценария](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMgwmbAbE7nK7xCbnP%2F-LiMijSU3AugGlYW8Hb9%2Fgetting_started_10.gif?alt=media\&token=19974399-a80a-4c9d-8929-1481ff85ddff)

## Видео инструкция

Посмотрите весь процесс создания сценария описанного в руководстве на видео

{% embed url="<https://youtu.be/Gyg_4w78KBo>" %}

## Код для импорта через [shared](/other/import/shared)

{% file src="/files/-LiMgl1CXlo1QrHQ-pvL" %}
Быстрый старт Share код
{% endfile %}

## Скачать проект

Разархивируйте  в директорию проектов TestMace.

{% file src="/files/-LiMgePcyczxfcL4KgnN" %}
Быстрый старт
{% endfile %}


# Облачная синхронизация

Test Mace позволяет работать в команде над проектами и синхронизировать их в облачном хранилище

## Характеристики для тарифных планов

|                       | FREE   | PROFESSIONAL | ENTERPRISE |
| --------------------- | ------ | ------------ | ---------- |
| Пользователи          | 1      | 1-25         | ∞          |
| Дисковое пространство | 200 МБ | 2000 МБ      | ∞          |
| Одновременные сессии  | 1      | 1-25         | ∞          |

## Для работы с облачной синхронизацией потребуется

1. Зарегистрироваться в [панели управления](https://dashboard.testmace.com/)
2. Создать команду и проект
3. Выбрать и активировать тарифный план
4. Добавить в команду и в проект нужных пользователей (другие пользователи должны быть также зарегистрированы в панели управления)
5. В приложении Test Mace выполнить вход под своим аккаунтом
6. Выбрать и загрузить проект

Далее подробно разберем каждый шаг.

{% hint style="info" %}
Для работы с облачной синхронизацией нужно в первую очередь создать аккаунт в [панели управления](https://dashboard.testmace.com/), создать команду и проект, и добавить пользователей.
{% endhint %}

## Регистрация

Перейдите по ссылке: [https://dashboard.testmace.com/](https://dashboard.testmace.com/register). Для создания аккаунта воспользуйтесь кнопками "Sign in with GitHub" или "Sign in with Google". Так же аккаунт можно создать используя электронную почту, для этого нажмите на ссылку "Click here to create one" и заполните поля регистрации, после чего авторизуйтесь в панели управления.

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LqjZkug7Dlq4RtBECAw%2F-LqjaE0RB4A7llyaTVtQ%2Fsign_up2.png?alt=media\&token=fbd55c25-6bca-4e5b-ae09-c382f9944f9c)

## Команда и проекты

После авторизации перейдите в раздел Teams и создайте новую команду. Перейдите в новую команду и добавьте в неё новый проект.

![Создание команды и проекта](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LqjZkug7Dlq4RtBECAw%2F-Lqk5Koiu2tUTfLsdPq6%2Fcloud-1.gif?alt=media\&token=9489b969-8ab6-4cb4-88bc-e2a03238e86a)

### Добавление пользователей в команду

{% hint style="info" %}
Пользователи, которых нужно добавить в команду, должны быть зарегистрированы в [панели управления](https://dashboard.testmace.com).&#x20;
{% endhint %}

По умолчанию, после создания команды и проекта в них находится один пользователь - их создатель, чтобы добавить новых пользователей в команду, нужно активировать тарифный план **Professional** с нужным числом пользователей от 2 до 25.

Перейдите в свою команду и выберите интересующий тарифный план, после чего произведите активацию подписки.&#x20;

![Активация Professional тарифа](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LqjZkug7Dlq4RtBECAw%2F-Lqk9MfNza809RfeDgL4%2Fcloud-2.gif?alt=media\&token=ae1d97e4-5ea6-4473-b099-b40590312311)

{% hint style="info" %}
Добавьте всех пользователей в вашу команду и распределите пользователей по проектам.
{% endhint %}

![Добавление пользователя в команду и в проект](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LqkBUVJEi_wl_gASFHM%2F-LqkcXbEchtm2Z7nX0zr%2Fcloud-3.gif?alt=media\&token=b32b8ea3-bfcd-4809-a0ab-5d1eaf5434fc)

## Авторизация в приложении и выбор проекта

В приложении Test Mace нажмите на кнопку <img src="https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lwqh7R_NDRZTxYgn0PT%2F-Lwqk71lELtwiZpySaXb%2Fcloud-1.jpg?alt=media&amp;token=a8f67a78-7452-41cf-84fc-a1255e5eb814" alt="" data-size="original"> и авторизуйтесь, используя данные созданные ранее. При успешной авторизации на месте <img src="https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lwqh7R_NDRZTxYgn0PT%2F-Lwqk8i-Nr7sP7jjxvcA%2Fcloud-1.jpg?alt=media&amp;token=c18616da-753f-484a-ad4e-32f9dc0405b6" alt="" data-size="original"> появится имя учетной записи, нажмите на него и выберите пункт Teams, в правой части окна отобразятся все доступные проекты для этой команды, выберите нужный проект и нажмите "Open"

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lwqh7R_NDRZTxYgn0PT%2F-LwqjihfAlp28dYyyYaf%2Fcloud-1.gif?alt=media\&token=9e7ad5d2-4fbe-4eab-843b-4f5d3c9306e4)

## Синхронизация проекта

Чтобы выполнить синхронизацию вы должны быть авторизованы в приложении Test Mace. Нажмите на кнопку <img src="https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lwqh7R_NDRZTxYgn0PT%2F-LwqkbKdFWV0-RlAGvVX%2Fcloud-2.jpg?alt=media&amp;token=4e36eef6-0d26-4b3d-ad6f-a0715b5a56cc" alt="" data-size="original"> для выполнения синхронизации.

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lwqh7R_NDRZTxYgn0PT%2F-LwqlM3mV_Fjov8B6o7m%2Fcloud-2.gif?alt=media\&token=626722c6-9f07-4862-8e30-ebd24d1cdac1)

### Состояния синхронизации

| Статус синхронизации                                                                                                                                                                                                                                               | Пояснение                             |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------- |
| <img src="https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lwqh7R_NDRZTxYgn0PT%2F-Lwqrih-WrZ-cvGTu64m%2Fcloud-3.jpg?alt=media&amp;token=53c024dd-ea2a-4b84-a3a9-c3f98806a3fb" alt="" data-size="original"> | Изменений в проекте нет               |
| <img src="https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lwqu0gAVvO4PsWJG0t8%2F-LwrXs7x4qqZiTY8eouk%2Fcloud-2.jpg?alt=media&amp;token=3bc5ff85-5e61-4d2f-a8d0-57e7c287176f" alt="" data-size="original"> | Есть локальные или облачные изменения |
| <img src="https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lwqu0gAVvO4PsWJG0t8%2F-LwrXu4lyFi1ZdxnhikA%2Fcloud-4.jpg?alt=media&amp;token=4b8ecf9d-418c-4040-b5dc-356ebcfbcd9f" alt="" data-size="original"> | Есть локальные и облачные изменения   |


# Меню

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lwqh7R_NDRZTxYgn0PT%2F-Lwqt6aBnCC7tiniuWFA%2Fmenu.png?alt=media\&token=da4daf77-de69-4931-93c9-2fcb67aa7b73)

* **Undo и Redo** - отмена и повтор действий. На данный момент поддерживаются все действия связанные с изменением проектов и узлов.
* [**Cookies**](/work-with/cookie) - диалог для работы с cookies.
* [**Environments**](/variables/env) - конфигурация и выбор текущего environment.
* [**Save in Cloud**](/cloud-sync) - облачная синхронизация проекта
* **Settings** - настройки приложения
* **Sign In** - войти в аккаунт


# Обзор интерфейса

### Интерфейс приложения разделен на 3 глобальные группы <a href="#interfeis-prilozheniya-razdelen-na-3-globalnye-gruppy" id="interfeis-prilozheniya-razdelen-na-3-globalnye-gruppy"></a>

1. Дерево проекта
2. Область шаблонов
3. Главная область

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lvein3UvBds-gwhsTuW%2F-Lvej8Nl1pr74uKW7_j4%2Fmain%20screen.jpg?alt=media\&token=6f0b5ef2-5d1b-4201-be65-81cbb90bf41b)

### Главная область или область запроса так же разделена на группы <a href="#glavnaya-oblast-ili-oblast-zaprosa-tak-zhe-razdelena-na-gruppy" id="glavnaya-oblast-ili-oblast-zaprosa-tak-zhe-razdelena-na-gruppy"></a>

1. Тип запроса
2. URL
3. Запуск
4. Параметры запроса
5. Зона ответа от сервера

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lx0GVUpvwZ3_qQ8s6QR%2F-Lx0HDNyUaQD3vloi-YM%2Frun%20screen.png?alt=media\&token=6fe5f1ce-6ce8-49dc-af65-5d5874b2b5a1)


# Черновики

{% hint style="info" %}
**Scratches — это черновики узлов , которые вы можете  вы переносить в основное дерево проекта**
{% endhint %}

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-Lx0CWUQnIwcZPYCFGVf%2F-Lx0GOxpAHRaEkzMZFjG%2Fdrafts-1.gif?alt=media\&token=511cf626-1116-4dc4-bc3a-72805ff22e72)


# Типы узлов

{% hint style="info" %}
Узел - это любой элемент дерева проекта или черновиков
{% endhint %}

### Типы узлов

* [**Project**](/node-types/project)**.** Это корневой узел, создается автоматически при создании проекта. В остальном повторяет функциональные возможности Folder узла.
* [**Folder**](/node-types/folder)**.** Позволяет группировать Folder и RequestStep узлы внутри себя.
* [**RequestStep**](/node-types/requeststep). Это узел, с помощью которого можно сделать запрос. В качестве дочернего элемента он может иметь только один Assertion узел.
* [**Assertion**](/node-types/assertion). Узел используется для написания тестов. Может быть дочерним узлом только для RequestStep узла.
* [**Script**](/node-types/script). Позволяет запускать произвольный скрипт на языке JavaScript с возможностью обращения к API приложения.
* [**Link**](/node-types/link). Позволяет сослаться на уже существующую ноду.
* [**Api description**](/node-types/api-description)
  * [**ApiRootFolder**](/node-types/api-description/apirootfolder)**.** Корневой элемент (папка) для описания API
  * [**ApiFolder**](/node-types/folder)**.** Служит для объединения логически близких эндпоинтов при описании API (например, эндпоинты с одинаковыми url-ами но разными методами)
  * [**ApiRoute**](/node-types/api-description/apiroute)**.** Описание конкретного эндпоинта
* [**Broken**](/node-types/broken)**.**  Используется для описания узлов, загрузка которых завершилась с ошибкой. Не может быть создан вручную и не сохраняется в файловую систему.


# Горячие клавиши

Использование горячих клавиш в TestMace

| Назначение               | Сочетание клавиш   |
| ------------------------ | ------------------ |
| **Навигация**            |                    |
| Фокус на дерево проекта  | Ctrl + 1           |
| Фокус на шаблоны         | Ctrl + 2           |
| Фокус на главную область | Ctrl + 3           |
| Открыть настройки        | Ctrl + Alt + S     |
| **Табы**                 |                    |
| Предыдущий таб           | Ctrl + Shift + Tab |
| Следующий таб            | Ctrl + Tab         |
| Закрыть таб              | Ctrl + W           |
| Создать новый шаблон     | Ctrl + T           |
| **Дерево проекта**       |                    |
| Фокус на поле поиска     | Ctrl + F           |
| Открыть узел             | Enter              |
| Открыть меню узла        | Alt + Insert       |
| Удалить узел             | Delete             |
| Переименовать узел       | Ctrl + F6          |
| Следующий узел           | ↓                  |
| Предыдущий узел          | ↑                  |
| Развернуть узел          | →                  |
| Свернуть узел            | ←                  |
| **Проект**               |                    |
| Run Node                 | Ctrl + Enter       |
| Focus Url                | Ctrl + E           |
| Save Project             | Ctrl + S           |
| Save Project as          | Ctrl + Shift + S   |
| Open Project             | Ctrl + O           |
| Create New Project       | Ctrl + N           |
| Undo                     | Ctrl + Z           |
| Redo                     | Ctrl + Shift + Z   |


# Project

Узел типа **Project** - корневой элемент проекта. Он создается автоматически при создании нового проекта и в дальнейшем повторяет функционал [Folder](/node-types/folder) узла. **Project** узел также не может быть создан вручную и не может использоваться в качестве потомка других типов узлов.

{% hint style="warning" %}
На данный момент переименование папки Project не поддерживается из приложения. Кроме того, переименование папки Project напрямую в файловой системе сломает проект.
{% endhint %}


# Folder

Данный тип узла используется для группировки других узлов. В качестве предков для данного типа узла могут выступать [Project](/node-types/project) и **Folder** узлы. В дереве проекта узел выглядит следующим образом:

![Вид Folder узла в дереве](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMkb3-DX1GM-t41kVp%2F-LiMmTIIcnPTqxcvqNKY%2Ff_1.png?alt=media\&token=be6e7ec3-e670-49f7-bbc5-6e441ec56e9b)

В дереве для данного типа узла доступны следующие пункты меню:

![Контекстное меню для Folder узла](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMkb3-DX1GM-t41kVp%2F-LiMmVgGhUcgkI5BfQ3f%2FF_2.png?alt=media\&token=965e0b09-8ea5-4833-ada7-8a79412da056)

* **Add node.** Добавление узла-потомка. В подменю можно выбрать тип узла.
* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название **NodeName \[Copy \[number]]**.
* **Remove node.** Удалить узел.
* **Run.** Запустить узел.
* [**Share**](/other/import/shared)**.** Поделиться узлом. При это в буфере обмена создается ссылка, которая содержит всю информацию о текущем узле.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

Открытие узла открывается двойным кликом по узлу в дереве. Вкладка **Folder** узла выглядит следующим образом:

![Вкладка с открытым Folder узлом](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMkb3-DX1GM-t41kVp%2F-LiMmZZV7lGYhAkNysCD%2Ff_3.png?alt=media\&token=70509ecd-5aa5-4fa9-b719-643315e26a6c)

На скрине отмечены следующие области

1. Кнопка **Run** для запуска узлов внутри Folder узла
2. Панель управления
3. Кнопка **Headers** для задания наследуемых HTTP-заголовков
4. Кнопка **открытия** [**диалога переменных**](/variables/user-variables)
5. Область **дочерних узлов**
6. Проверка на то, что узел имеет валидный SSL сертификат. Используется в качестве наследуемого параметра в [RequestStep](/node-types/requeststep) узле
7. **Авторизация**

Рассмотрим данные области подробнее.

### Панель управления

Назначение кнопки **Run** описано выше. Стоит добавить, что при запуске узла кнопка меняет вид на следующий:

![Вид кнопки Run в процессе запуска узла](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMkb3-DX1GM-t41kVp%2F-LiMmaMjx53JO9Hq1Xmv%2Ff_4.png?alt=media\&token=b5028006-c46d-498b-809f-44e69d9dcfe9)

При нажатии на **Abort** можно прервать выполнение узла.

Кнопка **Headers** позволяет задать [наследуемые HTTP-заголовки](/other/default-http-headers).

Редактирование переменных обсуждается в разделе [Пользовательские переменные](/variables/user-variables).

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

**Folder** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат.

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Folder node",
      "const": "Folder",
      "type": "string"
    },
    "authData": {
      "$ref": "#/definitions/IAuthorizationData",
      "description": "Authorization parameters"
    },
    "requestData": {
      "$ref": "#/definitions/IRequestParametersData",
      "description": "Request parameters"
    },
    "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": [
    "authData",
    "children",
    "name",
    "requestData",
    "type",
    "variables"
  ],
  "definitions": {
    "IAuthorizationData": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "IRequestParametersData": {
      "type": "object",
      "properties": {
        "headers": {
          "description": "Headers",
          "type": "array",
          "items": {
            "$ref": "#/definitions/NameValueParam"
          }
        },
        "disabledInheritedHeaders": {
          "description": "Names of disabled headers",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "strictSSL": {
          "$ref": "#/definitions/StrictSSLOptions",
          "description": "Requires SSL certificates be valid"
        }
      },
      "required": [
        "disabledInheritedHeaders",
        "headers",
        "strictSSL"
      ]
    },
    "NameValueParam": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "value": {
          "type": "string"
        },
        "isChecked": {
          "type": "boolean"
        }
      },
      "required": [
        "name",
        "value"
      ]
    },
    "StrictSSLOptions": {
      "enum": [
        "Inherit",
        "No",
        "Yes"
      ],
      "type": "string"
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# RequestStep

**RequestStep** узел - это узел для отправки HTTP-запросов. Наш инструмент позволяет гибко сконфигурировать запрос и использовать его как отдельно, так и в составе сценария.&#x20;

### Представление RequestStep узла в дереве проекта

Для создания **RequestStep** узла необходимо в контекстном меню [Folder](/node-types/folder) узла или [Project](/node-types/project) узла выбрать пункт **Add node** -> **RequestStep**.&#x20;

В дереве проекта **RequestStep** узел выглядит следующим образом

![Вид RequestStep узла в дереве](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMn8brxTqg9NyauFGQ%2Fr_1.png?alt=media\&token=bad90b90-b617-484a-be06-772296e84c6f)

Остановимся на узле поподробнее. Цвет левого верхнего кружка указывает на статус HTTP-запроса: серый - если запрос не выполнялся, зеленый - в случае успешного HTTP-кода (например, 200, 201 и т.д.), красный - в случае неудачного HTTP-кода (например, 404, 500 и т.д.). Цвет иконки листочка указывает на статус выполнения дочернего [Assertion](/node-types/assertion) узла: серый - если запуск не выполнялся, зеленый - в случае если после запуска, [Assertion](/node-types/assertion) узел либо отсутствует, либо существует и его выполнение завершилось успешно, красный - в случае, если выполнение [Assertion](/node-types/assertion) узла завершилось с ошибкой (не все проверки были пройдены).

В дереве для данного типа узла доступны следующие пункты меню:

![Контекстное меню для RequestStep узла](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnC-lWL3HbKt7n8v6%2Fr_2.png?alt=media\&token=f7c7f321-6640-4a8f-878f-a45b3e97dc74)

* **Add node.** Добавление узла-потомка. В подменю можно выбрать тип узла.
* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название NodeName \[Copy \[number]].
* **Remove node.** Удалить узел.
* **Run.** Запустить узел.
* [**Share**](/other/import/shared)**.** Поделиться узлом. При это в буфере обмена создается ссылка, которая содержит всю информацию о текущем узле.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

### Описание вкладки RequestStep узла

При создании **RequestStep** узла (или при двойном клике по уже существующему) открывается вкладка данного узла. Выглядит она следующим образом:

![Вкладка RequestStep узла](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnEvykjaSi-HmvyaO%2Fr_3.png?alt=media\&token=16228eaa-d70d-4745-ad8c-5532c8f5b6e8)

Рассмотрим подробнее каждую из частей интерфейса.&#x20;

#### Секция конфигурирования запроса

Верхняя часть запроса выглядит следующим образом:

![Верхняя часть запроса](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnHqzZyYcsjZwlpwR%2Fr_4.png?alt=media\&token=2c24d661-d1c9-4da2-b0bf-9dae21081de2)

На скрине выше отмечены следующие пункты

1. Метод запроса. На данный момент поддерживаются следующие методы:
   * **GET** — получение ресурса
   * **POST** — создание ресурса
   * **PUT** — обновление ресурса
   * **DELETE** — удаление ресурса
   * **PATCH** — для частичного изменения ресурса
   * **OPTIONS** — для описания параметров соединения с ресурсом
2. Поле для URL.
3. Кнопка для запуска запроса
4. Кнопка [редактирования переменных](/variables/user-variables)

Ниже представлена панель редактирования заголовков, query параметров, авторизации и тела запроса. Так выглядит данная панель для POST запросов:

![Панель редактирования параметров запроса](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnLAHkLfKFdOIj3XQ%2Fr_5.png?alt=media\&token=3857f903-abe2-44a4-a91a-f03827d78c31)

Данная панель организована в виде вкладок. На данный момент существуют следующие вкладки:

* **Headers** - для редактирования списка HTTP-заголовков
* **Query parameters** - для редактирования списка query параметров
* **Body** - для конфигурирования тела запроса
* **Authorization** - для конфигурирования [авторизаций](/work-with/authorization).
* **Other** - конфигурирование прочих параметров запроса

Вкладки **Headers** и **Query** parameters с точки зрения интерфейса очень похожи - это обычные таблицы с возможностью [массового редактирования](/other/bulk-table-editing) и отключением строк. Отдельно стоит добавить, что заголовки поддерживают механизм установки [HTTP-заголовков по умолчанию](/other/default-http-headers).&#x20;

Вкладка **Other** выглядит следующим образом:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnPKjfaH4wV8iveo2%2Fr_6.jpg?alt=media\&token=88df025b-8b5b-4eb5-8949-05235399c0fb)

На данный момент можно отредактировать параметр **Requires SSL certificates be valid** - проверять валидность SSL-сертификата узла. Параметр по умолчанию: **Inherit**, наследует значение родителя узла, если у родителя задан Inherit, параметр выключен. Возможные варианты:

* Yes — да
* No — нет
* Inherit — наследовать

Отдельно остановимся на вкладке **Body**, которая выглядит следующим образом:

![Вкладка Body](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnT7hfXfRdavga1tf%2Fr_7.png?alt=media\&token=9b1dde6f-51f5-4248-8460-ed5e21f55ddf)

В выпадающем списке можно выбрать тип тела. На данный момент поддерживаются следующие типы

* **JSON** - для отправки JSON данных. Сами данные редактируются в текстовом поле с подсветкой JSON-синтаксиса и с поддержкой [механизма переменных](/variables/user-variables) . При отправке запроса в список HTTP-заголовков добавляется заголовок `Content-Type` со значением `application/json` .
* **Form data** - для редактирования `multipart/form-data` форм. Имеет табличный вид с возможностью [массового редактирования](/other/bulk-table-editing) . В строках таблицы в качестве значения могут выступать как обычные строки, так и ссылки на файлы.
* **Form URL encoded** - для редактирования `application/x-www-form-urlencoded` форм. Имеет табличный вид с возможностью [массового редактирования](/other/bulk-table-editing) .
* **File** - для отправки в теле содержимое файла.
* **XML** - для отправки XML данных. Сами данные редактируются в текстовом поле с подсветкой XML-синтаксиса и с поддержкой [механизма переменных](/variables/user-variables) . При отправке запроса в список HTTP-заголовков добавляется заголовок `Content-Type` со значением `application/xml` .
* **Text** - для отправки текстовых данных. Сами данные редактируются в текстовом поле с поддержкой [механизма переменных](/variables/user-variables) . При отправке запроса в список HTTP-заголовков добавляется заголовок `Content-Type` со значением `text/plain` .

#### Секция конфигурирования ответа

Давайте выполним запрос на url <https://testmace-stage.herokuapp.com/posts> и посмотрим, как выглядит секция ответа:

![Секция ответа RequestStep узла](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMmi1feMjxGB4KfBAE%2F-LiMnXC3T2KRgRyj96nm%2Fr_8.png?alt=media\&token=94f12efb-b450-4ce2-805b-76b4d2d24327)

Верхняя часть секции показывает краткую информацию об ответе: код ответа с указанием, успешный он или нет, время выполнения запроса и размер ответа.

Нижняя область секции ответа разбита на несколько вкладок:

* **Response body** - содержит тело ответа, представленное различными способами. На данный момент имеются следующие представления тела ответа:
  * **Parsed**- ответ в виде дерева. Каждый лист дерева имеет контекстное меню для создания [Assertion](/node-types/assertion) узлов и для работы с [динамическими переменными](/variables/user-variables/dynamic-variables)
  * **JSON** - JSON-подсветка тела ответа. Существует только в случае, когда тело ответа пришло в формате json.
  * **XML -** XML-подсветка тела ответа. Существует только в случае, когда тело ответа пришло в формате XML.
  * **HTML** - HTML-подсветка тела ответа. Показывается в случае, если тело ответа - HTML-страница
  * **Text** - текстовое представление тела ответа без подсветки&#x20;
  * **Preview** - отрендеренный вариант тела ответа. Показывается в случае, если тело ответа - HTML-страница
* **Response headers** - список HTTP-заголовков ответа
* **Assertions** - список assertion-ов, которые содержатся в дочернем [Assertion](/node-types/assertion) узле.

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

**RequestStep** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат:

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Folder node",
      "const": "RequestStep",
      "type": "string"
    },
    "assignVariables": {
      "description": "List of variables assignments",
      "type": "array",
      "items": {
        "$ref": "#/definitions/AssignVariable"
      },
      "default": []
    },
    "requestData": {
      "$ref": "#/definitions/IRequestData"
    },
    "authData": {
      "$ref": "#/definitions/IAuthorizationData",
      "description": "Authorization parameters"
    },
    "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": [
    "assignVariables",
    "authData",
    "children",
    "name",
    "requestData",
    "type",
    "variables"
  ],
  "definitions": {
    "AssignVariable": {
      "type": "object",
      "properties": {
        "path": {
          "description": "Path in $response variable (e.g. body.id)",
          "type": "string"
        },
        "assign": {
          "$ref": "#/definitions/NodeReference",
          "description": "Link on target node (one of parents)"
        },
        "variable": {
          "description": "Name of dynamic variable in target node",
          "type": "string"
        }
      },
      "required": [
        "assign",
        "path",
        "variable"
      ]
    },
    "NodeReference": {
      "type": "object",
      "properties": {
        "refNodePath": {
          "description": "Absolute path to node",
          "type": "string"
        },
        "type": {
          "description": "Marker of reference entity",
          "const": "reference",
          "type": "string",
          "default": "reference"
        }
      },
      "required": [
        "refNodePath",
        "type"
      ]
    },
    "IRequestData": {
      "type": "object",
      "properties": {
        "request": {
          "description": "Common request parameters",
          "type": "object",
          "properties": {
            "method": {
              "$ref": "#/definitions/RequestMethod",
              "description": "HTTP-method"
            },
            "url": {
              "type": "string"
            }
          },
          "required": [
            "method",
            "url"
          ]
        },
        "params": {
          "description": "Query parameters",
          "type": "array",
          "items": {
            "$ref": "#/definitions/NameValueParam"
          }
        },
        "body": {
          "$ref": "#/definitions/IRequestBody",
          "description": "Body parameters"
        },
        "headers": {
          "description": "Headers",
          "type": "array",
          "items": {
            "$ref": "#/definitions/NameValueParam"
          }
        },
        "disabledInheritedHeaders": {
          "description": "Names of disabled headers",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "strictSSL": {
          "$ref": "#/definitions/StrictSSLOptions",
          "description": "Requires SSL certificates be valid"
        }
      },
      "required": [
        "body",
        "disabledInheritedHeaders",
        "headers",
        "params",
        "request",
        "strictSSL"
      ]
    },
    "RequestMethod": {
      "enum": [
        "DELETE",
        "GET",
        "OPTIONS",
        "PATCH",
        "POST",
        "PUT"
      ],
      "type": "string"
    },
    "NameValueParam": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "value": {
          "type": "string"
        },
        "isChecked": {
          "type": "boolean"
        }
      },
      "required": [
        "name",
        "value"
      ]
    },
    "IRequestBody": {
      "type": "object",
      "properties": {
        "type": {
          "$ref": "#/definitions/RequestBodyType",
          "description": "Type of body"
        },
        "jsonBody": {
          "description": "JSON string of body",
          "type": "string"
        },
        "xmlBody": {
          "description": "XML string of body",
          "type": "string"
        },
        "textBody": {
          "type": "string"
        },
        "formData": {
          "description": "multipart/form-data form",
          "type": "array",
          "items": {
            "$ref": "#/definitions/RequestStepFormData"
          }
        },
        "formURLEncoded": {
          "description": "application/x-www-form-urlencoded form",
          "type": "array",
          "items": {
            "$ref": "#/definitions/NameValueParam"
          }
        },
        "file": {
          "description": "Link on file, which will be used as a content for body",
          "type": "string"
        }
      },
      "required": [
        "file",
        "formData",
        "formURLEncoded",
        "jsonBody",
        "textBody",
        "type",
        "xmlBody"
      ]
    },
    "RequestBodyType": {
      "enum": [
        "File",
        "FormData",
        "FormURLEncoded",
        "Json",
        "Text",
        "Xml"
      ],
      "type": "string"
    },
    "RequestStepFormData": {
      "type": "object",
      "properties": {
        "type": {
          "$ref": "#/definitions/FormDataField"
        },
        "name": {
          "type": "string"
        },
        "value": {
          "type": "string"
        },
        "isChecked": {
          "type": "boolean"
        }
      },
      "required": [
        "name",
        "type",
        "value"
      ]
    },
    "FormDataField": {
      "enum": [
        "File",
        "Text"
      ],
      "type": "string"
    },
    "StrictSSLOptions": {
      "enum": [
        "Inherit",
        "No",
        "Yes"
      ],
      "type": "string"
    },
    "IAuthorizationData": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# Assertion

**Assertion** узел - это узел, используемый для написания тестов. Каждый **Assertion** узел состоит из набора **Assertion**-ов - минимальных проверок различных утверждений. При запуске **Assertion** узла запускается проверка всех **Assertion**-ов. Если хотя бы одна проверка завершится с ошибкой, то выполнение всего **Assertion** узла завершается с ошибкой.&#x20;

**Assertion** узел может быть создан как потомок [RequestStep](/node-types/requeststep) узла, либо как самостоятельный узел. Причем [RequestStep](/node-types/requeststep) узел может имет не более одного **Assertion** узла в качестве потомка.

Создать **Assertion** узел можно следующими способами: из дерева проекта в контекстном меню [RequestStep](/node-types/requeststep) узла выбрать **Add node** -> **Assertion.** Либо в секции ответа [RequestStep](/node-types/requeststep) узла во вкладке Assertion выбрать **+ CREATE NEW ASSERTION NODE**.

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2Sk7THxphw3vU2CDVz%2F-M2T9B9Xe_ko_bAnchnA%2FTestMace%202020-03-15%2016.25.37.png?alt=media\&token=c2d67250-0de9-492e-8dca-187407c23edb)

В дереве проекта **Assertion** узел выглядит следующим образом:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2Sk7THxphw3vU2CDVz%2F-M2T9_siaCP6psfTX_Xb%2FTestMace%202020-03-15%2016.27.55.png?alt=media\&token=d660c3c3-1b7d-47a2-8cb1-6e2d52340b9f)

Если запуск **Assertion** узла завершился успешно, то в дереве он принимает следующий вид:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2Sk7THxphw3vU2CDVz%2F-M2T9jfi_x53Nzud58v3%2FTestMace%202020-03-15%2016.28.35.png?alt=media\&token=95d39fd0-cbc7-4512-b6fe-0c7250ad83f5)

В случае, если запуск **Assertion** узла завершился с ошибкой, узел выглядит так:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2Sk7THxphw3vU2CDVz%2F-M2T9x3EL17536xmIgpK%2FTestMace%202020-03-15%2016.29.23.png?alt=media\&token=c7406bcd-247a-45b3-923f-bc6e946b1962)

В дереве для данного типа узла доступны следующие пункты меню:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2Sk7THxphw3vU2CDVz%2F-M2TAACn_y_NplaPFGCl%2FTestMace%202020-03-15%2016.30.02.png?alt=media\&token=9e49d5f0-a109-4ffc-83e9-3e11c0861b5c)

* **Remove node.** Удалить узел.
* **Run.** Запустить узел.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

Вкладка с **Assertion** узлом выглядит следующим образом:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2Sk7THxphw3vU2CDVz%2F-M2TE0NdZV0ZLWbl12Ok%2FTestMace%202020-03-15%2016.31.27\(edit\).png?alt=media\&token=82d2e3b3-823d-43a3-ba39-f5d69676d596)

На скрине отмечены следующие области:

1. Панель управления
2. Панель настроек выбранного **Assertion**-а
3. Список **Assertion**-ов

На панели управления расположены следующие кнопки

* **RUN** - запуск списка **Assertion**-ов
* **FIX ERRORS** - исправление ошибок **Assertion**-ов где это возможно. Данная кнопка активируется в случае, если есть ошибки в **Assertion**-ах. Функционал исправления ошибок описан в разделах **Исправление ошибок** каждого из **Assertion**-ов.
* **DISABLE ERRORS** - выключение **Assertion**-ов, завершившихся с ошибкой. Отключенные **Assertion**-ы не будут участвовать в дальнейших запусках. Данная кнопка активируется в случае, если есть ошибки в **Assertion**-ах
* **+ ADD ASSERTION** - добавление **Assertion** в список

Ниже панели управления находится список **Assertion**-ов. Каждый элемент в данном списке выглядит следующим образом:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2Sk7THxphw3vU2CDVz%2F-M2THhkhc6ecEUS-Z9hS%2FTestMace%202020-03-15%2016.53.55\(edit\).png?alt=media\&token=139799aa-5119-43b6-92a4-aa64f0a6bbab)

На скрине отмечены следующие области:

1. Подсветка статуса. Если **Assertion** не запускался, то его цвет серый, если запуск завершился с ошибкой - красный, если успешно - зеленый
2. Место для захвата и перетаскивания элемента
3. Иконка конкретного типа **Assertion**-а
4. Краткое текстовое представление **Assertion**-а
5. Кнопка для отображения/скрытия подробностей о произошедших ошибках&#x20;
6. Удалить **Assertion**
7. Задизейблить **Assertion**. При этом не будет участвовать в последующих запусках
8. Запустить **Assertion**
9. Исправить **Assertion**

{% hint style="info" %}
Заметим, что контролы 6, 7, 8 и 9 появляются при наведении на **Assertion**.
{% endhint %}

Интерфейс панели настроек выбранного **Assertion**-а зависит от выбранного **Assertion**-а. В следующих разделах мы подробно разберем каждый из **Assertion**-ов.

Все Assertion имеют общее поле `Name` для описания назначения данной проверки. Если поле оставить пустым, то будет задано описание по-умолчанию в зависимости от свойств assertion-а.

### Шаблонный Assertion

Начиная с версии 1.0.0 Assertion узел можно создавать без привязки к RequestStep как любой другой узел в проекте. Его можно использовать с целью проверки результатов работы нескольких запросов, либо как шаблон, в котором будет описан ряд типичных проверок для каждого запроса.&#x20;

В отличии от Assertion-а, который привязан к RequestStep и наследует его контекст (переменные, динамические переменные, response), шаблонный Assertion получает во время запуска контекст того узла, который ссылается на данный шаблон. Контекст сохраняется во встроенную переменную `$host` и инициализируется только после запуска.

Отдельный запуск шаблонного Assertion становится нецелесообразным, поскольку в нем отсутствует контекст и все проверки заведомо провалятся. По этой причине TestMace отключает возможность самостоятельного запуска такого узла и пропускает его при выполнении сценария, в котором тот находится.&#x20;

Для отладки в интерфейсе шаблона отображается имя узла, который последним запускался и передавал свой контекст в шаблон. В таком случае будет доступна подсветка значений и автоподстановка в выражениях, содержащих переменную `$host`

![Пример шаблонного Assertion узла](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2Sk7THxphw3vU2CDVz%2F-M2TIrdD_G9xkFaIP4Lo%2FTestMace%202020-03-15%2017.08.03.png?alt=media\&token=ce8b31aa-aae0-4948-a4b3-eee941ef78f9)

Подробнее об использовании самостоятельного узла Assertion как шаблона и примеры смотрите в разделе [Link Assertion](/node-types/assertion/link-assertion).

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

**Assertion** узел хранится в файле \<nodename>.yml, где \<nodename> - название Assertion-а и имеет следующий формат:

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Assertion node",
      "const": "Assertion",
      "type": "string"
    },
    "assertions": {
      "description": "List of assertions",
      "type": "array",
      "items": {
        "$ref": "#/definitions/AbstractAssertion"
      },
      "default": []
    },
    "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": [
    "assertions",
    "children",
    "name",
    "type",
    "variables"
  ],
  "definitions": {
    "AbstractAssertion": {
      "oneOf": [
        {
          "$ref": "#/definitions/CompareAssertion"
        },
        {
          "$ref": "#/definitions/ContainsAssertion"
        },
        {
          "$ref": "#/definitions/XPathAssertion"
        },
        {
          "$ref": "#/definitions/ScriptAssertion"
        }
      ]
    },
    "CompareAssertion": {
      "type": "object",
      "properties": {
        "type": {
          "description": "Type of Compare assertion",
          "const": "compare",
          "type": "string"
        },
        "actualValue": {
          "description": "Actual value",
          "type": "string",
          "default": "${$response.body}"
        },
        "operator": {
          "$ref": "#/definitions/CompareOperator",
          "description": "Operator",
          "default": "equal"
        },
        "expectedValue": {
          "description": "Expected value",
          "type": "string"
        },
        "disabled": {
          "type": "boolean",
          "default": false
        }
      },
      "required": [
        "actualValue",
        "disabled",
        "expectedValue",
        "operator",
        "type"
      ]
    },
    "CompareOperator": {
      "enum": [
        "equal",
        "greater",
        "greater or equal",
        "less",
        "less or equal",
        "not equal"
      ],
      "type": "string"
    },
    "ContainsAssertion": {
      "type": "object",
      "properties": {
        "type": {
          "description": "Type of Contains assertion",
          "const": "contains",
          "type": "string"
        },
        "text": {
          "description": "Text to be searched",
          "type": "string",
          "default": "${$response.body}"
        },
        "value": {
          "description": "Value for search in text",
          "type": "string"
        },
        "disabled": {
          "type": "boolean",
          "default": false
        }
      },
      "required": [
        "disabled",
        "text",
        "type",
        "value"
      ]
    },
    "XPathAssertion": {
      "type": "object",
      "properties": {
        "type": {
          "description": "Type of Xpath assertion",
          "const": "xpath",
          "type": "string"
        },
        "text": {
          "description": "Text to be searched",
          "type": "string",
          "default": "${$response.body}"
        },
        "path": {
          "description": "XPath selector",
          "type": "string"
        },
        "expectedValue": {
          "description": "Expected value",
          "type": "string"
        },
        "disabled": {
          "type": "boolean",
          "default": false
        }
      },
      "required": [
        "disabled",
        "expectedValue",
        "path",
        "text",
        "type"
      ]
    },
    "ScriptAssertion": {
      "type": "object",
      "properties": {
        "type": {
          "description": "Type of Script assertion",
          "const": "script",
          "type": "string"
        },
        "script": {
          "description": "Assertion script",
          "type": "string",
          "default": "`function test(assertion, variables) {\n  // It should return true if test is passed\n  // return true;\n}`"
        },
        "disabled": {
          "type": "boolean",
          "default": false
        }
      },
      "required": [
        "disabled",
        "script",
        "type"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# Compare

Интерфейс **Compare assertion**-а выглядит следующим образом:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2TJOc1QgQA4tU8BtyI%2F-M2TMFw7YXNfGyuQR4Pa%2FTestMace%202020-03-15%2017.23.04.png?alt=media\&token=722ff142-b16c-45a8-874f-8e21d55dbae8)

**Compare assertion** служит для сравнения 2 значений. В поле `Expected value type` указывается какого типа значения будут сравниваться - строки, числа, JSON-объекты.

От выбранного типа значения зависит доступный набор операций сравнения, которые можно выбрать в поле `Operator`. Для типов string и number доступны следующие операторы:

* **equal** - проверка на равенство значений
* **not equal** - проверка на неравенство значений
* **greater** - проверка на то, что текущее значение больше ожидаемого
* **greater or equal** - проверка на то, что текущее значение больше ожидаемого или  равно ему
* **less** - проверка на то, что текущее значение меньше ожидаемого
* **less or equal** - проверка на то, что текущее значение меньше ожидаемого или равно ему

{% hint style="warning" %}
Важно отметить, что при сравнении значений, которые можно представить и как строки и как числа, результат некоторых операторов может показаться неожиданным. Например, возьмем утверждение число 100 больше числа 2. Такой assertion завершится успешно. Однако, если сравнивать те же значения но как строки ("100" is greater than "2"), то assertion завершится с ошибкой. Это объясняется тем, что строки сравниваются посимвольно в алфавитном порядке.
{% endhint %}

Для типа object доступны следующие операторы:

* **equal** - проверка на точное соответсвие структуры объектов
* **not equal** - проверка на то, что структуры объектов различаются
* **is subset of** - проверка на то, что структура актуального значения содержится в структуре ожидаемого значения.
* **is superset of** - проверка на то, что структура актуального значения содержит в себе структуру ожидаемого значения.

{% hint style="success" %}
Поясняющие примеры для операторов "**is subset of"** и "**is superset of**"

Пусть актуальное значение равно:

```javascript
[
    { 
        "name": "Mike"
    }
]
```

А ожидаемое значение:

```javascript
[
    { 
        "id": 0,
        "name": "John",
        "name": 24
    },
    {
        "id": 1,
        "name": "Mike",
        "age": 28
    }
]
```

В данном примере актуальное значение является подмножеством ожидаемого значения. Автоматически верно и обратное - ожидаемое значение является надмножеством актуального.

Структуры сравниваются рекурсивно, проверяя на соответствие каждый уровень вложенности. В примере выше сначала проверяется, что на верхнем уровне оба значения представляют из себя массив, затем каждый элемент массива из актуального значения сравнивается с каждым элементом из ожидаемого, пока не встретится первое совпадение. Объекты сравниваются на соответствие строковых ключей и их значений.

Отдельно стоит отметить, что при сравнении элементов массивов происходит поиск подпоследовательности, а не поэлементный поиск. Например, массив `[2,4]` является подмножеством массива `[1,2,3,4]`, а массив `[4, 2]` - уже нет.
{% endhint %}

### Исправление ошибок

Алгоритм исправления ошибок зависит от каждого конкретного компаратора.

* **equal** - ожидаемому значению присваивается текущее значение
* **not equal** - компаратор меняется на **equal**
* **greater** - компаратор меняется на **greater or equal** и ожидаемому значению присваивается текущее значение
* **greater or equal** - ожидаемому значению присваивается текущее значение
* **less** - компаратор меняется на **less or equal** и ожидаемому значению присваивается текущее значение
* **less or equal** - ожидаемому значению присваивается текущее значение

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

В файле **Assertion** имеет тип `compare` , описание самого типа можно найти в документации к [файловому представлению Assertion](/node-types/assertion#failovoe-predstavlenie) в определении `#/definitions/CompareAssertion` .


# In range

{% hint style="warning" %}
Данный функционал доступен только для владельцев [платной подписки](https://testmace.com/pricing/) TestMace
{% endhint %}

Интерфейс **In range assertion**-а выглядит следующим образом:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2TY1R1ffQ61Sy50P0I%2F-M2TZWH-jYK7ge0tK_vV%2FTestMace%202020-03-15%2018.20.52.png?alt=media\&token=6d46a9bf-e55c-4ab8-bb8f-ee862678258c)

Данный assertion служит для проверки попадания актуального значения в интервал. В поле `Expected value type` указывается какого типа значения будут сравниваться - строки, числа.

В поле с лейблом `Expected value` присутствуют поля ввода для указания нижней и верхней границы интервала, а также две кнопки по краям, указывающие, должны ли граничные значения быть включены в интервал или нет.

Например, возможные интервалы для значений 0 и 10:

* \[ 0 \~ 10 ] - интервал от 0 включительно и до 10 включительно.
* \[ 0 \~ 10 ) - интервал от 0 включительно и до 10, исключая само число 10.
* ( 0 \~ 10 ] - интервал от 0 и до 10 включительно, исключая само число 0.
* ( 0 \~ 10 ) - интервал включающий все числа от 0 и до 10, исключая сами числа 0 и 10.

{% hint style="info" %}
Заметьте, что в качестве значений в интервале можно указывать строки. В таком случае сравенение на больше - меньше с границами интервала будет происходить посимвольно в алфавитном порядке.
{% endhint %}

Флаг `Use negative statement` служит для отрицания описанного утверждения, т.е. актуальное значение не должно попадать в указанный интервал.

### Исправление ошибок

Алгоритм исправления ошибок зависит от состояния флага `Use negative statement`:

* false - задается интервал \[actual \~ actual]
* true - задается интервал (actual \~ actual)


# One of set

{% hint style="warning" %}
Данный функционал доступен только для владельцев [платной подписки](https://testmace.com/pricing/) TestMace
{% endhint %}

Интерфейс **One of set assertion**-а выглядит следующим образом:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2TctBGr_VbHu-cexPQ%2F-M2TdZRBLLkKf9TKnCLD%2FTestMace%202020-03-15%2018.43.09.png?alt=media\&token=0595e6a2-e599-4b1a-a8ba-0da8c74a75b7)

Данный assertion служит, чтобы проверить что актуальное значение принимает одно значение из заданного множества. В поле `Expected value type` указывается какого типа значения будут сравниваться - строки, числа, JSON-объекты.

В поле с лейблом `Expected value` указывается список возможных ожидаемых значений.

Флаг `Use negative statement` служит для отрицания описанного утверждения, т.е. актуальное значение не должно содержаться в указанном множестве.

### Исправление ошибок

Алгоритм исправления ошибок зависит от состояния флага `Use negative statement`:

* false - в список добавляется актуальное значение.
* true - из списка удаляется актуальное значение.


# Contains

**Contains assertion** служит для проверки вхождения подстроки в строку или на соответствие строки регулярному выражению.

Данный **Assertion** имеет следующий интерфейс:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2TctBGr_VbHu-cexPQ%2F-M2TepuECuJ7qWBzn6_h%2FTestMace%202020-03-15%2018.48.47.png?alt=media\&token=0fc9cc51-29be-46ec-a360-e38b5ab5e328)

Данный **Assertion** имеет следующие поля:

* **Text** - текст, где будет производиться поиск
* **Value** - значение для поиска
* Флаг **Use negative statement** - означает отрицание описанного утверждения.
* Флаг **Use value as Regular Expression** - значение поля value в таком случае будет воспринято как шаблон для регулярного выражения которому должно соответствовать актуальное значение.

### Исправление ошибок

У данного **Assertion**-а нет механизма исправления ошибок

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

В файле **Assertion** имеет тип `contains` , описание самого типа можно найти в документации к [файловому представлению Assertion](/node-types/assertion#failovoe-predstavlenie) в определении `#/definitions/ContainsAssertion` .


# XPath

**XPath assertion** позволяет проверить значение по XPath-селектору.

Данный **assertion** имеет следующий интерфейс:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2TfVyloe5GNGu6k_KG%2F-M2TfucO3ovxeghTjwLS%2FTestMace%202020-03-15%2018.53.21.png?alt=media\&token=f0bdbf69-01d7-484c-af77-ed286b7806fa)

**XPath assertion** имеет следующие поля:

* **Text** - текст, где будет производиться поиск
* **Path** - XPath селектор
* **Expected value** - ожидаемое значение по данному селектору
* Флаг **Use negative statement** - означает отрицание описанного утверждения, т.е. в тексте по данному селектору не должно быть ожидаемого значения.

### Исправление ошибок

При исправлении ошибки в данном виде **Assertion**-а ожидаемому значению присваивается значение, лежащее по селектору.

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

В файле **Assertion** имеет тип `xpath` , описание самого типа можно найти в документации к [файловому представлению Assertion](/node-types/assertion#failovoe-predstavlenie) в определении `#/definitions/XPathAssertion` .


# JSONPath

{% hint style="warning" %}
Данный функционал доступен только для владельцев [платной подписки](https://testmace.com/pricing/) TestMace
{% endhint %}

**JSONPath assertion** позволяет проверить значение по XPath-селектору.

Данный **assertion** имеет следующий интерфейс:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2ThD74qRZqCSNdLCOo%2F-M2Tu--T6wh4Q9fGpKKu%2FTestMace%202020-03-15%2019.54.33.png?alt=media\&token=74d8e57e-cde6-4713-a5dd-1014f92ffc93)

**JSONPath assertion** имеет следующие поля:

* **Text** - текст, где будет производиться поиск
* **Path** - JSONPath селектор
* **Expected value** - ожидаемое значение по данному селектору. Значение должно быть массивом ожидаемых елементов.
* Флаг **Use negative statement** - означает отрицание описанного утверждения, т.е. в тексте по данному селектору не должно быть ожидаемого значения.

### Исправление ошибок

При исправлении ошибки в данном виде **Assertion**-а ожидаемому значению присваивается значение, лежащее по селектору.


# Script

**Script assertion** позволяет написать проверочный скрипт на языке JavaScript. Сам скрипт представляет из себя функцию с названием `test`, которая на вход принимает объект assertion-а и объект с переменными (в формате ключ-значение). В случае, если функция возвращает `true` считается, что проверка прошла успешно. Если функция возвращает `false` или бросает исключение, то считается, что запуск **Script assertion**-а завершился с ошибкой.

{% hint style="warning" %}
**Устаревший синтаксис:**&#x20;

Мы настоятельно рекомендуем использовать новый способ описания проверочных скриптов взамен определения функции `test`. У вас появится возможность использовать программный интерфейс ко всем сущностям вашего проекта, использовать встроенные вспомогательные библиотеки (например `lodash` и `chai`), а также определять подробное описание для каждого проверочного утверждения, которое будет отображаться в списке ошибок и консоли.

Ваши тесты, написанные в функции `test` останутся работоспособны, но в дальнейших мажорных релизах будет исключена поддержка этого синтаксиса.
{% endhint %}

### Новый программный интерфейс

**Script assertion** поддерживает такой же программный интерфейс как в **Script** узлах.

{% content-ref url="/pages/-Ll\_fiT--tqog4pfZycd" %}
[Script](/node-types/script)
{% endcontent-ref %}

Проверка **Script assertion**-а считается провальной, если в процессе выполнения скрипта было выброшено исключение любого типа, в противном случае считается, что проверка прошла успешно.

### Интерфейс пользователя

Данный **Assertion** имеет интерфейс, аналогичный интерфейсу узла **Script**:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2Th-pSAXk8IEvHySm4%2F-M2ThBMbiJ2D7aKV15Di%2FTestMace%202020-03-15%2018.58.58.png?alt=media\&token=a133ee76-b15e-4e6a-a6bd-38b454c17fbd)

Поле **Name** позволяет задать осмысленное описание для данной проверки.

### Исправление ошибок

У данного **Assertion**-а нет механизма исправления ошибок

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

В файле **Assertion** имеет тип `script` , описание самого типа можно найти в документации к [файловому представлению Assertion](/node-types/assertion#failovoe-predstavlenie) в определении `#/definitions/ScriptAssertion` .


# Link

{% hint style="warning" %}
Данный функционал доступен только для владельцев [платной подписки](https://testmace.com/pricing/) TestMace
{% endhint %}

**Link assertion** позволяет создать ссылку на другой шаблонный Assertion узел в дереве проекта и запустить его с контекстом данного узла, параметризуя запуск переменными. Таким образом можно вынести некоторое множество типовых проверок для нескольких запросов в один узел и переиспользовать его.

Данный **assertion** имеет следующий интерфейс:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2TuEf0tZHHd82dc636%2F-M2U-Wk_mfo-m8OxLI5F%2FTestMace%202020-03-15%2020.23.30.png?alt=media\&token=4106d79f-2952-44d1-887e-a11054441040)

Для начала работы с данным assertion необходимо создать [Assertion](/node-types/assertion) узел в проекте или папке и добавить туда необходимые шаги проверки. Например:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2TuEf0tZHHd82dc636%2F-M2U-zZtb3R5DgtrewdU%2FTestMace%202020-03-15%2020.25.24.png?alt=media\&token=bc8ce92a-bfa4-4f29-9b76-e640ed079608)

{% hint style="info" %}
Заметьте, что выражения в проверках содержат переменную `$host` - это контекст узла из которого будет запускаться Assertion узел по ссылке, т.е. объект содержащий переменные, динамические переменные, response.
{% endhint %}

Далее, добавим link assertion, и нажав на кнопку Choose Assertion выберем только что созданный узел. Мы можем создать переменную прямо в assertion и затем использовать ее в выражениях шаблона, например `${$host.my_var}`

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2TuEf0tZHHd82dc636%2F-M2U0PGM-w2Pk-bzfXLS%2FTestMace%202020-03-15%2020.27.17.png?alt=media\&token=693196dc-4015-4602-9015-31cbc8b1f515)

Запустив запрос, можно заметить, что состояние шаблонного assertion узла также изменилось. Открыв этот узел, в нем будет отображаться последний узел, который передавал ему контекст при запуске. С этим контекстом теперь доступна подсведка значений выражений и автоподстановка.

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-M2TuEf0tZHHd82dc636%2F-M2U0fzUKNeo0UMuDCcQ%2FTestMace%202020-03-15%2020.28.02.png?alt=media\&token=6124480c-8f75-4348-b3c6-306a5be17ba1)

### Исправление ошибок

У данного **Assertion**-а нет механизма исправления ошибок


# Link

Узел типа Link (ссылка) предназначен для повторно использования других узлов: RequestStep (включая Assertion) и сценариев (Folder).

## Принцип действия&#x20;

После выбора вызываемого узла, **Link** узел предоставляет возможность переопределить значения его переменных. **Link** узел вызывает исполнение другого узла, передавая ему заданные пользователем переменные. После выполнения, динамические переменные вызванного узла, устанавливаются как динамические переменные родительской группы **Link** узла. Таким образом результат выполнения доступен из любого соседствующего узла **Link**.

#### Из Link узла можно сослаться на:

* [RequestStep](/node-types/requeststep) узел
* [Folder](/node-types/folder) узел

#### Нельзя сослаться на:

* Другой **Link** узел (в том числе на самого себя)
* На любого предка **Link** узла (т.к. это вызовет при запуске бесконечный цикл)

{% hint style="info" %}
&#x20;Link узел предоставляет возможность переопределить значения переменных узла родителя.
{% endhint %}

{% hint style="warning" %}
При удалении узла, на который ссылается Link узел, ссылка будет считаться потерянной и запуск будет невозможен пока не будет указана корректная ссылка.
{% endhint %}

## Узел родитель

Создайте узел родитель, на который нужно ссылаться, и задайте ему необходимые [статически определяемые переменные](/variables/user-variables/static-variables), например `postID`. Значение переменной можно не указывать.

![Создание переменных для узла родителя](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrUP_I2wt8JRAOTIo%2Fl_1.jpg?alt=media\&token=0ddded72-bae2-44e2-ace5-54b585876324)

## Узел Link

Создайте **Link** узел и укажите родителя, после этого отобразятся все созданные переменные родителя. В качестве переопределяемого значения можно использовать любые переменные или статическое значение.&#x20;

![Создание Link узла и выбор родителя](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrYUzKPma0ErHXhNj%2Fl_2.gif?alt=media\&token=23bd3e83-5b06-4164-8ab1-509f065511fc)

## Пример сценария

Рассмотрим пример, в котором, в качестве **Link** узла будем вызывать [RequestStep](/node-types/requeststep) узел для удаления записи.

### Создание узла родителя

1. Создайте [RequestStep](/node-types/requeststep) узел с именем **deletePost**
2. Тип запроса DELETE
3. В качестве URL используйте[ https://testmace-stage.herokuapp.com/posts/${id}](< https://testmace-stage.herokuapp.com/posts/${id}>)
4. Создайте для этого узла [статически определяемую переменную](/variables/user-variables/static-variables) `id` с пустым значением

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrbQNUc1uEfXxWXb-%2Fl_3.gif?alt=media\&token=ac7a97bf-ebec-446b-9572-9ed1fc258634)

### Создание сценария

* Создайте [Folder](/node-types/folder) узел с именем **scenario**
* Добавьте в scenario[ RequestStep](/node-types/requeststep) узел с именем **createPost**:&#x20;
  * тип запроса: POST
  * URL: [https://testmace-stage.herokuapp.com/posts/](< https://testmace-stage.herokuapp.com/posts/${id}>)
  * body запрос JSON `{"title":"will delete with link node"}`
  * Выполняем запрос и присваиваем `id` созданной записи [динамической переменной](/variables/user-variables/dynamic-variables) postId для узла **Scenario**.

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrcoO2XM6ONc0CZsH%2Fl_4.gif?alt=media\&token=fd36a09f-0266-4ecf-9707-1031a711d9af)

* Далее создаем **Link** узел с именем **deleteLink**
  * В качества родителя указываем узел **project/deletePost**
  * Для переменной `id` родителя **deletePost** в Link узле указываем Overridden Value `${$dynamicVar.postId}`
* Создадим [RequestStep](/node-types/requeststep) узел **checkIfExists** для проверки удаления записи
  * Тип запроса: GET
  * URL: <https://testmace-stage.herokuapp.com/posts/${$dynamicVar.postId}>
  * Ожидаемый ответ сервера 404.

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMqrBlEUY-qUdSNMR2%2F-LiMrduTdT4bc9kgalMN%2Fl_5.gif?alt=media\&token=3120d7e1-b3b8-4f45-be2a-520e55e855f9)

## Пример проект для импорта [через URL](/other/import/shared)

{% file src="/files/-LiMr55F1c6QspuvzbcH" %}

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

**Link** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат.

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of Link node",
      "const": "Link",
      "type": "string"
    },
    "linkedNode": {
      "$ref": "#/definitions/NodeReference",
      "description": "Link to node"
    },
    "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",
    "linkedNode",
    "name",
    "type",
    "variables"
  ],
  "definitions": {
    "NodeReference": {
      "type": "object",
      "properties": {
        "refNodePath": {
          "description": "Absolute path to node",
          "type": "string"
        },
        "type": {
          "description": "Marker of reference entity",
          "const": "reference",
          "type": "string",
          "default": "reference"
        }
      },
      "required": [
        "refNodePath",
        "type"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# API description

TestMace имеет мощный функционал описания API, включая импорта из Swagger 2.0/ Openapi  3.0. Реализован данный функционал посредством следующих узлов:

* [ApiRootFolder](/node-types/api-description/apirootfolder) - корневой узел описания API
* [ApiFolder](/node-types/api-description/apifolder) - узел для группировки других узлов API
* [ApiRoute](/node-types/api-description/apiroute) - узел для описания конкретного эндпоинта

В следующих разделах мы подробнее познакомимся с функцией каждого из данных узлов


# ApiRootFolder

**ApiRootFolder** - это корневой узел поддерева описания API. Он, по аналогии с [Project](/node-types/project) узлом, является корневым элементом, и в пределах поддерева описания API может быть может быть только один элемент данного типа. В остальном повторяет функционал [ApiFolder](/node-types/api-description/apifolder) узла.

Создать данный узел можно одним из следующих способов

* Из контекстного меню [Project](/node-types/project) узла
* Воспользовавшись импортом из форматов описания API

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

**ApiRootFolder** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат:

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of ApiRootFolder node",
      "const": "ApiRootFolder",
      "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",
    "type",
    "variables"
  ],
  "definitions": {
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# ApiFolder

**ApiFolder** узел, по аналогии с [Folder](/node-types/folder) узлом, служит для группировки других типов узлов (в данном случае [ApiRoute](/node-types/api-description/apiroute) узлов). &#x20;

Создать данный узел можно следующими способами:

* Из контекстного меню [ApiRootFolder](/node-types/api-description/apirootfolder) узла
* Воспользовавшись импортом из форматов описания API

В дереве проекта **ApiFolder** узел имеет следующий вид:

![Вид ApiFolder узла в дереве проекта](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsBurAEw8jjEkJrtf%2Faf_1.png?alt=media\&token=680ed8d0-b230-4c56-a2fd-6dc021bb00fe)

Контекстное меню данного узла выглядит следующим образом:

![Контекстное меню ApiFolder узла](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsEDI1oLvGTZfTmYQ%2Faf_2.png?alt=media\&token=1cf07376-2887-4c2d-9ac9-90c413997f7d)

* **Add node.** Добавление узла-потомка. В подменю можно выбрать тип узла.
* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название NodeName \[Copy \[number]].
* **Remove node.** Удалить узел.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

Интерфейс вкладки данного узла выглядит следующим образом:

![Интерфейс вкладки ApiFolder узла](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsHryxF8VAVuXeS0_%2Faf_3.png?alt=media\&token=736707f8-b932-4edd-a1f4-51aa787cf8de)

На данном скрине отмечены следующие области

* Диалог управления [пользовательскими переменными](/variables/user-variables)
* Список дочерних узлов

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

**ApiFolder** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат:

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of ApiFolder node",
      "const": "ApiFolder",
      "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",
    "type",
    "variables"
  ],
  "definitions": {
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# ApiRoute

Данный узел служит для описания интерфейса конкретного эндпоинта. Интерфейс схож с [RequestStep](/node-types/requeststep) узлом. Это и не удивительно - в обоих случаях мы имеем дело с HTTP-запросами.

Основные возможности данного типа узлов:

* Возможность описания http-заголовков, query параметров, body параметров запроса и HTTP-кодов, HTTP-заголовков, body параметров ответа
* Использование типов для описания каждого из заголовков, query параметров, body параметров. Поддерживаются следующие типы: `string`, `number`, `integer`, `boolean`, `array` и `object`.
* Добавление описаний для каждой из сущностей
* Поддержка описания нескольких параметров тела запроса (в зависимости от content-type)
* Поддержка описания нескольких возможный ответов от сервера
* Создание запроса из описания
* Автодополнение урлов, HTTP-заголовков, query параметров и body параметров в [RequestStep](/node-types/requeststep) узлах.

## Обзор интерфейса

Для создание **ApiRoute** узла необходимо в контекстном меню [ApiFolder](/node-types/api-description/apifolder) узла выбрать **Add node** -> **ApiRoute.**

### **Вид узла в дереве проекта**

В дереве **ApiRoute** узел выглядит следующим образом:

![Вид ApiRoute узла в дереве проекта](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsjdLErhFxCQUpVzR%2Far_1.png?alt=media\&token=21b635ae-a97e-4358-b8f2-c2c95028108c)

В качестве иконки у данного вида узла выступает название HTTP-метода. Контекстное меню выглядит следующим образом:

![Контекстное меню ApiRoute узла](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMslz8Y5XicOHnnV8p%2Far_2.png?alt=media\&token=faa4b280-b90e-4ec8-911f-8080e90ce282)

* **Rename.** Переименовать узел.
* **Duplicate.** Сделать копию узла. Новый узел будет иметь название NodeName \[Copy \[number]].
* **Remove node.** Удалить узел.
* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

### Интерфейс вкладки

Вкладка **ApiRoute** узла выглядит следующим образом:

![Вкладка ApiRoute узла](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMspLCONT78JfocOc6%2Far_3.png?alt=media\&token=a997d9f9-afcf-4903-bb20-8fd792925559)

#### Области общих параметров запроса

Рассмотрим подробнее верхнюю часть данной вкладки:

![Верхняя часть таба ApiRoute узла](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsscrBJx53fsqf00u%2Far_4.png?alt=media\&token=8029abe1-0053-409c-a01d-1c769ce21204)

На скрине обозначены следующие области:

1. Http-метод. Данный список совпадает со списком методов из [RequestStep](/node-types/requeststep) узла
2. Url с поддержкой [механизма переменных](/variables/variables)
3. Кнопка открытия [диалога работы с переменными](/variables/user-variables)
4. Кнопка создания запроса из текущего описания API
5. Текстовое описание запроса

#### Область описания параметров запросов

В левой нижней части расположена область описания запроса. Она разделена на 3 вкладки: **Headers**, **Query parameters** и **Body** для редактирования HTTP-заголовков, query параметров и параметров тела запроса соответственно.

Рассмотрим вкладку **Headers**. Ее содержимое представлено в табличном виде. Для редактирования заголовков доступны следующие поля:

* Название заголовка
* Тип значения заголовка (список типов описан выше)
* Описание

Поддерживаются все стандартные операции.

Вкладка **Query Parameters** используется для редактирования query параметров, в остальном по функционалу идентична вкладке **Headers**.

Как уже было сказано, в **ApiRoute** узле можно описать несколько тел для одного и того же запроса. Например, по одному и тому же эндпоинту могут приниматься как данные с `Content-Type` равным `application/json`, так и с `application/xml`. Вкладка **Body** разделена как раз по `content-type` на вкладки и имеет следующий вид:

![Вид вкладки Body интерфейса описания запроса](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMsvmecyriXA8KhPQP%2Far_5.png?alt=media\&token=10f32ea0-49d8-49ae-8473-8d94a367ad3e)

На скрине отмечены следующие области:

1. Кнопка редактирования текущего `content-type`. При нажатии на нее данное поле подменяется на текстовое поле, где можно ввести интересующий `content-type`.
2. Кнопка удаления тела запроса
3. Кнопка добавления тела запроса
4. Текущий `content-type` узла
5. Область редактирования тела запроса

Область редактирования тела запроса меняется в зависимости от `content-type` по следующему правилу: если `content-type` равен `application/x-www-form-urlencoded` или `multipart/form-data`, то область редактирования принимает табличный вид (аналогичный табличной области в **Headers** вкладке), в противном случае - текстовый как на скрине выше. В текстовой области в качестве формата описания используется [OpenAPI](https://swagger.io/specification/#requestBodyObject).

#### Область описания параметров запросов

В правой нижней области интерфейса вкладки **ApiRoute** узла расположена области редактирования ответов от сервера. Как уже было сказано, TestMace поддерживает описание нескольких ответов в рамках одного эндпоинта. Интерфейс данной области выглядит следующим образом:

![Интерфейс редактирования ответов сервера](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMszNK7ApEdzbaBel_%2Far_6.png?alt=media\&token=b6ff2068-1344-4527-95e0-71d17a081074)

Данный интерфейс разделен на вкладки, отдельно для каждого ответа. В рамках вкладки каждого ответа можно редактировать код ответа, описание, а также HTTP-заголовки и тела ответа, интерфейсы которых идентичны таковым из области запроса.

## Интеграция с RequestStep узлом

TestMace имеет интеграцию с **ApiRoute** узлами в **RequestStep** узлах. На данный момент эта интеграция проявляется в автодополнении url, HTTP-заголовков, query параметров, параметров тела запросов **RequestStep** узлов. Причем, для url-ов в автодополнении участвуют всех url-ы **ApiRoute** узлов, тогда как для остальных параметров автодополнение работает по следующему алгоритму:

* Берутся метод и url данного **RequestStep** узла
* Ищутся все **ApiRoute** узлы с такими url и методом
* Осуществляется поиск по искомому параметру (например, по HTTP-заголовку) среди найденных **ApiRoute** узлов

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

**ApiRoute** узел представляет из себя папку с названием узла, внутри которой содержится файл index.yml, имеющий следующий формат.

```javascript
{
  "type": "object",
  "properties": {
    "type": {
      "description": "Type of ApiRoute node",
      "const": "ApiRoute",
      "type": "string"
    },
    "url": {
      "type": "string",
      "default": ""
    },
    "method": {
      "$ref": "#/definitions/RequestMethod"
    },
    "description": {
      "type": "string",
      "default": ""
    },
    "requests": {
      "$ref": "#/definitions/ApiRequests",
      "description": "List of requests"
    },
    "responses": {
      "description": "List of responses",
      "type": "array",
      "items": {
        "$ref": "#/definitions/ResponseParameters"
      },
      "default": []
    },
    "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",
    "description",
    "method",
    "name",
    "requests",
    "responses",
    "type",
    "url",
    "variables"
  ],
  "definitions": {
    "RequestMethod": {
      "enum": [
        "DELETE",
        "GET",
        "OPTIONS",
        "PATCH",
        "POST",
        "PUT"
      ],
      "type": "string"
    },
    "ApiRequests": {
      "type": "object",
      "properties": {
        "queryParameters": {
          "description": "List of query parameters",
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "headers": {
          "description": "List of headers",
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "cookies": {
          "description": "List of cookies",
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "bodies": {
          "description": "List of bodies",
          "type": "array",
          "items": {
            "$ref": "#/definitions/RequestParameters"
          },
          "default": []
        }
      },
      "required": [
        "bodies",
        "cookies",
        "headers",
        "queryParameters"
      ]
    },
    "QueryParameter": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "type": {
          "enum": [
            "array",
            "boolean",
            "integer",
            "number",
            "object",
            "string"
          ],
          "type": "string"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "name",
        "type"
      ]
    },
    "RequestParameters": {
      "type": "object",
      "properties": {
        "contentType": {
          "type": "string"
        },
        "schema": {
          "anyOf": [
            {
              "$ref": "#/definitions/SchemaRef"
            },
            {
              "$ref": "#/definitions/OneOf"
            },
            {
              "$ref": "#/definitions/AllOf"
            },
            {
              "$ref": "#/definitions/AnyOf"
            },
            {
              "$ref": "#/definitions/ObjectMember"
            },
            {
              "$ref": "#/definitions/ArrayMember"
            },
            {
              "$ref": "#/definitions/ScalarMember"
            }
          ]
        }
      },
      "required": [
        "contentType",
        "schema"
      ]
    },
    "SchemaRef": {
      "type": "object",
      "properties": {
        "$ref": {
          "type": "string"
        }
      },
      "required": [
        "$ref"
      ]
    },
    "OneOf": {
      "type": "object",
      "properties": {
        "oneOf": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/SchemaRef"
              },
              {
                "$ref": "#/definitions/OneOf"
              },
              {
                "$ref": "#/definitions/AllOf"
              },
              {
                "$ref": "#/definitions/AnyOf"
              },
              {
                "$ref": "#/definitions/ObjectMember"
              },
              {
                "$ref": "#/definitions/ArrayMember"
              },
              {
                "$ref": "#/definitions/ScalarMember"
              }
            ]
          }
        }
      },
      "required": [
        "oneOf"
      ]
    },
    "AllOf": {
      "type": "object",
      "properties": {
        "allOf": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/SchemaRef"
              },
              {
                "$ref": "#/definitions/OneOf"
              },
              {
                "$ref": "#/definitions/AllOf"
              },
              {
                "$ref": "#/definitions/AnyOf"
              },
              {
                "$ref": "#/definitions/ObjectMember"
              },
              {
                "$ref": "#/definitions/ArrayMember"
              },
              {
                "$ref": "#/definitions/ScalarMember"
              }
            ]
          }
        }
      },
      "required": [
        "allOf"
      ]
    },
    "AnyOf": {
      "type": "object",
      "properties": {
        "anyOf": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/SchemaRef"
              },
              {
                "$ref": "#/definitions/OneOf"
              },
              {
                "$ref": "#/definitions/AllOf"
              },
              {
                "$ref": "#/definitions/AnyOf"
              },
              {
                "$ref": "#/definitions/ObjectMember"
              },
              {
                "$ref": "#/definitions/ArrayMember"
              },
              {
                "$ref": "#/definitions/ScalarMember"
              }
            ]
          }
        }
      },
      "required": [
        "anyOf"
      ]
    },
    "ObjectMember": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "object"
          ]
        },
        "properties": {
          "$ref": "#/definitions/SchemaMember"
        },
        "required": {
          "type": "boolean"
        },
        "additionalProperties": {
          "$ref": "#/definitions/ScalarMember"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "SchemaMember": {
      "type": "object",
      "additionalProperties": {
        "anyOf": [
          {
            "$ref": "#/definitions/SchemaRef"
          },
          {
            "$ref": "#/definitions/OneOf"
          },
          {
            "$ref": "#/definitions/AllOf"
          },
          {
            "$ref": "#/definitions/AnyOf"
          },
          {
            "$ref": "#/definitions/ObjectMember"
          },
          {
            "$ref": "#/definitions/ArrayMember"
          },
          {
            "$ref": "#/definitions/ScalarMember"
          }
        ]
      }
    },
    "ArrayMember": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "array"
          ]
        },
        "items": {
          "anyOf": [
            {
              "$ref": "#/definitions/SchemaRef"
            },
            {
              "$ref": "#/definitions/OneOf"
            },
            {
              "$ref": "#/definitions/AllOf"
            },
            {
              "$ref": "#/definitions/AnyOf"
            },
            {
              "$ref": "#/definitions/ObjectMember"
            },
            {
              "$ref": "#/definitions/ArrayMember"
            },
            {
              "$ref": "#/definitions/ScalarMember"
            }
          ]
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "items",
        "type"
      ]
    },
    "ScalarMember": {
      "type": "object",
      "properties": {
        "type": {
          "$ref": "#/definitions/ScalarSchemaType"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ]
    },
    "ScalarSchemaType": {
      "enum": [
        "boolean",
        "integer",
        "number",
        "string"
      ],
      "type": "string"
    },
    "ResponseParameters": {
      "type": "object",
      "properties": {
        "code": {
          "description": "Http-code (e.g. 200, 404)",
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "headers": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/QueryParameter"
          }
        },
        "content": {
          "$ref": "#/definitions/RequestParameters",
          "description": "Response body"
        }
      },
      "required": [
        "code",
        "content"
      ]
    },
    "NodeVariables": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
```


# Импорт описания API

TestMace позволяет не только вручную задокументировать API, но и импортировать уже существующую документацию. На данный момент поддерживается импорт из форматов Swagger 2.0 и OpenAPI 3.0.

Импортировать описание API можно из контекстного меню + проекта, выбрав **Import** -> **Swagger** (аналогичное меню есть и в области Scratches):

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LvigB_ebqRKI4OZpbwR%2F-LvigmezDlcGZlxMb3HC%2F1-swagger.jpg?alt=media\&token=bc57af15-0bcb-40b7-b013-2796fa952790)

При этом открывается диалог следующего вида:

![](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LvigB_ebqRKI4OZpbwR%2F-Lvih0EDc4S16T5ESr9a%2F2-swagger.jpg?alt=media\&token=a6be4d40-f85a-4b54-aa0d-b4fa812e4b77)

Как видите, на данный момент поддерживается как импорт из файла, так и загрузка API с удаленного сервера по URL. После выбора источника и нажатия на кнопку **OK** в дерево добавляется импортированное описание.

### Обновление описания API

Помимо загрузки описания API, можно также обновить уже существующие описание API . Для этого из контекстного меню [ApiRootFolder](/node-types/api-description/apirootfolder) узла необходимо выбрать **Update api.** При этом откроется диалог как при импорте API. Стоит отметить, что все изменения в описании API, сделанные вручную, будут перетерты после обновления.


# Broken

При открытии проекта могут возникнуть ситуации, когда некоторые узлы не могут быть загружены. Примером такой ситуации является наличие merge конфликтов. В таких случаях проект загружает все возможные узлы, однако после открытия проекта пользователю показывается такое предупреждение:

![Предупреждение в случае наличия в проекте незагруженных узлов](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMte0JJQ45gAj9tq8k%2Fb_1.png?alt=media\&token=aa82e45e-4b0c-4c57-8cf7-87ca7db22450)

А в загруженном проекте появляются такие узлы:

![Вид Broken узла в дереве](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMtisxrwZeSwW-Wbb8%2Fb_2.png?alt=media\&token=cfa3609b-a880-4fdb-825b-96367bdec0d2)

Это **Broken** узел. Он не может быть создан вручную, а появляется, если при загрузке определенного узла произошли ошибки. Контекстное меню данного узла выглядит следующим образом:

![Контекстное меню Broken узла](https://1540441421-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lh_FaVh9XfQJ0p1KqZ1%2F-LiMrmYbW3n5VDqYxikj%2F-LiMtlMptczUpzeTB5vN%2Fb_3.png?alt=media\&token=2f0882f2-0ce7-4e62-94f4-16f8060f4d17)

* **Show in explorer.** Открыть папку с узлом в файловом менеджере.

**Broken** узел не может быть открыть во вкладке и не от него нельзя создать каких-либо потомков. Основное предназначение - помочь пользователю исправить ошибку.




---

[Next Page](/llms-full.txt/1)

