В чём API-тестирование в Cypress действительно хорошо
Подготовка и очистка. Создание нужного UI-тесту состояния через API вместо прокликивания пяти экранов. Быстрее, надёжнее и ровно то, для чего эта возможность и нужна.
Проверки на стыке слоёв. Сделать что-то в интерфейсе и убедиться, что бэкенд записал это правильно. Это реальный класс проверок, и Cypress справляется с ним аккуратно.
Несколько проверок эндпоинтов. Пока поверхность API невелика, держать их в том же наборе тестов — разумный размен ради простоты.
Четыре проблемы, которые приходят с масштабом
Время жизни сессии
Токены истекают посреди прогона, и падения выглядят как баги продукта.
Логику обновления токена в итоге пишут вручную в support-файле.
Значения между вызовами
Идентификатор из запроса на создание должен дойти до запроса на удаление, а цепочки команд Cypress делают это неудобным между тестами.
Значения зашивают в код, и набор тестов отрабатывает ровно один раз.
Порядок выполнения
Настоящее покрытие API — это граф, а файлы тестов — список. Ручное кодирование этого графа и съедает время на поддержку.
Четвёртая проблема — очистка. Записи накапливаются, начинают срабатывать ограничения уникальности, а проверки пагинации плывут по мере роста данных.
Почему это не совсем проблемы Cypress
Cypress проектировался вокруг жизненного цикла теста, которым управляет браузер. Всё перечисленное выше — про состояние, которое живёт за пределами одного теста и одного прогона. Решить это в support-файлах можно, но решение превращается в маленький фреймворк, который кому-то придётся поддерживать, — и вот эту цену никто не закладывает заранее.
Что вместо этого берёт на себя специализированный слой для API
Переживёт ли набор API-тестов свой первый год, решают четыре вещи — с любым инструментом: истекающие сессии, значения, которые существуют только во время выполнения, взаимозависимые вызовы и записи, которые никто не удаляет. В TestSprite это называется Auto-Authentication, Dynamic Variables, Dependency Chains и Auto-Cleanup, а документация по API-тестированию описывает механику.
Где support-файл превращается во фреймворк
Есть узнаваемый момент, когда набор API-тестов внутри Cypress перестаёт быть парой запросов и становится инфраструктурой. Его стоит назвать вслух, чтобы решение принималось осознанно, а не складывалось само собой.
Начинается всё с команды логина в support-файле. Потом появляется кэш токена, потому что логиниться в каждом тесте медленно. Потом логика обновления, потому что кэш устаревает посреди прогона. Потом хелпер, который хранит созданные идентификаторы, чтобы их нашли следующие тесты, потом договорённости о порядке в именах файлов, потом задача очистки, которая запускается после прогона и знает обо всём этом.
Ни один из этих шагов не ошибочен, каждый — очевидное следующее действие. В результате в support-директории живёт несколько сотен строк фреймворка, понятных одному человеку и находящихся за пределами раннера, на котором всё построено. Вся ценность этого описания в том, чтобы разглядеть траекторию заранее.
Разделение, которое стоит принять
Оставьте cy.request для подготовки, очистки и тех проверок на стыке слоёв, где обе стороны действительно нужны в одном тесте. А самостоятельное покрытие эндпоинтов и интеграций перенесите в слой, для которого эти четыре проблемы — часть его работы, а не ваше домашнее задание.
Двум наборам тестов не нужно знать друг о друге, и оба могут запускаться из одного пайплайна.
Триггер важнее механизма. Привязка к событию деплоя означает, что каждое изменение проверяется без чьего-либо отдельного решения: GitHub App делает это из дашборда, а шаг GitHub Actions делает это прямо внутри вашего workflow. Подробности в репозитории CLI.
Что перестаёт требовать поддержки
Именно описанный выше фреймворк в support-файлах и заменяет TestSprite. Auto-Authentication берёт на себя время жизни сессии. Dynamic Variables переносят идентификатор из запроса на создание в запрос на удаление. Dependency Chains выводят безопасный порядок из того, что каждому случаю нужно на входе и что он даёт на выходе. Auto-Cleanup удаляет ровно то, что создал прогон, — именно это делает параллельный запуск безопасным.
Покрытие также перестаёт зависеть от того, у кого есть время. Планы генерируются из спецификации или по результатам обхода работающего сервиса — вместе с ветками ошибок и граничными значениями, которые вручную никто не пишет, — и уточняются обычным языком.
За Cypress остаётся то, в чём он хорош: подготовка, очистка и проверки на стыке слоёв, где браузер и API действительно нужны в одном тесте. Оба набора запускаются из одного пайплайна и ничего не знают друг о друге.
cy.request — это плохая практика?
Вовсе нет. Это правильный инструмент для подготовки данных и проверок на стыке слоёв. Ограничение — в масштабе, а не в корректности.
Можно ли оставить всё в Cypress?
Можно — и тогда работу с сессиями, захват значений, порядок выполнения и очистку вы будете поддерживать сами. При небольшой поверхности это оправданно, дальше — дорого.
А что с компонентным тестированием в Cypress?
Всего этого оно не касается. Компонентные тесты отвечают на другой вопрос, и их лучше оставить там, где они есть.
Как избежать дублирования покрытия?
Разделяйте по вопросу. Cypress отвечает, работает ли видимый пользователю сценарий. Слой API отвечает, правильно ли ведут себя эндпоинты. Если тест прошёл бы в обоих местах, его место там, где он дешевле.
Нужен ли слою API наш исходный код?
Нет. Он работает с запущенным сервисом и узнаёт, что в нём есть, из спецификации или по результатам обхода.
Оставьте cy.request для подготовки данных, а не для всего набора API-тестов.
API-тестирование в Cypress отлично подходит для фикстур и проверок на стыке слоёв. Но как только самостоятельное покрытие API разрастается, сессии, сохранённые значения, порядок выполнения и очистка превращаются во фреймворк, который вы поддерживаете вручную, — и это тот момент, когда этот слой пора перенести туда, где он предусмотрен изначально.