Как запускать тесты API с помощью Newman и отправлять результаты в Telegram

Как запускать тесты API с помощью Newman и отправлять результаты в Telegram

8 ноября 2022 г.

Всем привет!

Как насчет того, чтобы запускать свои коллекции запросов API Postman и автоматически получать содержательный отчет прямо в Telegram? В этой статье я покажу вам, как реализовать этот трюк в одном небольшом скрипте! 🔥

Прежде всего, уместно отметить, что данная статья является лишь обучающим примером создания небольшой части конвейера непрерывной интеграции, которую можно легко выполнить локально с помощью Node.js. Это поможет вам попрактиковаться в запуске коллекций с (или без) выполнением тестов и отправкой запросов API с использованием узловых модулей и без Postman. Но для практического использования есть много отличных встроенных решений для наиболее широко известных инструментов CI, которые вы легко можете найти в свободном доступе. ♾️

Экспорт исходной коллекции и окружения из Postman 🚀

Чтобы запускать какие-либо наборы запросов API, нам сначала нужно сделать их доступными в виде отдельного файла, который можно получить, например, из Postman. Для этого случая в моем Почтальоне у меня была коллекция для проекта CRM "ClientBase v5" который содержит несколько десятков наиболее вероятных API-запросов и более 400 встроенных тестов, а в некоторых случаях и скрипты предварительного запроса.

Во всех тестах я намеренно использовал синтаксис BDD Chai Assertion Library, чтобы упростить разработку. автоматизированные тесты на их основе. Некоторые тесты содержат одни и те же утверждения, но используют немного другой синтаксис. Дело в том, что синтаксис библиотеки Postman и Chai позволяет нам реализовать конкретное утверждение по-разному, что, безусловно, здорово. 🍵

Postman collection for the CRM Project "ClientBase v5"

Все, что мне нужно было сделать, это экспортировать коллекцию в виде файла json и сохранить его локально. Далее мне будет важно знать ==только путь к этому файлу==.

The export of the collection as a json file

Я также экспортировал в виде json набор переменных среды. Большинство этих переменных были созданы как динамические, другими словами, они генерируются с использованием библиотека фейкеров. Значения переменных, как видно на картинке, изначально не заданы и заполняются автоматически в процессе выполнения запросов:

The environment variables

Если вам интересно, эта коллекция Postman доступна ==здесь == (все еще растет).

API Telegram Bot 🤖

Как я уже упоминал, после запуска сбора и создания отчета я отправлю уведомление и этот отчет в Telegram. Причем здесь важно отметить, что получателем в данном случае может ==не обязательно быть Telegram==. Например, ==это может быть Slack или любой другой ресурс==, доступный для взаимодействия через API.

Что ж, для обучающего примера я выбрал Telegram, потому что просто хотел больше узнать о возможностях Telegram Bot API. Для начала мне нужно было выбрать существующую или создать новую группу Telegram, чтобы получать туда уведомления и отчеты. Это может быть любая группа Telegram (общедоступная или закрытая). Поэтому я создал новую группу под названием "Оповещения API". Самым важным шагом было ==получение идентификатора чата== моей группы. И мне это удалось очень легко с помощью специального бота внутри Telegram — бота «Получить мой ID». Я только что переслал этому боту одно сообщение из моей только что созданной группы, и у меня уже был идентификатор чата. Были и другие способы сделать это, но этот показался быстрее.

Тогда оставалось только создать бота, с которым я собирался взаимодействовать с помощью API запросов. Ну, я сделал это еще быстрее, и ==здесь== подробное руководство по созданию Telegram бот с помощью @Botfather. Здесь главное ==получить от Botfather уникальный токен== аутентификации бота, который выглядит примерно так: 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11 . Далее я добавил своего нового бота в созданную группу "API alerts" и дал админу разрешение на отправку сообщений в группу.

Кажется, нет смысла более подробно объяснять этот шаг, потому что здесь все предельно просто и в Интернете есть масса инструкций, как это сделать.

Что ж, пришло время создать проект.

Создание проекта и установка необходимых зависимостей 🗂️

Выполнив подготовительные действия в Postman и Telegram, я, наконец, создал новый проект в IDE, инициализировал его и приступил к установке необходимых зависимостей. Поэтому для запуска коллекции я использовал Newman, средство запуска коллекции для Postman из командной строки. Для того, чтобы установить Newman локально в проект в виде библиотеки, использовалась следующая команда:

npm i newman

Что касается отчета о работе коллекции, в целом, мы можем интегрировать его с нашим конвейером CI с помощью интерфейса командной строки Postman или Newman в качестве чистого средства запуска коллекции из командной строки и генерировать некоторые отчеты, например, с помощью Allure или хотя бы JUnit. Однако мы также можем использовать генераторы отчетов Newman и получать как минимум (а иногда и гораздо больше) информативные и удобные для пользователя отчеты с целевой страницей сводки в стиле панели и набором различных вкладок, содержащих подробную информацию о запросе.

Чтобы быть более точным, я часто предпочитаю использовать html-extra reporter Дэнни Дейнтона, который — это обновленная версия стандартного Newman HTML Reporter, содержащая более подробный вывод данных и несколько полезных дополнений. 📑

Итак, этот репортер был установлен в проекте с помощью команды:

npm i newman-reporter-htmlextra

Помимо использования в проекте переменных среды, мне также понадобился еще один модуль dotenv, загружающий переменные среды из файл .env в process.env. После установки этого модуля командой:

npm i dotenv

Я создал файл .env в корне проекта, в который поместил необходимые переменные среды:

  • COLLECTION_PATH – путь к локально размещенному json-файлу с моей коллекцией Postman;
  • ENVIRONMENT_PATH — путь к локально размещенному файлу json с переменными среды, который также был экспортирован из Postman;
  • TOKEN — токен моего Telegram-бота;
  • CHAT_ID – идентификатор чата моей группы Telegram.

В моем случае это выглядело так (значения чувствительных переменных конечно изменены):

COLLECTION_PATH=C:/Users/user1/.vscode/Newman-Collection-Run-Reporter-on-CRM-Project-example/CRM_Project_ClientBase_v5_collection.json
ENVIRONMENT_PATH=C:/Users/user1/.vscode/Newman-Collection-Run-Reporter-on-CRM-Project-example/ClientBase_v5_environment.json
TOKEN=270485614:AAHfiqksKZ8WmR2zSjiQ7_v4TMAKdiHm9T0
CHAT_ID=-1002956968

Ну вот, основные зависимости установлены, пора кодить. 👨‍💻 Для этого я создал в корне проекта файл runner.js, в который включил первый блок кода:

require('dotenv').config()
const newman = require('newman');

//Running collection with Newman, report generation:

newman.run({
    collection: process.env.COLLECTION_PATH.toString(),
    environment: process.env.ENVIRONMENT_PATH.toString(),
    reporters: ['htmlextra'],
    iterationCount: 1,
    reporter: {
        htmlextra: {
            export: 'report' + '/report.html',
            // template: './template.hbs'
            // logs: true,
            // showOnlyFails: true,
            // noSyntaxHighlighting: true,
            // testPaging: true,
            browserTitle: 'My Newman report',
            title: 'My Newman Report',
            titleSize: 4,
            // omitHeaders: true,
            // skipHeaders: "Authorization",
            // omitRequestBodies: true,
            // omitResponseBodies: true,
            // hideRequestBody: ["Login"],
            // hideResponseBody: ["Auth Request"],
            showEnvironmentData: true,
            // skipEnvironmentVars: ["API_KEY"],
            // showGlobalData: true,
            // skipGlobalVars: ["API_TOKEN"],
            // skipSensitiveData: true,
            // showMarkdownLinks: true,
            showFolderDescription: true,
            // timezone: "US/Boston",
            // skipFolders: "folder name with space,folderWithoutSpace",
            // skipRequests: "request name with space,requestNameWithoutSpace",
            displayProgressBar: true
        }
    }
})

Как видите, в полях коллекция и environment я поместил COLLECTION_PATH и ENVIRONMENT_PATH в качестве переменных среды, используя свойство process.env.

В настройках репортера в поле export я ==указал каталог== куда Newman будет сохранять файл моего отчета. Другими словами, после того, как Newman завершит свою работу, в корне проекта появится новый каталог report, в котором находится report.html будет размещен.

Кроме того, как пользователи, мы можем ==настраивать шаблоны отчетов== только для своих нужд. Html-extra Reporter позволил нам сделать это, раскомментировав строки кода внутри поля htmlextra.

Проблема асинхронности и ее решение 💡

