Все разделы

Основные возможности

Скрипты

На этой странице

Скрипты в Tetiva — это JavaScript, который выполняется до отправки запроса (Pre-request) и после получения ответа (Post-response). Pre-скрипт подставляет заголовок, пересчитывает подпись или кладёт значение в переменную окружения; post-скрипт читает ответ, сохраняет из него токен и проверяет результат через pm.test. Скрипты живут на вкладке Scripts запроса или коллекции, выполняются в песочнице без доступа к файлам и сети, а всё, что они напечатали, попадает во вкладку Tests рядом с ответом.

Где писать#

Вкладка Scripts есть у каждого запроса, а у коллекции — раздел «Скрипты» (пункт «Открыть коллекцию» в её контекстном меню). Внутри — две кнопки: «Перед запросом» и «После ответа», каждая со своим редактором. Оба редактора остаются смонтированными, поэтому история отмен не теряется при переключении.

У WebSocket-запроса кнопка одна и называется «Перед подключением»: скрипт выполняется перед рукопожатием, а фазы post-response там нет — см. WebSocket.

Редактор понимает pm. и подсказывает методы по мере набора, а {{var}} подсвечиваются и резолвятся так же, как в теле запроса: наведите курсор — увидите значение из активного окружения, секреты замаскированы.

Tetiva
v1.3.1
Вкладка Scripts в Tetiva: post-response скрипт с pm.test и результатами тестовВкладка Scripts в Tetiva: post-response скрипт с pm.test и результатами тестов
Post-скрипт сохраняет токен и проверяет ответ — результат виден во вкладке Tests

Наследование: запрос → коллекция → родитель#

Скрипт запроса перекрывает скрипт коллекции целиком. Если поле у запроса пустое или в нём одни пустые строки, Tetiva идёт вверх по дереву коллекций и берёт первый непустой скрипт (глубина обхода — до 50 уровней). Pre и post наследуются независимо: post-скрипт может прийти от коллекции, пока pre-скрипт задан на самом запросе.

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

API pm.*#

Доступно в обеих фазах:

ВызовЧто делает
console.log(...)Печатает в блок Console вкладки Tests; объект или массив выводится как JSON. warn, error, info пишут в тот же поток, уровней нет
pm.environment.get(key)Значение переменной или undefined
pm.environment.set(key, value)Задать переменную; значение приводится к строке
pm.environment.unset(key)Убрать переменную из набора этого запуска
pm.collectionVariables.get/set/unsetТо же, что pm.environment: работает с переменными активного окружения
pm.variables.get/set/unset/has, replaceIn(text), toObject()Переменные этого запуска: значение из pre-скрипта подставляется в {{переменные}} запроса и видно его post-скрипту, но в окружение не сохраняется. Если локального значения нет, get берёт его из окружения
btoa(text), atob(base64)Base64, как в браузере. atob понимает и base64url, и строку без = в конце, так что JSON.parse(atob(jwt.split('.')[1])) читает payload JWT
pm.expect(value)Утверждение chai 4.5, как в Postman. Вне pm.test проваленное утверждение становится ошибкой скрипта
pm.request.methodМетод запроса
pm.request.urlURL после подстановки переменных
pm.request.protocolhttp, grpc, graphql или websocket
pm.request.headers.upsert({ key, value })Добавить заголовок или заменить существующий; регистр имени не важен, так что content-type заменит Content-Type
pm.request.headers.add({ key, value })Добавить заголовок; если такой уже есть, у него появится второе значение
pm.request.headers.remove(key)Удалить заголовок, в каком бы регистре ни было записано имя

pm.request доступен в обеих фазах, но headers.add, upsert и remove в post-скрипте ни на что не влияют: запрос уже ушёл, и его изменённую копию никто не читает.

Только для gRPC: pm.request.service, pm.request.grpcMethod, pm.request.message (тело в JSON), а также pm.request.metadata с методами get(key), set(key, value), remove(key) и toObject(). Метаданные приходят в скрипт копией: set меняет то, что уйдёт на сервер, но запись в коллекции остаётся нетронутой. Подробнее — gRPC.

Только для GraphQL: pm.request.graphqlVariables и pm.request.graphqlOperation. См. GraphQL.

Только в post-скрипте:

ВызовЧто делает
pm.response.codeКод ответа числом
pm.response.statusТекст статуса, "OK", как в Postman; у gRPC — имя статуса
pm.response.text()Тело ответа строкой
pm.response.json()Тело, разобранное как JSON; при невалидном JSON возвращает undefined, а не бросает исключение
pm.response.responseTimeВремя ответа в миллисекундах
pm.response.headers.get(name), pm.response.headers.has(name)Значение заголовка ответа (имя без учёта регистра) или undefined; есть ли такой заголовок
pm.response.to.have.status(...), .header(...), .body(...), .jsonBody(...), pm.response.to.be.jsonПроверки ответа, как в Postman; status принимает код или текст статуса
pm.response.to.be.ok, success, clientError, serverError, notFound и другиеКласс статуса; у gRPC ok и success означают статус 0
pm.test(name, fn)Тест: fn без исключения — PASS. Проваленное утверждение — FAIL с его сообщением, как в Postman (AssertionError: expected 200 to equal 201); другая ошибка, например TypeError, — FAIL с номером строки

