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

В этот момент прокси-инструменты вроде Proxyman начинают играть совсем другую роль. Это уже не просто «посмотреть запросы», а полноценный слой управления трафиком.

Меня зовут Станислав, я Test-инженер в KODE, в этой статье разберу, как использовать Proxyman Scripts не как вспомогательную фичу, а как инструмент автоматизации тестирования.

Где вообще здесь автоматизация

На первый взгляд скрипты в прокси выглядят как простая подмена ответа. Но по факту это точка, где вы можете: 

  • вмешаться в любой сетевой вызов

  • изменить данные до того, как их увидит приложение

  • воспроизвести нужное состояние системы без участия бэкенда

То есть фактически вы получаете контролируемую «прослойку» между клиентом и сервером. И это меняет подход к тестированию: вместо «ждём, пока бэкенд починят» — эмулируем ответ; вместо «не можем воспроизвести баг» — собираем сценарий вручную; вместо «нужно поднять тестовый стенд» — делаем всё локально.

Как устроено выполнение скриптов

В Proxyman скрипты выполняются в двух точках:

  • onRequest — до отправки запроса

  • onResponse — после получения ответа

Это не просто «хуки», а полноценные точки управления данными.

У вас есть доступ к объектам:

  • request

  • response

И вы можете:

  • менять body

  • редактировать headers

  • добавлять комментарии

  • менять визуальное отображение запроса

Ключевой момент: изменения происходят до того, как данные попадут в приложение.
Для клиента это выглядит так, будто сервер вернул именно эти данные.

Скрипты в Proxyman находятся во вкладке Scripting → Script List (в верхней панели). Можно создать новый скрипт, задать ему имя и выбрать, будет ли он работать на запрос (onRequest) или на ответ (onResponse). Для каждого скрипта можно указать фильтр (например, только определённые URL или методы).

Рядом с каждым скриптом есть чекбокс. Когда он включён, скрипт активен. В редакторе скрипта есть отдельные чекбоксы для onRequest и onResponse — их можно включать/отключать независимо.

Полезные инструменты, для ускорения и частичной автоматизации процесса тестирования:

  1. Использование переменных для подмены данных

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

Когда это реально полезно

  1. Фича ещё не реализована на бэке
    Можно собрать UI и протестировать поведение заранее.

  2. Данные сложно получить
    Например, редкий статус транзакции или особый тип ошибки.

  3. Нужно ускорить тестирование
    Не дергать сервер каждый раз, а стабилизировать ответ.

Шаг 1: Определите переменную

В 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"
 }];

Шаг 2: Подставьте переменную в ответ

