Proxyman Scripts: как превратить прокси в инструмент автоматизации тестирования
- пятница, 10 апреля 2026 г. в 00:00:04
Когда в проекте появляются сложные сценарии: нестабильный бэкенд, редкие ошибки, зависимость от внешних сервисов, классические инструменты тестирования могут тормозить. Любая правка требует участия сервера, а воспроизведение бага превращается в квест.
В этот момент прокси-инструменты вроде Proxyman начинают играть совсем другую роль. Это уже не просто «посмотреть запросы», а полноценный слой управления трафиком.
Меня зовут Станислав, я Test-инженер в KODE, в этой статье разберу, как использовать Proxyman Scripts не как вспомогательную фичу, а как инструмент автоматизации тестирования.
На первый взгляд скрипты в прокси выглядят как простая подмена ответа. Но по факту это точка, где вы можете:
вмешаться в любой сетевой вызов
изменить данные до того, как их увидит приложение
воспроизвести нужное состояние системы без участия бэкенда
То есть фактически вы получаете контролируемую «прослойку» между клиентом и сервером. И это меняет подход к тестированию: вместо «ждём, пока бэкенд починят» — эмулируем ответ; вместо «не можем воспроизвести баг» — собираем сценарий вручную; вместо «нужно поднять тестовый стенд» — делаем всё локально.
В Proxyman скрипты выполняются в двух точках:
onRequest — до отправки запроса
onResponse — после получения ответа
Это не просто «хуки», а полноценные точки управления данными.
У вас есть доступ к объектам:
request
response
И вы можете:
менять body
редактировать headers
добавлять комментарии
менять визуальное отображение запроса
Ключевой момент: изменения происходят до того, как данные попадут в приложение.
Для клиента это выглядит так, будто сервер вернул именно эти данные.
Скрипты в Proxyman находятся во вкладке Scripting → Script List (в верхней панели). Можно создать новый скрипт, задать ему имя и выбрать, будет ли он работать на запрос (onRequest) или на ответ (onResponse). Для каждого скрипта можно указать фильтр (например, только определённые URL или методы).
Рядом с каждым скриптом есть чекбокс. Когда он включён, скрипт активен. В редакторе скрипта есть отдельные чекбоксы для onRequest и onResponse — их можно включать/отключать независимо.

Использование переменных для подмены данных
Переменные помогают хранить значения, которые вы хотите подставить в ответ или запрос. Это удобно, когда нужно заменить большой блок данных (например, массив карт) или точечно изменить один параметр.
Фича ещё не реализована на бэке
Можно собрать UI и протестировать поведение заранее.
Данные сложно получить
Например, редкий статус транзакции или особый тип ошибки.
Нужно ускорить тестирование
Не дергать сервер каждый раз, а стабилизировать ответ.
В JavaScript переменная объявляется с помощью var, let или const. Внутри скрипта вы можете создать объект или массив, который будет имитировать данные.
Переменные:
var: Устаревший. Виден везде внутри функции (даже вне циклов/условий). Можно объявлять повторно.
let: Современный. Виден только внутри блока { } (например, внутри if или for).
const: Как let, но значение нельзя менять (кроме содержимого объектов и массивов).
// Пример: создаём переменную, которая будет имитировать массив cards данные карты и назовем ее cards_mock var cards_mock = [{ "accountOpenDate": "2019-03-12", "applePayAvailable": true, "availableBalance": "2500", "cardHolder": "TESTER QA", "cardId": "100002556979", "cardNoFinish": "7777", "bnpl": { "amount": { "available": "1200", "currency": "EUR", "total": "2000" } } }, { "accountOpenDate": "2012-08-22", "applePayAvailable": false, "availableBalance": "1000", "cardHolder": "TESTER QA2", "cardId": "100002556997", "cardNoFinish": "8888" }];
Когда обрабатываете ответ (onResponse), у вас есть доступ к объекту response.body. Это тело ответа, которое сервер вернул приложению. Вы можете заменить его часть или полностью.
// Заменяем весь массив "cards" в ответе на нашу переменную response.body["cards"] = cards_mock;
Получаем такую функцию, объявляем массив в переменную, после чего используем ее для подмены ответа. Можно использовать разные переменные и менять их в зависимости от условий.

Из всего ответа мы подменили только один массив, не затрагивая остальные данные.

Если нужно изменить только одно поле внутри существующего ответа, используйте путь к объекту и индексацию для массива:
// Меняем конкретное поле для второй карты в массиве response.body["cards"][0]["availableBalance"] = "9999";


// Или более глубокое поле внутри первой карты в массиве response.body["cards"][0]["bnpl"]["amount"]["available"] = "100";