На этом этапе мы можем столкнуться с проблемой, связанной с асинхронным выполнением прохода сбора и отправкой вызова API в Telegram. Понятно, что Ньюману потребуется какое-то время, чтобы прогнать все запросы и вложенные тесты, а также сгенерировать отчет. Конечно, это всего пара секунд, но т==выполнение кода ускорит отправку звонка в Телеграм, не дожидаясь Ньюмана==.

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

npm i deasync

Этот пакет позволил мне использовать loopWhile(predicateFunc), где predicateFunc — это функция, возвращающая логическое условие цикла. Поэтому я добавил в свой код следующий блок:

let done
newman.run({
//...
})
    .on('start', () => {
        console.log(`Running a collection. Please wait a few seconds...`)
    }).on('done', () => {
        done = true
    })
    require('deasync').loopWhile(() => {
        return !done
    })

Что ж, осталось только настроить вызовы API к Telegram.

Отправка файлов с помощью Fetch API 📨

На этом этапе мне нужно было настроить отправку ==двух вызовов API== в Telegram: первый с уведомлением об успешном завершении сбора и второй с отчетом в формате HTML. Эти звонки должны были пойти сразу после того, как Ньюман завершит свою работу. Для реализации этой задачи, безусловно, можно использовать любые HTTP-клиентские библиотеки для Node.js, доступные в виде npm-пакетов (Axios, Got, SuperAgent и т. д.), но я обратился к Fetch API. Для его установки использовалась следующая команда:

npm i node-fetch

В коде я использовал метод fetch(). с обычным синтаксисом промисов:

const fetch = require('node-fetch')

//Sending an information notification to Telegram:

const url1 = `https://api.telegram.org/bot${process.env.TOKEN}/sendMessage?chat_id=${process.env.CHAT_ID}&text=
Your collection has been successfully run. The results are contained in the attached report below.`

fetch(url1, {
    method: 'GET'
})
    .then((res) => res.json())
    .then((res) => {
        console.log(res)
    })
    .catch((error) => {
        console.log(error)
    })

Как видите, константа url1 содержит строку с URL, на который отправляется запрос. Это ==стандартный шаблон==, который устанавливается Telegram API. В соответствии с этим шаблоном я включил токен и идентификатор чата внутри URL-адреса в качестве переменных среды, которые я вытащил из файла .env с помощью свойства process.env.

Следующий запрос оказался чуть сложнее в реализации, потому что внутри него нужно было отправить файл report.html, который сначала нужно было ==конвертировать== с использованием типа кодировки multipart form-data. Поэтому для создания читаемых потоков «multipart/form-data» мне нужно было использовать Form-Data. библиотека. Для того, чтобы установить его локально, использовалась следующая команда:

npm i form-data

Основываясь на синтаксисе этой библиотеки, я создал форму с одним полем, содержащим файловый поток файла report.html и передал его методу fetch() для отправки в качестве тела запроса. В результате получился следующий блок кода:

const FormData = require('form-data')
const fs = require('fs')

//Sending html-report to Telegram:

const url2 = `https://api.telegram.org/bot${process.env.TOKEN}/sendDocument?chat_id=${process.env.CHAT_ID}`

let readStream = fs.createReadStream('report/report.html')
let form = new FormData()

form.append('document', readStream)

fetch(url2, {
        method: 'POST',
        body: form,
    }
)
    .then((res) => res.json())
    .then((res) => {
        console.log(res, 'The report was successfully sent to 
        Telegram')
    })
    .catch((error) => {
        console.log(error)
    })

Что ж, наконец пришло время выполнить написанный скрипт. Однако в файле package.json я ранее изменил команду для запуска сценария «тест», написав:

"test": "node runner.js"

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

npm test

тут же в терминале появилась специальная зеленая полоска, показывающая ход выполнения сбора:

The indication of the collection running

После окончания прогона я получил два сообщения с уведомлением и файлом report.html прямо в моей группе Telegram "API alerts": ✉️

Received messages on Telegram

Отлично, давайте откроем полученный отчет и посмотрим, что это такое:

HTML report

Кроме того, в терминале я получил тело ответа от Telegram API, содержащее подробную информацию о том, что и куда было отправлено:

The bodies of the responses received from the Telegram API

Вместо заключения 👋

В этой статье я постарался максимально подробно описать весь процесс, от экспорта коллекции Postman до получения отчета о ее работе в Telegram. Я надеюсь, что повторение шагов, которые я сделал, поможет вам зарядить свои навыки API. 💪

Этот проект с подробными инструкциями по установке и использованию полностью доступен ==здесь==.


Оригинал