Узел, выполняющий сценарии, написанные на JavaScript. Script будет полезен для решения разных задач:
Реализация сложных тестов над результатами одного или нескольких других узлов
Генерация тестовых данных
Преобразование переменных других узлов
Выполнение операций для приведения тестируемой системы в заданное состояние (set_up, tear_down)
Отладка и доступ к состоянию всех узлов проекта
Окно редактирования узла разделено на две области - окно редактирования кода и окно консольного вывода. Для скрытия консоли нажмите на кнопку .
Над окном консольного вывода расположена панель инструментов для управления поведением консоли:
/
- переключение между режимами сохранения результатов выполнения в консоли.
- очистка консоли перед каждым запуском скрипта,
- накопление результатов запуска.
- автоматическая прокрутка к последней строке вывода консоли
- очистить текущий вывод консоли
Скрипт начинает выполнение при нажатии на кнопку RUN
. Узел заканчивает свое выполнение после исполнения всех строки кода и после завершения всех асинхронных задач (например, setTimeout
). Скрипт считается выполненным успешно при выполнении следующих условий:
В коде не выявлено синтаксических ошибок
При выполнении все выброшенные исключения обработаны
Выполнение заняло не более 30 секунд (по истечении этого времени скрипт будет прерван)
Вызов скрипта обернут в функцию, поэтому для того, чтобы прервать выполнение без ошибок воспользуйтесь инструкцией возврата: return;
Чтобы прервать выполнения скрипта с ошибкой, воспользуйтесь выбросом любого исключения: throw new Error('Something went wrong');
Запуск осуществляется в виртуальном окружении node.js. Пользователю доступно некоторые модули из node.js, а также все встроенные возможности JavaScript, поддерживаемые движком V8.
Осуществляется поддержка стандарта ECMAScript 6
fs - работа с файловой системой
lodash - библиотека со множеством утилитарных алгоритмов
moment.js - библиотека для работы с датами
CryptoJS - библиотека реализующая множество криптографических алгоритмов
random-js - библиотека для генерации математически корректных случайных чисел
faker.js - библиотека для генерации случайных данных для свойств различных сущностей
chai.js - библиотека предоставляющая комфортные интерфейсы для проверки логических утверждений.
request - библиотека предоставляющая мощный HTTP-клиент.
axios - библиотека для отправки HTTP-запросов
Ниже приведены объекты и функции глобальной области видимости скрипта.
Все описанные модули автоматически подключаются к контексту выполнения и доступны в глобальной области видимости.
_.sum([1, 2, 3, 4]) // 10
const now = moment(new Date()).format();
const hash = crypto.MD5('Message');
const randomEngine = new random.Random();const shuffledArray = randomEngine.shuffle([1,2,3,4,5]);
const person = {'name': faker.name.findName(),'email': faker.internet.email()};
const foo = 'bar';// successassert.equal(foo, 'bar');expect(foo).to.equal('bar');// failureassert.equal(1, 0);
Библиотека request
не предоставляет интерфейса для работы с async/await. Одно из возможных решений это обернуть вызов request
в объект Promise
await new Promise((resolve, reject) => {request('https://docs-ru.testmace.com', (error, response, body) => {try {assert.equal(error, null);assert.equal(response.statusCode, 206);assert.notEqual(body, null);resolve();} catch(e) {reject(e);}});})
await axios.get('https://api.ipify.org?format=json')
Методы для вывода данных в консоль: log, info, warn, error, debug, exception
Сигнатура методов совпадает с их стандартными версиями. Каждый тип события в консоли окрашивается в свой цвет. Каждая строка сопровождается указателем на строку и столбец, из которой произошел вызов функции вывода. События типа exception отображаются вместе со стеком вызовов внутри скрипта.
В предыдущих версиях TestMace пытался автоматически определить, когда скрипт завершал свою работу. В новых версиях эта возможность (вкупе с функцией finish()) удалена.
Скрипт может содержать асинхронные вызовы (например, Promise, setTimeout, addEventListener, колбэки при вызове встроенных модулей и пр.). Для работы с асинхронными операции JavaSсript предоставляет удобный механизм, называемый async/await. TestMace полностью поддерживает работу с async/await и полагается на него при выполнении асинхронных операций, чтобы определить, завершился ли скрипт или нет. К примеру, рассмотрим следующий код:
console.log('1');setTimeout(() => console.log('2'), 100);console.log('3');
В консоли будет выведено
13
Для того, чтобы исправить данное поведение, нужно явно указать, что данная операция асинхронная, используя ключевое слово await
. Для удобства мы добавили функцию delay
, которая позволяет поставить выполнение скрипта "на паузу" и совместима с async/await:
console.log('1');await delay(100);console.log('2');console.log('3');
В данном случае вывод будет:
123
Для получения дальнейшей информации о механизме async/await рекомендуем обратиться к документации. Работу с async/await поддерживают следующие модули:
fs.promises
axios
В заключении отметим, что на работу скрипта отводится максимум 30 секунд, по истечению которых скрипт завершится с ошибкой.
В глобальной области видимости доступен объект для доступа к проекту и текущему Script узлу - tm
.
currentNode: nodeAPI
- интерфейс текущего Script узла
project: nodeAPI
- интерфейс узла проекта
env: envAPI
- интерфейс для доступа к переменным окружения проекта
cookies: cookie[]
- список установленных в проекте cookies
systemVars: object
- объект, содержащий переменные окружения системы
parent: nodeAPI
- возвращает интерфейс для родительского узла. Для узла проекта значение будет null
name: string
- имя данного узла
type: string
- тип данного узла.
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` для данного узла.
Узел типа RequestStep
обладает расширенным интерфейсом.
request: object
- объект содержит настройки запроса узла.
response: object
- объект содержит результаты последнего выполнения запроса
active: string
- имя активного окружения
vars: object
- объект содержит переменные текущего окружения
Данный пример демонстрирует как пробросить данные всем потомкам текущего узла.
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);
В данном примере демонстрируется как можно найти дочерний узел по его имени при помощи метода findChild
const current = tm.currentNode;const scriptNode = current.parent.findChild(current.name);assert.equal(current, scriptNode);
В данном примере мы генерируем случайную строку-идентификатор при помощи библиотеки faker
и устанавливаем ее следующему узлу как динамическую переменную UUID
. После выполнения скрипта из следующего узла можно сослаться на данную переменную в URL, теле запроса и т.п.
const current = tm.currentNode;const uuid = faker.random.uuid();const anotherNode = current.next;anotherNode.setDynamicVar('UUID', uuid);
{"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#"}