У gRPC добавляются pm.response.statusText (имя статуса) и pm.response.metadata — обычный объект, где каждому ключу соответствует первое значение.

Утверждения пишутся на chai 4.5, как в Postman: pm.expect(x).to.equal(y), eql, include, property, lengthOf и остальные. Проверка через throw тоже работает.

Что происходит с переменными#

Значения, которые скрипт положил через pm.environment.set, после выполнения запроса записываются в активное окружение: существующие переменные обновляются, недостающие создаются как обычные (не секретные). Если активного окружения нет, изменения живут только внутри запуска. А pm.variables.set в окружение не попадает никогда: значение перекрывает переменную окружения с тем же именем только в этом запросе. Разбор приоритетов — на странице Окружения и переменные.

Заголовки, которые ставит сам скрипт, тоже проходят подстановку — во всех протоколах. Раньше {{переменные}} из скрипта уходили на сервер как есть, теперь они раскрываются перед отправкой, как и всё остальное.

Ограничения песочницы#

  • Файловой системы и сети нет: fetch, XMLHttpRequest, WebSocket, require, process, module, Buffer, __dirname не определены.
  • Таймеров нет: setTimeout и setInterval отсутствуют. Promise доступен, но отложить код нечем.
  • Стандартные JSON и Math на месте, как и btoa с atob.
  • pm.globals и pm.sendRequest есть только для того, чтобы упасть с понятным сообщением: pm.globals is not supported in Tetiva; use pm.environment и pm.sendRequest is not supported in Tetiva: scripts cannot make network calls.
  • Состояние не переживает запуск: каждый скрипт получает свежую машину, глобальные переменные из прошлого запуска не видны.
  • На каждую фазу — 5 секунд. Скрипт, который не реагирует на остановку (классический случай — регулярное выражение с возвратами), остаётся доигрывать в фоне, но окно и остальные вкладки при этом не зависают.
  • Ограничения памяти нет. Это стоит помнить, открывая чужую коллекцию.

Ошибка в скрипте#

Если pre-скрипт бросил исключение или не уложился в 5 секунд, запрос не уходит — как в Postman. В историю ничего не попадает, окружение остаётся прежним. Панель ответа показывает Request not sent: The pre-request script of this request failed: (или of collection “Payments”, если скрипт пришёл от коллекции), за ним текст ошибки со строкой и столбцом, подсказку, где её исправить, и строки Console, которые скрипт успел напечатать.

Ошибка в post-скрипте ответ не трогает. Тесты, прошедшие до ошибки, и вывод консоли остаются во вкладке Tests, а в Script Errors появляется Post-response: с текстом ошибки и местом вроде (line 5, column 6). Изменения окружения из этого скрипта не сохраняются.

Тесты и консоль#

Вкладка Tests рядом с ответом собирает три блока: Test Results с PASS/FAIL по каждому pm.test, Console с выводом обеих фаз (строки помечены [pre] и [post]) и Script Errors с фазой и текстом ошибки. Бейдж на вкладке показывает «пройдено/всего», а при одних лишь console-строках — точку. Подробнее про панель ответа — Просмотр ответа.

Примеры#

Pre-скрипт: подпись и заголовок трассировки.

pm.request.headers.upsert({ key: "X-Request-Id", value: String(Date.now()) })

var token = pm.environment.get("access_token")
if (!token) {
  console.warn("access_token пуст — сначала выполните запрос логина")
}

Post-скрипт: сохранить токен и проверить ответ.

var data = pm.response.json()

pm.test("статус 200", function () {
  pm.response.to.have.status(200)
})

pm.test("токен пришёл", function () {
  pm.expect(data).to.have.property("access_token")
})

if (data && data.access_token) {
  pm.environment.set("access_token", data.access_token)
}

Копирование cURL и скрипты#

Пункт Copy as cURL у HTTP-запроса прогоняет pre-скрипт в режиме dry-run: изменения заголовков и переменных попадают в команду, но не сохраняются в базу и не создают запись в истории. Если скрипт упал, команда не копируется: уведомление называет ошибку, а его кнопка Generate code… копирует команду без запуска скрипта. За токеном OAuth 2.0 команда в сеть не ходит — если токена нет, она уйдёт без Authorization и с предупреждением. Остальные пункты Copy as, Copy as cURL у GraphQL-запроса и диалог Generate code скрипт не запускают и предупреждают об этом. Подробности — Импорт и экспорт.

Скрипты, написанные для Postman, могут потребовать правок: поддержано только подмножество pm.* из таблиц выше, и pm.sendRequest, pm.globals или require придётся заменить: скрипт, который их вызывает, падает на этой строке, а в pre-скрипте это ещё и останавливает отправку. Что переносится при миграции, разобрано на странице Переход с Postman.

обновлено