Интеграционные тесты руками агента: что я проверяю до мержа
Раннер Medusa поднимает приложение целиком, агент пишет сценарии, я проверяю, что эти сценарии вообще способны упасть. Разбираю свой чек-лист перед мержем и три места, где агенту нельзя верить на слово.
Когда я собирал витрину на Astro поверх Medusa, почти каждый коммит трогал стык двух систем. Конфиг nginx с редиректами, YML-фид для маркетплейсов, CI/CD, потом Dockerfile для Medusa и calculated_price, который витрина упорно не получала. Ни одна из этих поломок не ловится юнит-тестом: функции по отдельности работают, разваливается склейка.
Поэтому перед каждым мержем я прошу агента прогнать интеграционные тесты. Ниже — что именно я проверяю и где агенту нельзя верить на слово.
Почему интеграционные
Medusa даёт для этого готовый раннер в medusa-test-utils. Он поднимает приложение целиком — с контейнером зависимостей и HTTP-клиентом, — так что тест ходит по настоящему роуту:
import { medusaIntegrationTestRunner } from "medusa-test-utils"
medusaIntegrationTestRunner({
testSuite: ({ api, getContainer }) => {
describe("GET /store/custom", () => {
it("returns correct message", async () => {
const response = await api.get(`/store/custom`)
expect(response.status).toEqual(200)
})
})
},
})
Ключевое здесь — api и getContainer. Первый бьёт по роуту как реальный клиент. Второй даёт доступ к сервисам: подготовить данные до запроса и проверить состояние базы после. Этого хватает, чтобы ловить большинство поломок на склейке.
Как я ставлю задачу агенту
Формулировка «напиши тесты для роута» даёт бесполезный результат: агент проверит статус 200 и успокоится. Работает другая постановка — я описываю сценарий словами клиента, и агент сам решает, что для этого нужно поднять.
- «Покупатель открывает карточку товара и видит цену для своего региона» → тест на
calculated_priceв ответе/store/products - «Маркетплейс скачивает фид и видит все активные товары» → тест на структуру YML и состав позиций
- «Старый URL со старого сайта ведёт на новую карточку» → проверка редиректа
Такая формулировка заставляет агента лезть в контейнер за реальными данными, вместо того чтобы подменять ответ заглушкой.
Чек-лист до мержа
Что я прогоняю перед каждым merge:
- Роуты витрины. Статус, форма ответа, обязательные поля. Для товаров — наличие
calculated_price. Именно на нём я один раз обжёгся: цена приходит только при правильном контексте региона, и без него витрина показывает пустоту. - Побочные эффекты. После POST идём через
getContainer()в сервис и смотрим, что запись создалась с нужными полями. Ответ 201 сам по себе ничего не доказывает. - Ошибки. Невалидный id, отсутствующий регион, пустая корзина. Агент по умолчанию пишет только happy path, эту часть приходится требовать явно.
- Внешние контракты. YML-фид парсится как валидный XML, обязательные элементы на месте. Фид ломается тихо: узнаёшь об этом от маркетплейса через неделю.
- Сборка. Зелёные тесты локально мало значат, если Dockerfile собирает другое окружение. Прогон идёт в том же образе, который уедет на прод.
Три места, где агент врёт
Тест, который не может упасть. Классика жанра: expect(response.status).toBeLessThan(500). Формально зелёный, смысла ноль. Лечится грубо: прошу агента специально сломать код и показать красный прогон. Если тест остался зелёным, он мусор.
Заглушка вместо интеграции. Когда тест долго не проходит, агент начинает упрощать себе жизнь: подменяет сервис моком, и тест начинает проверять мок. Признак — jest.mock внутри интеграционного теста. Это повод остановиться и разобраться, почему настоящий сервис не поднялся.
Отчёт без запуска. Самое неприятное. Агент пишет «все тесты проходят», а прогона не было. Я всегда требую вывод команды целиком: сколько тестов, сколько прошло, сколько времени заняло. Нет вывода — нет зелёного.
Что это в итоге даёт
Роль сместилась: теперь я приёмщик тестов. Агент пишет их быстрее, чем я успеваю сформулировать сценарий, и это честно экономит время. Взамен я держу дисциплину проверки — каждый новый тест обязан доказать, что умеет краснеть.
Финальный вопрос перед мержем всегда один: если я сейчас сломаю эту функцию, какой тест покраснеет? Когда внятного ответа нет, тестов недостаточно, сколько бы их ни было в отчёте.
Исследовательская сессия автоматизации
Очно или в Zoom разбираю вашу работу изнутри, ставлю гипотезы и тут же применяю их на реальной задаче. Уходите с инструментом, который уже работает.