Я продолжаю повторять себе (как и некоторые участники тренировочных сессий), что как-то не ладится у меня с JavaScript. Может, дело во мне, а может, и в нем, но по какой-то причине мне не удается его понять до конца. И то, что в университетские годы я занимался более строго типизированными языками (в основном Java), видимо, мне не помогает.

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

Поскольку многие технические заметки в блогах, написанные мной, посвящены тому или иному тестированию API (включая мокинг API и контрактные тесты), до сих пор я не был особенно впечатлен библиотеками для тестирования API, доступными для JavaScript. Я решил, что будет хорошей идеей сделать этот момент отправной точкой.

Я большой фанат библиотек API, например — REST Assured для Java и requests для Python, поскольку они оба упрощают написание тестов API.

Я не знал ни об одной JavaScript-библиотеке, которая была бы проста в использовании, до тех пор, пока я не увидел чью-то статью про Pactum на LinkedIn (к сожалению, не смог ее найти, чтобы приложить ссылку). Pactum меня заинтересовал, и я решил его попробовать.

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

Судя по документации, Pactum способен на многие вещи. Интегрированное тестирование, API мокинг, контрактное тестирование… здесь есть все. В этой статье я фокусируюсь на тех возможностях библиотеки, которые помогают провести тестирование API (интеграционное тестирование). Возможно, позже я исследую другие фичи Pactum-а и сделаю целую серию статей на эту тему.

Примеры, приведенные в этой статье, написаны с использованием Jest в качестве фреймворка тестирования.

Давайте начнем с самых основ тестирования API: выполнение GET-запроса к эндпоинту и проверка кодов ответа HTTP на запрос. В Pactum это может быть сделано так:

describe('Retrieving data for user with ID 1', () => {

    test('should yield HTTP status code 200', async () => {

        await pactum.spec()
            .get('http://jsonplaceholder.typicode.com/users/1')
            .expectStatus(200)
    });
});

pactum.spec() раскрывает все методы, предлагаемые Pactum для построения запроса. Поскольку нам не нужно указывать что-либо с точки зрения заголовков, cookies или тела запроса, мы можем напрямую вызвать метод GET с помощью метода get() для эндпоинта по нашему выбору, а затем указать наши ожидания относительно ответа. В этом случае мы ожидаем, что код ответа будет 200, и это мы можем проверить с помощью метода expectStatus().

Прогонка теста (с помощью npm run test, что в свою очередь вызывает Jest) показывает, что наши тесты прошли:

Далее, давайте посмотрим, сможем ли мы проверить значение в заголовке ответа, в данном случае Content-Type:

test('should yield Content-Type header containing value "application/json"', async () => {

    await pactum.spec()
        .get('http://jsonplaceholder.typicode.com/users/1')
        .expectHeaderContains('content-type', 'application/json')
});

Метод expectHeaderContains() ищет заголовок ответа и проверяет, что его значение содержит предопределенное ожидаемое значение, в данном случае application/json. Обратите внимание на один момент — по какой-то причине имя заголовка нужно указать строчными буквами. Изначально я использовал “Content-Type”, но из-за этого тест провалился, потому что не смог найти заголовок по этому имени.

Если вам нужен метод, который выполняет точное совпадение, используйте expectHeader().

Теперь давайте взглянем на тело ответа. Pactum отлично поддерживает формат JSON в теле ответа сервера, для других же форматов (простой текст, XML,...) поддержка по всей видимости ограничена сравнением на основе строк, а это значит, что вам придется немного больше проделать собственной работы. API во время тестов возвращает данные в формате JSON, поэтому это не проблема.

Предположим, мы хотим проверить, что в JSON-ответе элемент name на первом уровне вложенности содержит значение, равное “Leanne Graham”. Использование метода expectJsonMatch() в Pactum упрощает задачу:

test('should yield "name" JSON body element with value "Leanne Graham"', async () => {

    await pactum.spec()
        .get('http://jsonplaceholder.typicode.com/users/1')
        .expectJsonMatch('name', 'Leanne Graham')
});

Первый аргумент метода expectJsonMatch() на самом деле является выражением json-query, поэтому его также можно использовать для извлечения вложенных объектов, например:

test('should yield "Gwenborough" as the city within the address', async () => {

    await pactum.spec()
        .get('http://jsonplaceholder.typicode.com/users/1')
        .expectJsonMatch('address.city', 'Gwenborough')
});

Что насчет того, чтобы передавать данные в эндпоинт с помощью метода POST вместо того, чтобы получать и проверять данные из эндпоинта? Оказывается, что с Pactum это тоже можно легко сделать:

describe('Posting a new post item', () => {

    test('should yield HTTP status code 201', async () => {

        let new_post = {
            "title": "My awesome new post title",
            "body": "My awesome new post body",
            "userId": 1
        }

        await pactum.spec()
            .post('http://jsonplaceholder.typicode.com/posts')
            .withJson(new_post)
            .expectStatus(201)
    });
});

Создать полезную нагрузку JSON так же просто, как создать его и добавить в запрос с помощью метода withJson().

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

Теперь же Jest делает большую часть тяжелой работы за нас (подобно тому, как JUnit в Java или pytest в Python), поскольку дает механизм для управляемых данными тестов с помощью test.each():

describe('Retrieving user data for users', () => {

    test.each(
        [[1,'Leanne Graham'], [2,'Ervin Howell'], [3,'Clementine Bauch']]
    )('User with ID %i has name %s', async (userId, expectedName) => {

        await pactum.spec()
            .get('http://jsonplaceholder.typicode.com/users/{user}')
            .withPathParams('user', userId)
            .expectJsonMatch('name', expectedName)
    });

});

Все, что нам надо добавить во время написания наших тестов на Pactum — это указать параметр path с помощью метода withPathParams() и использовать его для заполнения плейсхолдера {user} в эндпоинте. Этот механизм действительно похож на то, к чему я привык в работе с Java, C# и Python, благодаря чему я ценю Pactum (и Jest, и даже JavaScript в целом).

Запуск этого теста дает нам следующий результат:

Running a test in Pactum and seeing that it passes
Running a test in Pactum and seeing that it passes

Из этой статьи вы узнали всего лишь небольшую часть того, что позволяет реализовать Pactum. Судя по документации, с библиотекой можно делать гораздо больше, и я жду-не дождусь возможности в будущем изучить Pactum подробнее, особенно мокинг и возможности контрактного тестирования. Никогда не думал, что когда-нибудь скажу такое о библиотеке JavaScript…

Весь код и примеры, приведенные в статье, можно найти на github.


Всех желающих приглашаем на открытое занятие «Типичное собеседование автоматизатора», на котором поговорим о софт-скиллах и хард-скиллах для удачного прохождения собеседования на автоматизатора тестирования на Java Script. Регистрация доступна по ссылке.

Комментарии (0)