Если вы работаете с response.body, убедитесь, что ответ действительно содержит JSON. Для XML или других форматов подход может отличаться.
Если подменяете данные в onRequest, используйте request.body (тело запроса).
Аналогично можно подменять значения для request.headers["X-New-Headers"] и request.queries["name"]
Без условий скрипты превращаются в хаотичный набор подмен. С условиями — в инструмент сценарного тестирования.
if (условие) { // что-то делаем, если условие истинно } else { // иначе делаем что-то другое
Запрос лимитов для валют, представьте, что в запросе есть параметр currency. Если он соответствует нужной валюте, мы хотим отдать заранее подготовленный ответ.
Вариант 1: Объявляем переменные и подставляем их в тело ответа в зависимости от запрошенной валюты
async function onResponse(context, url, request, response) { // Определяем три возможных варианта ответа для RUB, EUR и любого другого значения var bodyRub = { "amountLimit": { "maximum": "90000", "minimum": "1" } }; var bodyEur = { "amountLimit": { "maximum": "1000", "minimum": "1" } }; var bodyOther = { "amountLimit": { "maximum": "2000", "minimum": "1" } }; // Проверяем тело запроса, а именно значение параметра currency if (request.body.currency === "RUB") { response.body = bodyRub; // Если запрос отправляется для валюты "RUB" - то подставляем переменную c лимитом для RUB } else if (request.body.currency === "EUR") { response.body = bodyEur; // Для EUR соответственно подставляем лимит EUR } else { response.body = bodyOther; // Для всех других значений валюты - подставляем переменную c общим лимитом } return response; }



Все эти проверки работают автоматизированно в одном скрипте, поэтому не требуется каждый раз вмешиваться в подмену запроса или ответа.
Вариант 2:: Представленная выше схема показана для логики работы if/else, но данное решение можно реализовать и другим способом, более изящным (вставляем этот код вместо блока с условной логикой):
// Создаем объект-словарь с соотношением значений currency к переменной ответа const currencyMap = { RUB: bodyRub, EUR: bodyEur }; response.body = currencyMap[request.body.currency] || bodyOther; //Теперь тело ответа будет подставлять соответствующую переменную со словаря, а в случае отсутствия в словаре - bodyOther
Вариант 3: Так-же можно обойтись и без переменных, если нам требуется подменить только одно значение максимального лимита:
async function onResponse(context, url, request, response) { if (request.body.currency === "RUB") { response.body["amountLimit"]["maximum"] = "90000"; // для RUB } else if (request.body.currency === "EUR") { response.body["amountLimit"]["maximum"] = "1000"; // для EUR } else { response.body["amountLimit"]["maximum"] = "2000"; // Другие валюты } return response; }
Вариант 4: Лучшее из вариантов 2 и 3, в случае когда нужно подменить значение только одного параметра - создаем объект словарь со значением максимального лимита для каждой валюты:
async function onResponse(context, url, request, response) { const limits = { RUB: "90000", EUR: "1000" }; // Берем значение из словаря, если его нет — ставим "2000" response.body.amountLimit.maximum = limits[request.body.currency] || "2000"; return response; }
Как можно заметить вариантов решений множество, поэтому можно по разному подойти к решению необходимой задачи и автоматизировать процессы тестирования
Часто нужно применять логику только к определённым эндпоинтам. Например, для всех запросов, которые содержат /api/v1/payments:
if (request.url.includes("/api/v1/payments")) { // Здесь мы можем менять ответы для платёжных запросов response.body["status"] = "success"; }
Разные методы (GET, POST, PUT) могут требовать разной обработки:
if (request.method === "POST") { // Действия только для POST-запросов console.log("Это POST-запрос"); }
Если сервер вернул ошибку, можно покрасить запрос в красный цвет или изменить тело ответа:
if (response.statusCode >= 400) { response.color = "red"; // Можно также подменить тело ответа, чтобы приложение не упало response.body = { "error": "handled by script" }; }
Когда запросов сотни — смотреть их «в лоб» невозможно. Цветовая подсветка — это простой способ быстро находить нужные запросы в списке трафика. Например, можно выделить зелёным все успешные запросы из кэша, красным — ошибки, синим — запросы с определённым заголовком.
Чтобы установить цвет, в скрипте onResponse (или onRequest) присвойте свойству response.colorстроку с названием цвета.
response.color = "blue";
Доступные цвета: red, yellow, orange, green, blue, purple, gray.
Пример: подсветка запросов, которые пришли из кэша:
// Предположим, в запросе есть поле, запрашивающее данные из кэша if (request.body.fromCache === true) { response.color = "green"; }
Теперь запрос, который обращается к кэшу, можно отличить визуально:

if (response.statusCode >= 400) { response.color = "red"; }

В результате в окне списка запросов вы увидите цветной текст в строке запроса. Это помогает мгновенно оценить, какие запросы требуют внимания.
Одна из самых недооценённых возможностей. Комментарии позволяют отображать важную информацию прямо в списке запросов, не открывая детали. Чтобы их увидеть, нужно добавить колонку Comment в интерфейсе Proxyman (обычно клик правой кнопкой по заголовкам колонок → выбрать Comment).
Добавление комментария с фиксированным текстом
response.comment = "TEST";
Теперь в колонке Comment у этого запроса будет написано "TEST".

Вы можете извлечь значение из тела запроса или ответа и поместить его в комментарий.
В onRequest:
async function onRequest(context, url, request) { request.comment = request.body["name"]; }

В onResponse:
async function onResponse(context, url, request, response) { response.comment = response.body["cards"][0]["availableBalance"]; }

Комментарии можно комбинировать из нескольких полей, например:
response.comment = "Status: " + response.statusCode + " | User: " + response.body.user.name;
Proxyman позволяет включить несколько скриптов одновременно. Они будут выполняться последовательно в том порядке, в котором расположены в списке (сверху вниз). Это удобно, когда у вас есть скрипт для общей подмены данных (например, валюты) и отдельные скрипты для специфических эндпоинтов.
Порядок имеет значение. Если один скрипт изменяет response.body, а следующий скрипт рассчитывает на исходные данные, это может привести к неожиданным результатам. Учитывайте последовательность.
Нельзя использовать «Run as Mock API» для нескольких скриптов. Эта опция предназначена для имитации работы бэкенда без реального сервера. Если вы используете несколько скриптов, не включайте её, если не уверены в совместимости.
Скрипт №1: подменяет валюту во всех ответах на EUR.
Скрипт №2: добавляет комментарий с ID пользователя.
Скрипт №3: подсвечивает ошибки красным.
Все они будут работать вместе, если не конфликтуют.
первый скрипт меняет response.body
второй ожидает старую структуру
Получаем баг, который сложно найти.
Глобальные переменные позволяют обмениваться данными между разными скриптами. Например, один скрипт сохраняет токен авторизации из ответа, а другой скрипт использует этот токен в последующих запросах.
В Proxyman за глобальные переменные отвечает объект sharedState. Вы можете сохранить в него любое значение, а затем прочитать его в другом скрипте.
// В скрипте onResponse после успешного входа sharedState.refreshTokenNC = response.body["refreshToken"];
В другом скрипте (например, для обновления токена) мы можем подставить этот токен в тело запроса.
// В скрипте onRequest для обновления токена request.body["refreshToken"] = sharedState.refreshTokenNC;
Чтобы глобальные переменные работали, нужно разрешить их использование. В интерфейсе Proxyman перейдите в Scripting → Advanced и убедитесь, что опция включена.

Не забывайте проверять существование переменной перед использованием:
if (sharedState.refreshTokenNC) { request.body["refreshToken"] = sharedState.refreshTokenNC;
Это убережёт от ошибок, если скрипт выполнится раньше, чем переменная будет установлена.
Когда вы пишете скрипты, полезно видеть, что происходит внутри. Вот несколько способов отладки:
1. Используйте console.log
В Proxyman вывод console.log можно увидеть в окне Scripting → Console (или в отдельной вкладке Console). Добавляйте логи, чтобы проверить, что скрипт вообще выполняется и какие значения имеют переменные.
console.log("Скрипт сработал для URL: " + url); console.log("Значение fromCache: " + request.body.fromCache);

Чтобы скрипт не падал из-за ошибок (например, отсутствия поля), оборачивайте критичные участки в try-catch.
try { response.body["cards"][0]["balance"] = "1000"; } catch (e) { console.log("Ошибка при изменении баланса: " + e.message); }
Убедитесь, что чекбокс рядом со скриптом активен и что в самом скрипте включён onRequest или onResponse (в зависимости от того, что вы пишете).
В Proxyman Scripts можно на любом этапе добавить задержку к выполнению кода. Например, можно поставить задержку для ответа с сервера, чтобы успеть проанализировать отображение данных с кэша и отследить их обновление к реальным данным. Команда sleep(1000) указывает задержку, где 1000 = 1сек.
Пример:
if (request.body.fromCache === false) { sleep(2000); };
Proxyman Scripts — это гибкий инструмент, который превращает прокси-сервер в мощного помощника для тестирования. С помощью скриптов вы можете:
Визуально анализировать трафик — окрашивая запросы и добавляя комментарии.
Эмулировать сложные сценарии — подменяя данные в зависимости от условий.
Ускорять ручное тестирование — автоматизируя повторяющиеся действия.
Не бойтесь экспериментировать: пробуйте менять разные поля, смотрите, как реагирует приложение. Со временем вы сможете создавать сложные цепочки скриптов, которые помогут проверять даже самые запутанные сценарии.
Все возможности Proxyman описаны в статье.