Когда обрабатываете ответ (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"]

2. Условия if и else: основа сложных сценариев

Без условий скрипты превращаются в хаотичный набор подмен. С условиями — в инструмент сценарного тестирования.

Базовый синтаксис

if (условие) {
  // что-то делаем, если условие истинно
} else {
  // иначе делаем что-то другое

Пример 1: Проверка параметра в теле запроса

Запрос лимитов для валют, представьте, что в запросе есть параметр 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;
}

Как можно заметить вариантов решений множество, поэтому можно по разному подойти к решению необходимой задачи и автоматизировать процессы тестирования 

Пример 2: Проверка URL

Часто нужно применять логику только к определённым эндпоинтам. Например, для всех запросов, которые содержат /api/v1/payments:

if (request.url.includes("/api/v1/payments")) {
  // Здесь мы можем менять ответы для платёжных запросов
  response.body["status"] = "success";
  }

Пример 3: Проверка HTTP-метода

Разные методы (GET, POST, PUT) могут требовать разной обработки:

if (request.method === "POST") {
  // Действия только для POST-запросов
  console.log("Это POST-запрос");
  }

Пример 4: Проверка статус-кода ответа

Если сервер вернул ошибку, можно покрасить запрос в красный цвет или изменить тело ответа:

if (response.statusCode >= 400) {
  response.color = "red";
  // Можно также подменить тело ответа, чтобы приложение не упало
  response.body = { "error": "handled by script" };
}

3. Визуализация трафика: underrated-фича

Когда запросов сотни — смотреть их «в лоб» невозможно. Цветовая подсветка — это простой способ быстро находить нужные запросы в списке трафика. Например, можно выделить зелёным все успешные запросы из кэша, красным — ошибки, синим — запросы с определённым заголовком. 

Это ускоряет анализ логов, снижает когнитивную нагрузку, помогает находить паттерны.

Чтобы установить цвет, в скрипте onResponse (или onRequest) присвойте свойству response.colorстроку с названием цвета.

response.color = "blue";

Доступные цвета: redyelloworangegreenbluepurplegray.

Пример: подсветка запросов, которые пришли из кэша:

// Предположим, в запросе есть поле, запрашивающее данные из кэша
if (request.body.fromCache === true) {
  response.color = "green";
}

Теперь запрос, который обращается к кэшу, можно отличить визуально:

Пример: подсветка ошибок

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

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

4. Вывод комментариев с данными из запроса или ответа

Одна из самых недооценённых возможностей. Комментарии позволяют отображать важную информацию прямо в списке запросов, не открывая детали. Чтобы их увидеть, нужно добавить колонку 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;

Это спасает при анализе больших логов, поиске конкретных значений, отладке сложных сценариев.

5. Несколько скриптов: уже почти pipeline

Proxyman позволяет включить несколько скриптов одновременно. Они будут выполняться последовательно в том порядке, в котором расположены в списке (сверху вниз). Это удобно, когда у вас есть скрипт для общей подмены данных (например, валюты) и отдельные скрипты для специфических эндпоинтов.

Важные моменты

  • Порядок имеет значение. Если один скрипт изменяет response.body, а следующий скрипт рассчитывает на исходные данные, это может привести к неожиданным результатам. Учитывайте последовательность.

  • Нельзя использовать «Run as Mock API» для нескольких скриптов. Эта опция предназначена для имитации работы бэкенда без реального сервера. Если вы используете несколько скриптов, не включайте её, если не уверены в совместимости.

Пример настройки

  1. Скрипт №1: подменяет валюту во всех ответах на EUR.

  2. Скрипт №2: добавляет комментарий с ID пользователя.

  3. Скрипт №3: подсвечивает ошибки красным.

Все они будут работать вместе, если не конфликтуют.

Типичная ошибка:

  • первый скрипт меняет response.body

  • второй ожидает старую структуру

Получаем баг, который сложно найти.

6. Глобальные переменные sharedState: состояние между запросами

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

В 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-catch.

try {
  response.body["cards"][0]["balance"] = "1000";
} catch (e) {
  console.log("Ошибка при изменении баланса: " + e.message);
}

3. Проверяйте, что скрипт включён

Убедитесь, что чекбокс рядом со скриптом активен и что в самом скрипте включён onRequest или onResponse (в зависимости от того, что вы пишете).

Задержка ответа/запроса

В Proxyman Scripts можно на любом этапе добавить задержку к выполнению кода. Например, можно поставить задержку для ответа с сервера, чтобы успеть проанализировать отображение данных с кэша и отследить их обновление к реальным данным. Команда sleep(1000) указывает задержку, где 1000 = 1сек.

Пример:

if (request.body.fromCache === false) {
    sleep(2000);
};

Proxyman Scripts — это гибкий инструмент, который превращает прокси-сервер в мощного помощника для тестирования. С помощью скриптов вы можете:

  • Визуально анализировать трафик — окрашивая запросы и добавляя комментарии.

  • Эмулировать сложные сценарии — подменяя данные в зависимости от условий.

  • Ускорять ручное тестирование — автоматизируя повторяющиеся действия.

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

Все возможности Proxyman описаны в статье.