Команды
tapstep test <flow.yaml | dir> [--driver web|android|ios|app[:port]] [-v]tapstep test app.flow.yaml --headed # реальное окно браузераtapstep test app.flow.yaml -c # watch-режим: перезапуск этого флоу при сохраненииtapstep test flows/ --tags smoke --shards 4 # прогон папки: фильтр по тегам, 4 флоу параллельноtapstep live <flow.yaml> [--port 7878] # интерактивный live-просмотр в браузере--driver web|android|ios|app[:port] выбирает цель (app = десктоп-приложение
с тестовым мостом, порт по умолчанию 9223 — см.
Десктоп-приложения). Без флага tapstep определяет цель
сам: appId-URL означает web, иначе — подключённое Android-устройство или
загруженный iOS-симулятор. Флоу с заголовком vscode: идёт на драйвер VS Code,
а флоу с device: none выполняется вообще без устройства.
--browser chrome|chromium|edge|brave|opera|vivaldi|yandex|firefox|managed
или путь к исполняемому файлу браузера выбирает браузер (managed = прибитый
Chromium в ~/.tapstep/browsers). --viewport WxH, --locale en-US
настраивают браузер; --video-scale 1–4 пишет --video в N× от вьюпорта
(чёткий ролик для демо). -e KEY=VAL переопределяет переменные сценария;
--env-file FILE подгружает дополнительные dotenv-файлы поверх автоматически
найденного .env; --env-set NAME гоняет против названного окружения из
блока environments: конфига (иначе берётся его defaultEnvironment) и
подгружает вместе с ним .env.NAME — см. config.yaml.
Остальные флаги test:
--tags a,b/--exclude-tags a,b— фильтр прогона папки поtags:флоу.--shards N— запускать до N флоу папки одновременно.--config <config.yaml>— умолчания рабочей области:flows, теги,ai,report; флаги важнее — см. config.yaml.-c/--continuous,--video,--capture-network— только для одного флоу: перезапуск при сохранении, запись видео рядом с флоу, захват сетевого трафика.--analyze— AI-триаж упавшего флоу (нужен блокai:в конфиге илиTAPSTEP_AI_ENDPOINT/MODEL/KEY).--strict-selectors— валить прогон, если шаг прошёл только потому, что совпала одна из его альтернативor:. Без флага такой шаг зелёный, а прогон пишет⚠ N step(s) passed on an alternative selector.--report json|junit|html|allure,--output <file|dir>— см. Отчёты.- Тюнинг, в мс:
--wait-timeout,--settle-timeout,--settle-stable-for,--poll-interval; повторы:--action-retries,--scroll-attempts.
live тоже принимает --driver, --browser, --headed, --viewport,
--locale и флаги тюнинга.
Инспекция и инструменты
Заголовок раздела «Инспекция и инструменты»tapstep inspect [target] [--measure] [--driver …] [--browser …] # компактный снимок экранаtapstep list-devices # браузеры, устройства Android, симуляторы iOStapstep start-device android|ios [--name <avd|sim>] # поднять эмулятор / симуляторtapstep doctor # проверить внешние инструменты каждого драйвераtapstep privacy install # локальная модель маскирования PII (~945 МБ загрузки)tapstep privacy status # privacy-режим: включён? модель установлена?tapstep validate <flow.yaml | dir> # проверить сценарии разбором и загрузить include, без устройстваtapstep fix-paths [path] [--write] [--all] # переписать пути runFlow с ../ от корня проектаtapstep init [path] [--samples] [--agents] # стартовый сценарий / примеры / настройка агентовtapstep skill status # по каждому агенту: установлен? той же версии, что бинарь?tapstep skill install # скилл агента для Claude Code / Codex / Gemini CLI / Cursor / OpenCodetapstep skill refresh # перезаписать установленные копии версией из этого бинаряtapstep mcp [--driver app:9223] [--browser …] # stdio MCP-сервер для AI-клиентаtapstep appmeta <apk|ipa|app> # метаданные сборки как JSONtapstep bugreport [path] # zip с локальной диагностикой для issuetapstep update [--check] # самообновление до последнего релизаtapstep mcp по умолчанию берёт подключённое устройство, иначе web.
tapstep update после обновления запускает skill refresh, чтобы
установленные скиллы агентов шли за бинарём; skill refresh ничего не
устанавливает заново — для этого есть skill install.
tapstep validate читает сценарий (или целую папку, включая файлы
.helper.yaml) и сообщает то, на чём споткнулся бы test, ещё до подъёма
устройства. Он же предупреждает про ${VAR}, который остаётся незакрытым в
каком-то окружении, и называет, в каком именно, — та самая проверка, что ловит
тест, записанный на одном окружении, до того как его запустят на другом.
Хелперы так не проверяются: их переменные приходят от вызывающего.
Пути include
Заголовок раздела «Пути include»С версии 0.13.12. CLI и десктоп постарше читают путь в runFlow: только от папки
файла, который его пишет, поэтому записанный от корня include во вложенном флоу
там не загрузится — обновите оба, прежде чем запускать fix-paths --write.
Путь в runFlow: ищется сначала в папке файла, который его пишет, затем от
корня проекта (папки ближайшего config.yaml). Записанная от корня —
helpers/login.helper.yaml — та же строка работает во флоу на любой глубине,
поэтому группа шагов, скопированная из одного теста в другой, продолжает
запускаться. Правило одно для всех файлов, которые называет шаг: runScript:,
схема request:, uploadFile:, installApp: и хелперы хуков before:/after:.
validate загружает каждый include оттуда, где лежит файл, и по строкам
сообщает: хелпера по этому пути нет (и какой файл с таким именем нашёлся в
проекте), обязательные параметры не переданы, есть цикл, — и завершается с
ненулевым кодом; хелпер за пределами проекта — предупреждение.
tapstep fix-paths переписывает include с ../ (или ./, или разделителями
\) в форму от корня. По умолчанию он только показывает изменения:
$ tapstep fix-paths flowsflows/checkout/cart/pay.flow.yaml 4 - ../../../helpers/login.helper.yaml 4 + helpers/login.helper.yaml1 path(s) in 1 file(s) would change — run again with --write to apply--write сохраняет файлы; --all переписывает от корня и include, которые
называют хелпер рядом с флоу (login.helper.yaml). Include, который после переписывания нашёл
бы другой файл или лежит вне проекта, остаётся как есть.
Импорт и экспорт
Заголовок раздела «Импорт и экспорт»tapstep import playwright <spec.ts|dir> [-o flows] # вывод codegen -> флоуtapstep export playwright <flow.yaml|dir> [-o playwright] # флоу -> *.spec.tstapstep export extester <flow.yaml|dir> [-o extester] # флоу с vscode: -> *.test.tsКуда попадает экспорт — настройка проекта, а не привычка отдельной команды:
без -o обе пишут в папку, названную в блоке exports:
файла config.yaml, и только в его отсутствие — в playwright/ и extester/
в корне проекта. Десктоп и MCP-инструменты читают ту же настройку; блок
exports:, который не разбирается, останавливает экспорт, а не молча
откатывает его в папку по умолчанию.
Каждый экспортированный файл открывается строкой // tapstep: с именем
сценария, из которого он вышел, и хешами обеих сторон, — так следующий экспорт
понимает, остался ли файл тем, что говорит сценарий, ушёл ли сценарий вперёд и
не правил ли файл кто-то руками.
Импорт читает то, что пишет playwright codegen: по одному флоу на каждый
test(...), локаторы переводятся в селекторы (getByTestId → testId,
getByRole → role + name, .nth() → index, .filter({ hasText }) →
containsDescendants). Всё, что перенести нельзя — циклы, вспомогательные
функции, xpath-локаторы, аргументы, вычисляемые во время выполнения, —
попадает в отчёт с номером строки и записывается во флоу как комментарий
# TODO ровно в том месте, где встретилось. Ничего не выбрасывается молча,
поэтому отчёт и есть список того, что ещё нужно доделать руками.
export playwright пишет браузерную часть флоу. Шаги без эквивалента в
Playwright (вся мобильная часть, AI-проверки) становятся комментариями
// TODO и перечисляются в сводке. ${VAR} превращается в process.env.VAR,
так что сгенерированный спек читает значения так же, как их читал флоу; значение
env, которое само выражение (TITLE: "Order ${Date.now()}"), становится одним
const в начале спека, и его читает каждый шаг — прогон тоже вычислял его один
раз. Каждый элемент ищется через маленький хелпер ui(), который смотрит на
странице и во всех фреймах внутри неё: флоу никогда не говорит, в каком
документе элемент, так что превью в <iframe> не требует frameLocator руками. tapOn
с последующим вводом становится одним fill(), а проверка, уточнённая по
тексту, сохраняет обе половины (expect(locator).toHaveText(…)). before: /
after: флоу — вся разрешённая цепочка, вместе с хуками проекта и testspace —
становятся test.beforeEach / test.afterEach спека; у флоу без хуков блоков
нет. Флоу с заголовком vscode: экспортируется вместо этого как
самостоятельный Electron-спек: он ставит vsix флоу в одноразовый профиль
и запускает установленный VS Code через Electron-лаунчер Playwright — так же,
как это делают собственные smoke-тесты VS Code. vscodeCommand превращается в
название палитры, на которое команда отзывается, а id без известного названия
остаётся // TODO, а не превращается в команду, делающую другое. Палитра
находит команду и по её id, и именно поэтому три команды пресета clean,
которые палитра скрывает, когда нужное состояние уже есть, печатаются как id:
их отсутствие читается как «делать нечего», а в интерфейсе на другом языке
английское название не найдётся никогда. Остальные — названия, так что экспорт
рассчитан на VS Code по-английски; для другого языка поставьте "locale": "en"
в argv.json.
export extester — второй способ уйти с флоу для VS Code: тест
vscode-extension-tester
— Mocha и chai поверх Selenium, запускается через extest. Флоу без заголовка
vscode: он отвергает, а не пишет то, что не сможет выполниться; экспорт папки
проходит мимо таких флоу и говорит, сколько их было. Первый экспорт в папку
кладёт туда ещё и README.md с командами extest под неё (get-vscode,
get-chromedriver, install-vsix, run-tests или setup-and-run одной
командой), с --code_version, который назвал VS Code этой машины, и с
workspace, который раннер должен открыть флагом -r. В самих тестах: одна
константа TIMEOUT — бюджет всех ожиданий файла (пошаговые таймауты флоу
намеренно не переносятся), а элементы ищутся через помощник withWebview(...),
который пробует документ workbench, а затем каждый iframe.webview →
#active-frame по очереди, потому что флоу записывает, что у шага есть
элемент, а не в каком документе он лежит.
--report json|junit|html|allure печатает json/junit/html-отчёт в stdout или
пишет его в --output <file>; allure пишет папку allure-results/ в текущей
директории (или в --output <dir>). Прогон папки с --report даёт один
сводный отчёт.
С --config config.yaml, где есть блок report: (format, output — по
умолчанию html → reports/, относительно папки конфига), каждый прогон без
всяких флагов пишет туда <flow>.<ext>; прогон папки пишет один сводный файл.
--report/--output по-прежнему важнее.
Блок — runFlow в .helper.yaml, repeat или retry — это один шаг, названный
по тому, что он запустил, а его собственные шаги вложены внутрь: у упавшего
хелпера видно, какой именно шаг упал. Верхний уровень по-прежнему считает один
шаг на команду — по нему индексируются отчёты в CI.
Шаг, которому пришлось действовать на неуспокоившейся странице, говорит об этом
в любом формате: в JSON у шага есть "settled": false и "unsettledReason"
(Loading, Network(2), Mutating, Navigating или Timeout), в JUnit —
<property name="unsettled"> у этого теста, в Allure — параметр unsettled, в
HTML — плашка acted while loading в строке. У шага на успокоившемся экране
этих полей нет — см.
как прогон понимает, что страница успокоилась.
Шаг, прошедший только потому, что совпала одна из его альтернатив or:,
говорит об этом так же: в JSON у шага есть объект drifted (used, primary,
alternative), в JUnit — <property name="drifted">, в HTML — плашка
drifted в строке, а итог прогона их считает. Такой прогон всё равно выходит с
кодом 0 — валит его только --strict-selectors.
Коды выхода и артефакты падения
Заголовок раздела «Коды выхода и артефакты падения»0 — все флоу прошли. 1 — флоу выполнились, часть упала. 2 — ошибка
конфигурации или инфраструктуры (плохой флаг, нет устройства, нечитаемый
конфиг): CI отличает красный прогон от сломанного раннера.
При падении tapstep печатает экран на момент ошибки и пишет
<flow-stem>-failure.png — плюс <flow-stem>-failure.network.json, если
записывался сетевой трафик, — в reports/ и печатает путь к файлу:
- внутри проекта (папка ближайшего
config.yamlили--config) — папка отчётов проекта:report.output, если задан, иначеreports/. К имени добавляются папки флоу относительно корня проекта:flows/auth/login.flow.yamlпадает вreports/flows-auth-login.flow-failure.png; - вне проекта —
reports/рядом с файлом флоу.
Никогда не в текущую директорию. Сетевой лог может содержать данные запросов —
держите reports/ в .gitignore; tapstep один раз подскажет, если .gitignore
проекта его не игнорирует (сам файл не правит).
tapstep login [--token tapstep_pat_…] # SSO в браузере; --token сохраняет персональный токенtapstep logouttapstep token create --name <name> [--expires-days N] # персональный токен для CI, показывается один разtapstep token list # ваши токены — id, имя, префикс, последнее использование; без секретаtapstep token revoke <id|name>tapstep login по умолчанию выполняет вход через браузер (SSO); --token
вместо этого сохраняет токен, а TAPSTEP_TOKEN в окружении считается входом.
Токен даёт tapstep token create: он один раз открывает браузер и печатает в
stdout только токен (… | gh secret set TAPSTEP_TOKEN работает); list и
revoke входят через браузер так же. Токен tapstep_pat_… сверяется с API раз
в сутки и кэшируется в ~/.tapstep/token-check.json: отозванный или
неизвестный останавливает команду, а недоступный API прогон никогда не
останавливает (предупреждение — только если токен ещё ни разу не проверялся на
этой машине). Любое другое значение TAPSTEP_TOKEN работает с
предупреждением до 0.15 — см. CI / GitHub Actions.
Все команды, кроме login, logout, token, doctor, bugreport,
privacy, update, schema, validate, fix-paths, skill status и
skill refresh, требуют предварительного входа; после входа всё
работает офлайн.