---
title: "Скрипты и расширение"
id: "2101"
type: "page"
slug: "scripts"
published_at: "2026-09-30T18:20:37+00:00"
modified_at: "2026-10-19T18:55:42+00:00"
url: "https://pastukhov.com/agents/test/docs/scripts/"
markdown_url: "https://pastukhov.com/agents/test/docs/scripts.md"
excerpt: "Продукт закрывает типовые проверки интерфейса из коробки, а всё остальное можно дописать самому. Скрипт —…"
---

# Скрипты и расширение

[https://pastukhov.com/agents/test/docs/scripts/.md](https://pastukhov.com/agents/test/docs/scripts/.md)

Продукт закрывает типовые проверки интерфейса из коробки, а всё остальное можно дописать самому. **Скрипт** — это обычный файл с кодом на Python, который лежит в папке проекта: он может стать шагом теста, движком сравнения снимков, классификатором отличий или обработчиком завершённого прогона. Пересобирать и обновлять продукт для этого не нужно — в этом и смысл расширения. Ветка необязательная: без скриптов всё работает как раньше.

## Что такое скрипт

Скрипт — это файл с кодом на Python. Он лежит в папке проекта рядом с правилами и действиями и хранится вместе с проектом в git, то есть попадает в ту же историю версий и проходит тот же контроль, что и остальные файлы проекта.

Перед каждым запуском продукт читает файл заново. Поэтому правка вступает в силу сразу, без перезапуска сервера: сохранили файл — следующий запуск выполнит уже новый код. Зачем это нужно: продукт перестаёт быть набором готовых заготовок. Новый вид проверки заводится там, где живёт проект, — например, проверка адреса API, счётчика в базе данных или нужного файла на диске.

## Где живёт скрипт

Скрипты живут в папке `scripts/` внутри проекта. В ней три вещи:

- `scripts.yml` — опись: название скрипта, зачем он нужен, включён он или выключен, свой таймаут, разрешённые переменные сервера и свои переменные.
- `<id>.py` — сам код. Имя файла и есть имя скрипта в описи.
- `requirements.txt` — необязательный список библиотек, которые скрипту нужны.

Всё, что скрипту нужно для работы, но не является его кодом — окружение Python и рабочие каталоги для промежуточных файлов, — продукт держит в своих данных (папка `TEST_APP_DATA`, в образе — `/apps/test`), а не в папке проекта.

## Куда можно подключить скрипт

Один и тот же файл подключается к пяти точкам работы конвейера. Чем полезна каждая:

- **Шаг теста.** Проверка адреса API, базы данных или файла прямо в прогоне — рядом с шагами, которые работают в браузере. Подробности — в разделе [Тесты](/agents/test/docs/tests) .
- **Тест целиком из скриптов.** Если все шаги теста — скрипты, браузер не нужен: тест выполняется на сервере, а очередь, расписание и внешний доступ работают как обычно. В строке исполнителя такого прогона будет указан сервер — это видно в разделе [Запуски](/agents/test/docs/runs) .
- **Движок сравнения снимков.** Скрипт сам сравнивает два снимка и отвечает, на сколько процентов они отличаются: свой алгоритм вместо встроенного.
- **Классификатор отличий.** Скрипт смотрит на спорные отличия до того, как за дело возьмётся модель, и решает, важное это отличие или случайный шум. Он может только повысить важность, но не понизить её и ничего не одобряет.
- **Обработчик после прогона.** Когда прогон завершился, продукт передаёт внешнему коду его сводку — так делаются уведомления, отчёты и выгрузки.

Кроме этого, любой скрипт можно запустить вручную — с любыми аргументами, чтобы проверить его до подключения. Движок сравнения и классификатор описаны в разделе [Визуальное тестирование](/agents/test/docs/visual)
.

## Вкладка «Скрипты»

Работать со скриптами удобнее всего из отдельной вкладки «Скрипты» в окне проекта. В ней видно:

- **Список скриптов** со значками «используется в» — сразу понятно, какие тесты и настройки на скрипт ссылаются.
- **Редактор кода** с подсветкой Python и полем заметки «зачем нужен этот скрипт». Заметка помогает вспомнить назначение через полгода.
- **Настройки скрипта:** свой таймаут, разрешённые переменные сервера и свои переменные.
- **Пробный запуск** с аргументами в виде JSON — так скрипт проверяют до того, как подключать его к тестам.
- **Журнал запусков** — все запуски этого скрипта на одном экране.

Сверху вкладка честно предупреждает о том, что мешает работе: Python не найден, окружение ещё готовится или выполнение скриптов отключено. Эти предупреждения лучше не игнорировать — именно из-за них скрипт может не запуститься, и причина будет видна сразу.

## Что получает скрипт и что возвращает

Договор простой. На вход скрипт получает один объект JSON: какая точка его вызвала, что за прогон идёт, какие аргументы подключения заданы и сведения самой точки — например, имена файлов со снимками. На выход идёт последний объект JSON, который скрипт напечатал; строки, напечатанные раньше, не мешают.

То же самое скрипт видит и переменными окружения: `TEST_APP_SCRIPT_KEY` — имя самого скрипта, `TEST_APP_POINT` — точка подключения, `TEST_APP_RUN_ID` — номер записи в журнале (по нему запуск легко найти потом), `TEST_APP_WORK_DIR` — рабочий каталог запуска. Переменных сервера среди них нет — только разрешённые вами и свои.

Что именно вернуть — зависит от точки. Шаг теста отвечает «получилось или нет» и может вернуть строки проверок; движок сравнения — процент отличий; классификатор — класс отличия; обработчик прогона — что угодно. Вот короткий скрипт, который проверяет адрес API:

```
import json, sys, urllib.request

data = json.loads(sys.stdin.read())
url = data.get("args", {}).get("url")

with urllib.request.urlopen(url, timeout=20) as resp:
    ok = resp.status == 200

print(json.dumps({"ok": ok, "output": "адрес отвечает" if ok else "адрес не отвечает"}))
```

Все остальные подробности договора — как устроен объект на входе и что ждёт каждая точка на выходе — собраны в разделе [Внешний доступ для агентов](/agents/test/docs/external-api)
.

## Переменные и секреты

Скрипт видит не всё окружение сервера, а только то, что ему разрешили: список разрешённых переменных сервера и свои переменные. Значение вида `$ИМЯ` подставляется из окружения во время запуска и нигде не хранится. Значения с «секретными» именами — например, `token`, `secret`, `password` — читаются как `***`, так что случайно перезаписать пароль местами нельзя.

Зачем так сделано: в файлах проекта не должно оказаться паролей — они живут в переменных, как и у действий. Как заводить сами переменные и учётные данные, описано в разделе [Среды, учётные данные и переменные](/agents/test/docs/environments)
.

## Что видно про каждый запуск

Каждый запуск оставляет ровно одну запись в журнале — и удачный, и неудачный. В записи видно точку подключения, источник (вручную, расписание, внешний доступ, прогон), статус, длительность и хвост ошибки, если она была. Неудачи названы словами, а не кодами: выполнение отключено, нет Python, превышено время, код завершился с ошибкой, файл скрипта пропал, непонятный вывод, слишком много вывода, запуск отменён.

Записи хранятся 30 дней по умолчанию. Журнал — первое место, куда стоит смотреть, если скрипт ведёт себя не так, как ожидалось: по нему видно, дошло ли дело до запуска и что именно ответил скрипт.

## Среда исполнения и библиотеки

Своё окружение Python заводится для каждого проекта отдельно и создаётся при первом запуске. Интерпретатор берётся из переменной `TEST_APP_PYTHON` (по умолчанию `python3`); от него и строится окружение. Библиотеки из `requirements.txt` ставятся один раз и обновляются только тогда, когда файл изменился, — лишней работы при каждом запуске не происходит.

Если Python не найден или установка библиотек не удалась, продукт говорит об этом прямо в предупреждении на вкладке и записывает причину в журнал. Тихого пропуска, когда скрипт вроде бы есть, но никогда не работает, не бывает.

## Предохранители

У скриптов есть пределы — их можно менять в настройках проекта, но совсем снять нельзя:

- **Время одного запуска.** По умолчанию 60 секунд, потолок — 600 секунд. По истечении времени уничтожается всё дерево процессов, включая дочерние, так что зависший скрипт не остаётся работать втихую.
- **Число одновременных запусков.** По умолчанию два; остальные ждут своей очереди.
- **Объём вывода.** Ограничен примерно мегабайтом: результат нужно печатать, а объёмные данные — складывать в файлы рабочего каталога.
- **Число скриптов и размер кода.** До 200 скриптов на проект и до 256 КБ кода на каждый.
- **Срок хранения журнала.** 30 дней по умолчанию.

Есть и два выключателя: общий выключатель сервера `TEST_APP_SCRIPTS_ENABLED` и выключатель проекта в его настройках. Выключенный скрипт **не становится «зелёным» молча**: попытка запуска попадает в журнал с причиной — «выполнение отключено».

## Честные границы

- **Изолированной среды нет.** Скрипт работает от имени сервера и имеет его доступ к файлам и сети. Это код доверенного человека, который хранится вместе с проектом, поэтому запускать чужие скрипты нельзя. Пределы выше — защита от случайной ошибки, а не изоляция.
- **Только Python.** Других языков продукт не поддерживает — это осознанное ограничение, а не недоделка.
- **Постоянно работающих служб нет.** Каждый запуск — отдельный процесс, который завершается вместе с работой.
- **Скрипт ничего не одобряет.** Даже классификатор может только повысить важность отличия. Одобрение эталона и вердикт по отличиям остаются за человеком.

Дальше: те же скрипты по ключу доступа, для машин и конвейеров непрерывной сборки, — в разделе [Внешний доступ для агентов](/agents/test/docs/external-api)
.

[← Оглавление документации](/agents/test/docs)
