Skip to content
Back to skills

Testpilot 1c

ASecurity

UI-тестирование 1С через MCP-сервер 1c-testpilot (ROCTUP). Используй когда нужно управлять тестовым клиентом 1С напрямую — открывать формы, заполнять реквизиты, работать с табличными частями, сравнивать состояние формы до и после.

  • 14 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 29, 2026
ai-agentspythongotestinggitapi

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 29, 2026

npx -y skills add afk-yar/1c-testpilot-agent-kit --skill testpilot-1c --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Testpilot 1c?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Testpilot 1c
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/afk-yar-testpilot-1c/badge)](https://www.skillsdirectory.com/skills/afk-yar-testpilot-1c)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: testpilot-1c
description: UI-тестирование 1С через MCP-сервер 1c-testpilot (ROCTUP). Используй когда нужно управлять тестовым клиентом 1С напрямую — открывать формы, заполнять реквизиты, работать с табличными частями, сравнивать состояние формы до и после.
argument-hint: "сценарий на естественном языке"
---

# /testpilot-1c — UI-тестирование через 1c-testpilot

Сервер ходит напрямую в `/TESTCLIENT` по протоколу тестового клиента. Базы-менеджера нет,
BSL-сценарии писать не надо, один шаг — один вызов инструмента.

Своего скилла у автора нет, вся справка лежит в описаниях инструментов и в `docs/TOOLS.md`.
Этот файл — только то, чего в описаниях нет или что там сформулировано неоднозначно.

## Окружение

Все пути и настройки конкретной машины собраны здесь; ниже по тексту — только имена.
Заполните таблицу своими значениями.

| Что | Где |
|---|---|
| Сервер testpilot (клон ROCTUP/1c-testpilot) | `<каталог testpilot>` — проверено на 1.7.1 |
| Точные сигнатуры действий | `docs/TOOLS.md` сервера |
| Python API и pytest | `docs/PYTHON_TESTING.md` сервера |
| Типы значений для обработки Testpilot | `onec/Testpilot/README.md` сервера, раздел «Типы значений» |
| Профили запуска | `profiles.yaml` сервера (образец — `profiles.example.yaml`) |
| Порты | свой порт на каждое назначение: агенты, скрипты, pytest |
| Образцы повторяемых прогонов | ваши скрипты и тесты на Python API |
| Снятые грабли 5, 6, 10, 12, 13 | `история-граблей.md` рядом с этим файлом |

## Инструменты

Схемы отложенные, тянуть через `ToolSearch` запросом
`select:mcp__1c-testpilot__tc_session,...`. Все десять групп разом — около 21 тыс.
токенов, поэтому грузи только нужные. Базовый набор на обычный сценарий:
`tc_session`, `tc_find`, `tc_window`, `tc_field`, `tc_table`.

## Канонический поток

1. `tc_session` action=launch_client, profile=`<проект>` — профили в `profiles.yaml` сервера.
2. `tc_find` action=wait_for_object_displayed, cls=`ManagedForm` — дождаться интерфейса.
3. `tc_window` action=execute_command, command=`e1cib/list/<Тип>.<Имя>` — открыть список.
4. `tc_find` action=find_object / find_objects — получить ref нужных элементов.
5. `tc_field` / `tc_table` — действия.
6. `tc_window` action=close_window (можно с `ref` окна). Если на форме вопрос о сохранении,
   ответ `window_not_closed` — тогда action=answer_dialog.
7. `tc_session` action=stop_client. С 1.7.0 сначала штатный выход (15 с), потом
   принудительный. На ERP вопрос «Exit the app?» сервер не распознает — в ответе
   `shutdown: forced`, `shutdown_reason: shutdown_confirmation_required`; это норма.

## Режим наблюдения

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

Звать `launch_client` с обычным профилем проекта и `desktop='default'`.

Довести форму до нужного состояния и ОСТАНОВИТЬСЯ: не закрывать её и не звать
`stop_client`, пока пользователь не скажет.

Его ручные клики соединению не мешают: вызовы проходят без переподключения, ref
формы жив, свежий `get_context` показывает сделанные руками изменения. Устаревает
только ранее снятый снимок. Простой соединение не рвёт (с 1.7.0 сервер шлёт кадр
поддержания связи каждые 5 с).

Клиент, поднятый с `desktop='default'`, переживает конец сессии: он не в job-объекте,
в отличие от изолированного. Гасить его потом адресно по PID.

## Грабли

Каждая проверена на реальном прогоне, не выведена из документации. Номера с пропусками:
снятые грабли 5, 6, 10, 12, 13 лежат в `история-граблей.md`, а на номера ссылаются протоколы
прогонов. Грабли 1-4, 8, 11, 14 перепроверены на 1.7.1 2026-09-29 (стенд 1С:ERP 2.5), 7 и 9 — нет.

1. **Сразу после `launch_client` активного окна нет.** Любой вызов `tc_window` вернет
   `no active window`. Ждать `tc_find` action=wait_for_object_displayed, cls=`ManagedForm`.
   Класса `ClientApplicationWindow` на сервере НЕТ: ожидание его съедает весь таймаут
   и возвращает `class_known: false`.
2. **Схема группы шире реальной сигнатуры действия.** Групповая схема принимает все
   параметры группы, а конкретное действие отвергает лишние Python-ошибкой
   `got an unexpected keyword argument`. Известные случаи: `read_rows` не принимает
   `columns`, `choose_row` не принимает `row_column`/`row_value`/`column`/`conditions`
   (сверено по коду 1.7.0). Точная сигнатура — грепом по `docs/TOOLS.md` сервера.

   Общее правило: действия с таблицей работают по ТЕКУЩЕЙ строке, условие отбора
   им передать нельзя. Строку сначала находят (`find_rows`, курсор не двигает),
   потом встают на неё (`goto_row`), потом действуют (`choose_row` берёт только `ref`).
3. **В `set_fields` кладется ref поля ввода, а не ref формы** — иначе
   `unsupported_element_type`. Сам адрес идет только внутри `entries`,
   параметра `ref` верхнего уровня у действия нет.
4. **`goto_row` ищет вниз от текущей строки.** Строка выше курсора дает `found: false`
   без ошибки. Для нее `direction`=`up`. В динамическом списке та же `found: false`
   приходит на строку за пределами отрисованного окна, хотя `find_rows` ее находит;
   лечится `goto_first_row` перед поиском.
7. **Отказ «read-only or its editability is unknown» склеивает два разных случая.**
   Понять, чинить состояние формы или колонка нередактируема в принципе, по ответу
   нельзя. Смотреть `ReadOnly` в `Form.xml` объекта.
8. **Ref живут в рамках окна.** После открытия новой формы искать элементы заново.
9. **Неожиданное окно проверять чтением формы.** Окно ошибки и окно предупреждения
   из кода по ответу действия неразличимы (у обоих `title: 1С:Предприятие`, пустой `url`),
   различает только `form_name`: `ErrorWindow` против `MessageBox`.
11. **Профиль годится только для запуска клиента.** `connect` с `profile` отвергается
    как `profile_action_mismatch`: профиль описывает, как поднять клиент, а не как
    подключиться к живому. Состояние выясняет `list_connections` — пусто значит
    `launch_client`, есть подключение значит `connect` по порту и версии.
14. **Любую форму можно открыть по имени.** `e1cib/data/<Тип>.<Имя>.Форма.<ИмяФормы>`
    без `?ref` открывает именно эту форму объекта или записи регистра, для новой формы
    объекта — в режиме создания. Общие формы и формы обработок —
    `e1cib/app/ОбщаяФорма.<Имя>` и `e1cib/app/Обработка.<Имя>.Форма.<ИмяФормы>`.
    Проверено на 182 формах ERP 2026-09-23. Сверять `form_name` ответа с ожидаемым.
15. **`read_rows` на таблице неактивной вкладки вешает клиент.** На 1.7.1 в списке
    номенклатуры ERP таблица `СписокКачества` (страница `СтраницаТоварыДругогоКачества`)
    вернула одну пустую строку и `selection_cleanup_failed` через 30 с, дальше
    «connection desynchronised» на всех вызовах. `disconnect` + `connect` НЕ лечит: после
    переподключения `get_active_window` снова висит 30 с. Помогает только перезапуск
    клиента. Воспроизведено на 1.7.0 и 1.7.1, 2026-09-29. Виснет шаг снятия выделения:
    на 8.3 это `goto_row` без условия, и отдельный такой вызов виснет так же. Страница —
    неактивная вкладка панели навигации `ВариантыНавигации`: код формы делает ее текущей
    только в режиме «по товарам другого качества» (`ПодборТоваровСервер`). В сценариях не
    встречается — наткнулись, когда скрипт выбрал не ту таблицу. Issue https://github.com/ROCTUP/1c-testpilot/issues/17
    Таблицу выбирать по имени из `find_objects` cls=`Table`: у списка ERP их шесть, основная —
    `СписокСтандартныйПоискНоменклатура`, а не `Список`.

## Повторяемый прогон: Python API и pytest

Агент проходит сценарий через MCP один раз, потом пишет скрипт или pytest-тест, который
гоняется без модели. Python API (`from testpilot import Client`) работает в процессе
скрипта и сам ходит в `/TESTCLIENT` по TCP, MCP-сервер не нужен. Документация и образцы —
в разделе «Окружение».

- **pytest — когда тестов несколько и у каждого свои проверки.** Fixture `testpilot`
  поднимает клиент на каждый тест, это около 11 с. Прогон одного действия по списку
  (формы) — простым скриптом с одним клиентом.
- **pytest стоит в `.venv` testpilot** (extra `[test]`). `TC1C_PROFILES_FILE` задавать
  переменной окружения до запуска: плагин читает ее при загрузке.
- **Проверка данных — обработка Testpilot в профиле (`code_epf`), отдельным профилем.**
  На 1.7.0 ее окно открывалось активным и ломало проверку стартовой страницы. На 1.7.1
  после запуска активна стартовая страница (один прогон 2026-09-29), но запуск дольше
  примерно на 11 с, поэтому в общие профили ее по-прежнему не добавлять.
- **В `execute_code` всегда запрещен идентификатор `Выполнить`**, в том числе
  `Запрос.Выполнить()` — `forbidden_code`. Запросы — только `execute_query`. С 1.7.1
  так же запрещен запуск программ (`ЗапуститьПриложение`, `КомандаСистемы`).
- **Дата параметром** — `{'$type': 'date', 'value': '2026-09-23T00:00:00'}`. Ссылку из
  строки ответа запроса можно передать параметром в следующий запрос как есть.
  Типы значений — README обработки Testpilot (см. «Окружение»).
- **`click` по «Провести» возвращается до конца проведения.** Заголовок окна еще
  «(создание) *»; ждать номер в заголовке через `wait_until`.
- **Порты по назначению:** агенты — порт профиля, дымовой скрипт и pytest — свои
  (раскладка — в «Окружении»). Иначе второй `launch_client` падает на занятом порту.

## Экономия контекста

- `tc_form` action=get_context на форме ERP возвращает 200+ элементов и стоит около
  10 тыс. токенов, больше всех загруженных схем вместе. Звать один раз на разведку,
  дальше искать точечно через `tc_find` action=find_objects по имени или классу.
- Регрессию гонять через снимки `tc_form`: сравнение крупной формы дает несколько
  строк изменений вместо полного дерева, а само дерево остается на сервере.
- Заполнять пачками: `set_fields` берет до 100 полей за вызов, `add_rows` — строку
  со всеми ячейками сразу.

## Проверяемость

Мутирующие действия возвращают `value_before` / `value_after` и признак `verified`,
поэтому отдельное чтение для подтверждения обычно не нужно. Сверка чисел идет как
`numeric_equivalent`: введенное `100` и показанное `100,00` расхождением не считаются.

`ok: true` означает лишь, что клиент принял команду. `close_window` с 1.7.1 проверяет
закрытие сам: форма с изменениями дает `window_not_closed`, и тогда ОБЯЗАТЕЛЬНО звать
`answer_dialog` — он возвращает текст вопроса и данный ответ. Пропуск этого шага оставляет
висеть модальный диалог, а `stop_client` потом просто убивает клиента, маскируя недоделанный шаг.

Скриншот (`tc_app` action=get_screenshot) — вспомогательный канал и приходит неполным
(`capture_complete: false`, всплывающие окна не попадают). Решения принимать по дереву.

## Ошибки прикладного кода

Поймал окно ошибки — зови `tc_app` action=get_current_error: в самом окне места падения нет.
С 1.7.1 он отвечает и на вложенной ошибке обработчика объекта, причина — в `details`.
- `error` заполнен — исключение в коде, там же модуль, строка и стек вызовов.
- `error` пуст — ошибка компиляции, модуль, строка и позиция лежат в элементе `ErrorInfo` окна.

## Известные ограничения окружения

- Изолированный рабочий стол (`desktop: isolated` в профиле) не мешает снимкам,
  но у процесса пустой `MainWindowTitle` — искать его по командной строке, а не по заголовку.
- Клиент, поднятый не через `launch_client`, нельзя остановить через `stop_client`
  (ответ `no client was launched through tc_launch_client`). К такому клиенту можно
  подключиться через action=connect с указанием `port` и `version`, а гасить его
  адресно по PID.

Files in this skill

  • SKILL.md17.9 KB
  • история-граблей.md1.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…