Команды флоу
Каждый шаг флоу — одна команда: - name (голая), - name: значение (скаляр) или - name: с мапой ключей. Команды с селектором принимают голую строку (точный видимый текст) или объект-селектор — см. Файл флоу и селекторы. Длительности — в миллисекундах. ${VAR} подставляется в строковые значения — см. Переменные.
| Команда | Кратко | web | android | ios | vscode |
|---|---|---|---|---|---|
| Приложение и навигация | |||||
launchApp |
Запустить приложение (или открыть URL) | ✓ | ✓ | ✓ | ✓ |
stopApp |
Остановить приложение | ✓ | ✓ | ✓ | ✓ |
installApp |
Установить сборку (apk / ipa) | — | ✓ | ✓ | — |
openLink |
Открыть URL / deep link | ✓ | ✓ | ✓ | — |
clearState |
Стереть данные приложения | ✓ | ✓ | ✓ | ✓ |
grantPermissions |
Выдать runtime-разрешения | — | ✓ | ✓ | — |
setPermissions |
Разрешить / запретить отдельные разрешения | — | ✓ | ✓ | — |
back |
Назад | ✓ | ✓ | — | — |
vscodeCommand |
Выполнить команду VS Code | — | — | — | ✓ |
| Тапы и жесты | |||||
tapOn |
Тап по элементу или точке | ✓ | ✓ | ✓ | ✓ |
longPressOn |
Долгое нажатие по элементу или точке | ✓ | ✓ | ✓ | ✓ |
doubleTapOn |
Двойной тап по элементу или точке | ✓ | ✓ | ✓ | ✓ |
scroll |
Проскроллить экран | ✓ | ✓ | ✓ | ✓ |
swipe |
Свайп по направлению или между точками | ✓ | ✓ | ✓ | ✓ |
scrollUntilVisible |
Скроллить, пока элемент не появится | ✓ | ✓ | ✓ | ✓ |
dragAndDrop |
Перетащить один элемент на другой | ✓ | ✓ | ✓ | ✓ |
check |
Включить чекбокс или переключатель | ✓ | ✓ | ✓ | ✓ |
uncheck |
Выключить чекбокс или переключатель | ✓ | ✓ | ✓ | ✓ |
hover |
Навести указатель на элемент | ✓ | — | — | ✓ |
| Ввод текста и клавиши | |||||
inputText |
Ввести текст в активное поле | ✓ | ✓ | ✓ | ✓ |
inputRandomEmail |
Ввести случайный e-mail | ✓ | ✓ | ✓ | ✓ |
inputRandomPersonName |
Ввести случайное имя | ✓ | ✓ | ✓ | ✓ |
inputRandomNumber |
Ввести случайное число | ✓ | ✓ | ✓ | ✓ |
inputRandomText |
Ввести случайный текст | ✓ | ✓ | ✓ | ✓ |
inputRandomCityName |
Ввести случайный город | ✓ | ✓ | ✓ | ✓ |
inputRandomCountryName |
Ввести случайную страну | ✓ | ✓ | ✓ | ✓ |
inputRandomColorName |
Ввести случайный цвет | ✓ | ✓ | ✓ | ✓ |
clearText |
Очистить активное поле | ✓ | ✓ | ✓ | ✓ |
eraseText |
Стереть последние N символов | ✓ | ✓ | ✓ | ✓ |
pressKey |
Нажать клавишу или комбинацию | ✓ | ✓ | ✓ | ✓ |
hideKeyboard |
Скрыть экранную клавиатуру | ✓ | ✓ | ✓ | — |
setClipboard |
Записать в буфер флоу | ✓ | ✓ | ✓ | ✓ |
pasteText |
Вставить регистр в поле | ✓ | ✓ | ✓ | ✓ |
| Формы и страница (web) | |||||
selectOption |
Выбрать пункт в | ✓ | — | — | ✓ |
uploadFile |
Прикрепить файлы к file input | ✓ | — | — | ✓ |
assertUrl |
Проверить адрес страницы | ✓ | — | — | ✓ |
| Проверки и ожидания | |||||
assertVisible |
Проверить, что элемент виден | ✓ | ✓ | ✓ | ✓ |
assertNotVisible |
Проверить, что элемента нет | ✓ | ✓ | ✓ | ✓ |
waitForVisible |
Дождаться появления элемента | ✓ | ✓ | ✓ | ✓ |
extendedWaitUntil |
Ждать появления / исчезновения | ✓ | ✓ | ✓ | ✓ |
waitForAnimationToEnd |
Дождаться, пока экран успокоится | ✓ | ✓ | ✓ | ✓ |
assertTrue |
Проверка значений или JS-выражения | ✓ | ✓ | ✓ | ✓ |
copyText |
Скопировать текст элемента в переменную | ✓ | ✓ | ✓ | ✓ |
assertFile |
Проверить файл в workspace | — | — | — | ✓ |
assertScreenshot |
Визуальная проверка по эталону | ✓ | ✓ | ✓ | ✓ |
| Скриншоты и видео | |||||
takeScreenshot |
Сохранить скриншот | ✓ | ✓ | ✓ | ✓ |
startRecording |
Начать запись экрана | ✓ | ✓ | ✓ | ✓ |
stopRecording |
Остановить запись и сохранить видео | ✓ | ✓ | ✓ | ✓ |
| Состояние устройства | |||||
setLocation |
Подменить GPS-локацию | ✓ | ✓ | ✓ | — |
travel |
Проехать по GPS-точкам | ✓ | ✓ | ✓ | — |
setOrientation |
Повернуть устройство | ✓ | ✓ | ✓ | — |
setAirplaneMode |
Включить / выключить авиарежим | — | ✓ | — | — |
toggleAirplaneMode |
Переключить авиарежим | — | ✓ | — | — |
addMedia |
Добавить фото / видео в галерею | — | ✓ | ✓ | — |
clearKeychain |
Очистить keychain iOS | — | — | ✓ | — |
| Управление потоком | |||||
runFlow |
Выполнить хелпер или вложенный блок | ✓ | ✓ | ✓ | ✓ |
repeat |
Повторить блок | ✓ | ✓ | ✓ | ✓ |
retry |
Повторить блок при ошибке | ✓ | ✓ | ✓ | ✓ |
| AI | |||||
assertWithAI |
AI-проверка экрана | ✓ | ✓ | ✓ | ✓ |
assertNoDefectsWithAI |
AI-проверка на визуальные дефекты | ✓ | ✓ | ✓ | ✓ |
extractTextWithAI |
AI-извлечение текста в переменную | ✓ | ✓ | ✓ | ✓ |
| Скрипты | |||||
evalScript |
Выполнить inline JavaScript | ✓ | ✓ | ✓ | ✓ |
runScript |
Выполнить JS-файл | ✓ | ✓ | ✓ | ✓ |
| API и данные | |||||
request |
HTTP-запрос с extract / assert | ✓ | ✓ | ✓ | ✓ |
sql |
SQL-запрос с extract / assert | ✓ | ✓ | ✓ | ✓ |
Колонки покрытия — из самого движка: tapstep schema публикует их для каждой команды, а эта таблица их печатает. Цели «десктоп-приложение» (--driver app) отдельной колонки не имеют — они используют тот же обход DOM, но без большинства опциональных возможностей, см. Тестирование десктоп-приложений.
Приложение и навигация
Заголовок раздела «Приложение и навигация»launchApp
Заголовок раздела «launchApp»Запускает тестируемое приложение — на web открывает URL. Строковая форма принимает app id / URL; в форме-мапе есть clearState (стереть данные перед запуском), stopApp (гарантированный холодный старт), permissions (мапа имя: allow|deny|unset, mobile) и arguments (аргументы запуска, mobile).
Ключи: appId — строка · обязательный; clearState — bool; stopApp — bool; permissions — мапа; arguments — мапа.
commands: - launchApp: com.example.app - launchApp: appId: com.example.app clearState: true permissions: notifications: allowstopApp
Заголовок раздела «stopApp»Завершает приложение: голая форма - stopApp берёт appId флоу, - stopApp: <appId> останавливает другое. Алиас — killApp.
Алиасы: killApp
Ключи: appId — строка.
commands: - stopApp - stopApp: com.example.otherinstallApp
Заголовок раздела «installApp»Устанавливает сборку по пути. grant: true сразу выдаёт runtime-разрешения.
Платформы: android, ios
Ключи: path — строка · обязательный; grant — bool.
commands: - installApp: build/app-debug.apk - installApp: path: build/app.ipa grant: trueopenLink
Заголовок раздела «openLink»Открывает URL или deep link: навигация в браузере на web, am start -a VIEW на Android, simctl openurl на iOS. В браузере относительная ссылка — /login, ./next, ?page=2 — читается относительно уже открытой страницы или URL-appId; если нет ни того ни другого, шаг падает сразу, а не ждёт загрузку до таймаута.
Платформы: web, android, ios
Ключи: url — строка · обязательный.
commands: - openLink: https://example.com/reset?token=${TOKEN}clearState
Заголовок раздела «clearState»Сбрасывает сохранённое состояние: localStorage и cookies на web, pm clear на Android, контейнер данных приложения в симуляторе на iOS (только симулятор). Голая форма — для appId флоу; можно передать другой app id.
Ключи: appId — строка.
commands: - clearState - clearState: com.example.othergrantPermissions
Заголовок раздела «grantPermissions»Выдаёт типовые runtime-разрешения (simctl privacy на iOS, pm grant на Android). Голая форма — для appId флоу. На web не поддерживается.
Платформы: android, ios
Ключи: appId — строка.
commands: - grantPermissionssetPermissions
Заголовок раздела «setPermissions»Задаёт разрешения по одному: мапа имя: allow|deny|unset (all — все сразу), опционально под permissions: рядом с appId. Имена: camera, location, microphone, notifications, photos, contacts, calendar, bluetooth, motion, medialibrary, phone, reminders, siri, sms, storage.
Платформы: android, ios
Ключи: appId — строка; permissions — мапа.
commands: - setPermissions: camera: allow location: deny - setPermissions: appId: com.example.other permissions: all: unsetИстория назад в браузере на web, аппаратная кнопка Back на Android. На iOS системного «назад» нет — шаг ничего не делает.
Платформы: web, android
commands: - backvscodeCommand
Заголовок раздела «vscodeCommand»Только для флоу VS Code. id — голый workbench.action.closeAllEditors или { id, args } — выполняется через вспомогательное расширение, которое драйвер ставит сам и которое отвечает, когда команда завершилась; { title: … } вместо этого набирает название в палитре команд и считается выполненным, когда палитра закрылась. Голая строка читается как id, если выглядит как id (через точки, без пробелов), иначе — как название в палитре. args требует id: палитра не принимает аргументов, и просьба совместить их — ошибка, а не молчаливая потеря; так же и id вместе с title, и любой посторонний ключ в мапе. Работает и в before: / after:; before: clean — это шесть таких шагов.
Платформы: vscode
Ключи: id — строка; title — строка; args — список строк.
Взаимоисключающие: одно из id, title.
commands: - vscodeCommand: workbench.action.closeAllEditors - vscodeCommand: title: "My Ext: Generate Config" - vscodeCommand: id: workbench.action.openSettings args: ["editor.fontSize"]Тапы и жесты
Заголовок раздела «Тапы и жесты»Тапает первое совпадение селектора; элемент за экраном сначала доскролливается. { point: "x, y" } тапает по координатам (пиксели или %). repeat — N тапов с паузой delay мс (по умолчанию 100). timeout (мс, по умолчанию 5000) меняет ожидание элемента только для этого тапа.
Ключи: selector — селектор; repeat — целое; delay — мс; timeout — мс; point — точка "x, y".
commands: - tapOn: "Log in" - tapOn: id: submit - tapOn: point: "50%, 90%" - tapOn: text: "+" repeat: 3 delay: 200 - tapOn: text: "Continue" timeout: 30000longPressOn
Заголовок раздела «longPressOn»Нажимает и держит 600 мс — селектор или { point: "x, y" }.
Ключи: selector — селектор; point — точка "x, y".
commands: - longPressOn: "Message" - longPressOn: point: "200, 400"doubleTapOn
Заголовок раздела «doubleTapOn»Два быстрых тапа по селектору или { point: "x, y" }.
Ключи: selector — селектор; point — точка "x, y".
commands: - doubleTapOn: "Photo"Скроллит на экран up или down (голая форма - scroll = вниз). Горизонталь — через swipe: left|right. within — это якорь, а не то, что двигается: назовите то, что видно внутри контейнера (заголовок, строку, колонку вокруг списка), и прокрутится то, что скроллится под ним, а не окно.
Ключи: direction — enum (up | down); within — селектор.
commands: - scroll - scroll: upswipe: up|down|left|right или { start, end } — точки "x, y" в пикселях или % экрана.
Ключи: direction — enum (up | down | left | right); start — точка "x, y"; end — точка "x, y".
Взаимоисключающие: direction не вместе с start, end.
commands: - swipe: left - swipe: start: "50%, 80%" end: "50%, 20%"scrollUntilVisible
Заголовок раздела «scrollUntilVisible»Скроллит, пока селектор не станет видимым. В форме-мапе: direction (up|down|left|right, по умолчанию вниз), timeout мс, speed 0–100, centerElement: true — закончить с элементом по центру. Сдаётся после --scroll-attempts свайпов (по умолчанию 5). within — тот же якорь, что и у scroll. Если элемент уже в странице, а прячет его бокс со своим скроллером (или окошко, в котором рисуется webview), этот бокс просят показать элемент вместо свайпов по экрану; саму страницу всегда крутят по экрану, а бокс с overflow: hidden не двигают вовсе.
Ключи: selector — селектор · обязательный; direction — enum (up | down | left | right); timeout — мс; speed — целое; centerElement — bool; within — селектор.
commands: - scrollUntilVisible: "Terms of service" - scrollUntilVisible: id: footer direction: down centerElement: truedragAndDrop
Заголовок раздела «dragAndDrop»Находит оба элемента и тянет от центра к центру. duration (мс, по умолчанию 600) достаточно медленный, чтобы у цели сработало состояние hover — именно его ждёт большинство реализаций drag-and-drop. В браузере один шаг годится для обоих видов страниц: список, следящий за указателем, получает движения, а доска на HTML5 drag-and-drop — свои dragstart … drop.
Ключи: from — селектор · обязательный; to — селектор · обязательный; duration — мс; path — pointList.
commands: - dragAndDrop: from: "Card" to: { id: done-column }Сначала читает состояние checked и тапает, только если он ещё не включён, затем проверяет, что тап сработал — отключённый или перекрытый контрол валит шаг, а не проходит молча. Безопасно запускать повторно.
Ключи: selector — селектор · обязательный.
commands: - check: "Remember me"uncheck
Заголовок раздела «uncheck»Зеркало check: тапает, только если элемент включён, затем проверяет, что он выключился.
Ключи: selector — селектор · обязательный.
commands: - uncheck: { id: newsletter }Двигает указатель без нажатия — для меню, тултипов и контролов, появляющихся только под курсором: у сенсорного экрана нет наведения.
Платформы: web, vscode
Ключи: selector — селектор · обязательный.
commands: - hover: "Account" - assertVisible: "Sign out"Ввод текста и клавиши
Заголовок раздела «Ввод текста и клавиши»inputText
Заголовок раздела «inputText»Печатает текст в поле, у которого сейчас фокус. ${VAR} подставляется заранее.
Ключи: text — строка · обязательный.
commands: - tapOn: "Email" - inputText: "${EMAIL}"inputRandomEmail
Заголовок раздела «inputRandomEmail»Печатает сгенерированный e-mail в активное поле.
Ключи: length — целое.
commands: - inputRandomEmailinputRandomPersonName
Заголовок раздела «inputRandomPersonName»Печатает сгенерированные имя и фамилию.
Ключи: length — целое.
commands: - inputRandomPersonNameinputRandomNumber
Заголовок раздела «inputRandomNumber»Печатает случайное число из length цифр (по умолчанию 8) — голая форма, : N или { length: N }.
Ключи: length — целое.
commands: - inputRandomNumber: 6inputRandomText
Заголовок раздела «inputRandomText»Печатает случайные буквы; length символов (по умолчанию 8) — голая форма, : N или { length: N }.
Ключи: length — целое.
commands: - inputRandomText: length: 12inputRandomCityName
Заголовок раздела «inputRandomCityName»Печатает название города из встроенного списка.
Ключи: length — целое.
commands: - inputRandomCityNameinputRandomCountryName
Заголовок раздела «inputRandomCountryName»Печатает название страны из встроенного списка.
Ключи: length — целое.
commands: - inputRandomCountryNameinputRandomColorName
Заголовок раздела «inputRandomColorName»Печатает название цвета из встроенного списка.
Ключи: length — целое.
commands: - inputRandomColorNameclearText
Заголовок раздела «clearText»Очищает поле с фокусом.
commands: - tapOn: "Search" - clearTexteraseText
Заголовок раздела «eraseText»- eraseText: N удаляет N символов перед курсором; голая форма - eraseText очищает всё поле.
Ключи: count — целое.
commands: - eraseText: 3pressKey
Заголовок раздела «pressKey»Имена клавиш перечислены ниже, у ключа самого шага, и у каждого — экраны, которые его посылают: телефон посылает все, симулятор iOS принимает те четыре, что понимает текстовое поле. Регистр не важен. Комбинации вроде cmd+shift+p (модификаторы ctrl/control, alt/option, shift, cmd/meta/win/super) — клавиатурные, поэтому работают на web и в VS Code.
Ключи: key — enum (enter | home (android) | back (web, android) | backspace | tab | escape | arrow up (web, android, vscode) | arrow down (web, android, vscode) | arrow left (web, android, vscode) | arrow right (web, android, vscode) | volume up (android) | volume down (android) | lock (android) | power (android)) · обязательный.
commands: - pressKey: enter - pressKey: cmd+shift+phideKeyboard
Заголовок раздела «hideKeyboard»Убирает программную клавиатуру (blur на web, best-effort на iOS).
Платформы: web, android, ios
commands: - hideKeyboardsetClipboard
Заголовок раздела «setClipboard»Кладёт текст в регистр копирования флоу — тот же, что заполняет copyText и читает ${copiedText}. Это регистр флоу, а не системный буфер обмена.
Ключи: text — строка · обязательный.
commands: - setClipboard: "hello" - pasteTextpasteText
Заголовок раздела «pasteText»Печатает содержимое регистра (copyText / setClipboard, иначе переменную copiedText) в активное поле.
commands: - copyText: "Order #" - tapOn: "Search" - pasteTextФормы и страница (web)
Заголовок раздела «Формы и страница (web)»selectOption
Заголовок раздела «selectOption»Выбирает пункт по видимому тексту (option), по значению (optionValue) или по позиции (optionIndex) — ровно одно из трёх. Шлёт input и change, чтобы фреймворк увидел изменение.
Платформы: web, vscode
Ключи: selector — селектор · обязательный; option — строка; optionValue — строка; optionIndex — целое.
Взаимоисключающие: одно из option, optionValue, optionIndex.
commands: - selectOption: id: country option: "Germany"uploadFile
Заголовок раздела «uploadFile»Диалог выбора файла — это интерфейс браузера, по нему нельзя кликнуть, поэтому файлы передаются в input напрямую. files принимает путь или список путей; относительный ищется рядом с файлом флоу, затем в рабочем каталоге, а путь, за которым нет файла, валит шаг.
Платформы: web, vscode
Ключи: selector — селектор · обязательный; files — список строк · обязательный.
commands: - uploadFile: id: avatar files: fixtures/face.pngassertUrl
Заголовок раздела «assertUrl»Голая форма сравнивает точно; в форме-мапе — одно из equals, contains или regex, плюс timeout (мс). Опрашивает до совпадения, чтобы клик, ведущий на другую страницу, успел отработать.
Платформы: web, vscode
Ключи: equals — строка; contains — строка; regex — строка; timeout — мс.
Взаимоисключающие: одно из equals, contains, regex.
commands: - assertUrl: { contains: "/checkout" }Проверки и ожидания
Заголовок раздела «Проверки и ожидания»Как прогон понимает, что страница успокоилась
Заголовок раздела «Как прогон понимает, что страница успокоилась»Движок ждёт покоя перед каждой командой, поэтому явные ожидания в большинстве
флоу не нужны. На web страница считается успокоившейся, когда одновременно тихи
четыре сигнала — документ дозагрузился, нет запросов в полёте (потоки, которые
открыты по своей природе, и всё старше 5 с не считаются), DOM не менялся 150 мс
и адрес не менялся 150 мс — и два чтения экрана совпали, с допуском до 2 px,
чтобы хвост анимации не принимался за движение. На mobile и native первые три
сигнала заменяет собственный признак покоя платформы. Ожидание ограничено
--settle-timeout (2000 мс); свой timeout: у шага поднимает этот предел для
этого шага. Экран, дерево которого читается дольше этого предела, всё равно
читается дважды — предел растягивается на стоимость самих чтений, поэтому
медленная страница остаётся медленной, а не «не успокоившейся».
Прогон, который не дождался покоя, всё равно идёт дальше — но говорит об этом.
assertNotVisible, waitForNotVisible и when: notVisible проходят только на
успокоившемся экране: элемент, которого нет на ещё рисующейся странице, не исчез
— он не появился, поэтому они падают с причиной, а не проходят по недорисованному
экрану. Остальные (tapOn, assertVisible, inputText, …) действуют по
истечении срока, и у шага появляется пометка acted on a page that had not settled (Network(2)), а в отчёте — settled: false и unsettledReason. Причины:
Loading, Network(n), Mutating, Navigating и Timeout.
assertVisible
Заголовок раздела «assertVisible»Ждёт до timeout мс (по умолчанию 5000, --wait-timeout), пока селектор не станет видимым, иначе шаг падает.
Ключи: selector — селектор · обязательный; timeout — мс.
commands: - assertVisible: "Welcome" - assertVisible: id: toast timeout: 10000assertNotVisible
Заголовок раздела «assertNotVisible»Опрашивает, пока селектор не исчезнет на успокоившемся экране (до timeout мс, по умолчанию 5000); падает, если он всё ещё виден, и падает с причиной, если страница так и не успокоилась — отсутствие элемента на ещё рисующейся странице не доказывает, что он исчез.
Ключи: selector — селектор · обязательный; timeout — мс.
commands: - assertNotVisible: "Loading…"waitForVisible
Заголовок раздела «waitForVisible»То же, что assertVisible; читается лучше там, где шаг — ожидание, а не проверка.
Ключи: selector — селектор · обязательный; timeout — мс.
commands: - waitForVisible: text: "Dashboard" timeout: 15000extendedWaitUntil
Заголовок раздела «extendedWaitUntil»Форма-алиас: { visible: <селектор> } или { notVisible: <селектор> } плюс timeout мс.
Ключи: visible — селектор; notVisible — селектор; timeout — мс.
commands: - extendedWaitUntil: notVisible: "Spinner" timeout: 20000waitForAnimationToEnd
Заголовок раздела «waitForAnimationToEnd»Ждёт, пока экран перестанет меняться; timeout мс ограничивает ожидание (по умолчанию --settle-timeout, 2000).
Ключи: timeout — мс.
commands: - waitForAnimationToEnd - waitForAnimationToEnd: timeout: 5000assertTrue
Заголовок раздела «assertTrue»{ equals: [a, b] } / { contains: [где, что] } над строками после подстановки ${}, или голая строка — JavaScript в скриптовом контексте флоу (assertTrue: "${count} > 1").
Ключи: expression — строка; equals — список строк; contains — список строк.
Взаимоисключающие: одно из expression, equals, contains.
commands: - copyText: id: total into: total - assertTrue: equals: ["${total}", "42"] - assertTrue: "Number(total) > 40"copyText
Заголовок раздела «copyText»Читает текст элемента в переменную into (по умолчанию copiedText), доступную как ${name} и как глобал в JS. Алиас copyTextFrom.
Алиасы: copyTextFrom
Ключи: selector — селектор · обязательный; into — строка.
commands: - copyText: id: order-number into: orderassertFile
Заголовок раздела «assertFile»Для тестов расширений VS Code: проверяет, что path (относительно открытого workspace) существует и, с contains, содержит текст.
Платформы: vscode
Ключи: path — строка · обязательный; contains — строка.
commands: - assertFile: path: out/report.md contains: "PASS"assertScreenshot
Заголовок раздела «assertScreenshot»Сравнивает экран с <name>.png; первый прогон создаёт эталон. tolerance — допустимый процент отличающихся пикселей (по умолчанию 0.5); при провале фактический кадр сохраняется как <name>.actual.png.
Ключи: name — строка · обязательный; tolerance — число.
commands: - assertScreenshot: checkout - assertScreenshot: name: screens/home tolerance: 1.5Скриншоты и видео
Заголовок раздела «Скриншоты и видео»takeScreenshot
Заголовок раздела «takeScreenshot»Пишет <name>.png (по умолчанию screenshot.png) — относительно текущей папки в CLI, рядом с артефактами прогона в десктопе.
Ключи: name — строка.
commands: - takeScreenshot: after-loginstartRecording
Заголовок раздела «startRecording»Начинает запись (нативную на Android/iOS, screencast на web); stopRecording пишет <name>.mp4 (по умолчанию recording.mp4). Видео всего прогона проще получить через tapstep test --video.
Ключи: name — строка.
commands: - startRecording: checkout - tapOn: "Pay" - stopRecordingstopRecording
Заголовок раздела «stopRecording»Завершает запись, начатую startRecording, и сохраняет файл.
commands: - stopRecordingСостояние устройства
Заголовок раздела «Состояние устройства»setLocation
Заголовок раздела «setLocation»Подменяет локацию устройства { lat, lon } (geolocation override на web).
Платформы: web, android, ios
Ключи: lat — число · обязательный; lon — число · обязательный.
commands: - setLocation: lat: 43.238 lon: 76.889Последовательно ставит локацию в каждую точку "lat, lon"; с speed (м/с) пауза между точками считается по расстоянию, иначе 1 с.
Платформы: web, android, ios
Ключи: points — список строк · обязательный; speed — число.
commands: - travel: points: - "43.238, 76.889" - "43.240, 76.900" speed: 15setOrientation
Заголовок раздела «setOrientation»portrait, landscapeLeft (landscape), landscapeRight, upsideDown (регистр не важен).
Платформы: web, android, ios
Ключи: orientation — enum (portrait | landscapeLeft | landscapeRight | upsideDown) · обязательный.
commands: - setOrientation: landscapesetAirplaneMode
Заголовок раздела «setAirplaneMode»enabled или disabled (true/false тоже работают). Только Android.
Платформы: android
Ключи: mode — enum (enabled | disabled) · обязательный.
commands: - setAirplaneMode: enabledtoggleAirplaneMode
Заголовок раздела «toggleAirplaneMode»Переключает авиарежим. Только Android.
Платформы: android
commands: - toggleAirplaneModeaddMedia
Заголовок раздела «addMedia»Кладёт один путь или список путей в медиатеку устройства.
Платформы: android, ios
Ключи: paths — список строк · обязательный.
commands: - addMedia: - fixtures/photo.jpg - fixtures/clip.mp4clearKeychain
Заголовок раздела «clearKeychain»Стирает keychain симулятора. Только iOS.
Платформы: ios
commands: - clearKeychainУправление потоком
Заголовок раздела «Управление потоком»runFlow
Заголовок раздела «runFlow»runFlow: path.helper.yaml вставляет хелпер (файл обязан заканчиваться на .helper.yaml; путь ищется в папке вызывающего файла, затем от корня проекта — пишите его от корня, helpers/login.helper.yaml, и строка работает во флоу на любой глубине). Форма-мапа принимает file или вложенные commands, опциональный when ({ visible | notVisible: <селектор> } или { platform: android | [web, vscode] } — имена: web, android, ios, vscode) и env — переменные на время блока (перекрытые имена восстанавливаются, новые остаются). params: хелпера передаются через env.
Ключи: file — строка; when — условие; env — мапа; commands — команды.
commands: - runFlow: helpers/login.helper.yaml - runFlow: file: helpers/login.helper.yaml env: USER: qa@example.com - runFlow: when: visible: "Accept cookies" commands: - tapOn: "Accept cookies"times: N или while: <условие> ({ visible | notVisible: <селектор> }) плюс commands. Цикл while останавливается после 1000 итераций.
Ключи: times — целое; while — условие; commands — команды · обязательный.
commands: - repeat: times: 3 commands: - tapOn: "+" - repeat: while: visible: "Load more" commands: - tapOn: "Load more"Выполняет commands; при ошибке повторяет до maxRetries раз (по умолчанию 1). Успех после повторов помечается в отчёте.
Ключи: maxRetries — целое; commands — команды · обязательный.
commands: - retry: maxRetries: 2 commands: - tapOn: "Refresh" - assertVisible: "Updated"assertWithAI
Заголовок раздела «assertWithAI»Спрашивает у настроенной модели, верно ли утверждение для текущего экрана. Голая форма — optional: true: провал даёт предупреждение; { assertion, optional: false } роняет флоу. Нужно подключение к AI: ai: в config.yaml или TAPSTEP_AI_* — см. AI-агенты.
Ключи: assertion — строка · обязательный; optional — bool.
commands: - assertWithAI: "The cart shows exactly two items" - assertWithAI: assertion: "No overlapping text on the screen" optional: falseassertNoDefectsWithAI
Заголовок раздела «assertNoDefectsWithAI»Просит модель найти явные визуальные дефекты (обрезанный текст, наложения, сломанная вёрстка). По умолчанию optional; { optional: false } роняет флоу.
Ключи: optional — bool.
commands: - assertNoDefectsWithAIextractTextWithAI
Заголовок раздела «extractTextWithAI»Просит модель считать что-то с экрана в переменную into (по умолчанию aiText); с pattern (regex) ответ обязан совпасть — одна повторная попытка, затем шаг падает.
Ключи: query — строка · обязательный; into — строка; pattern — строка.
commands: - extractTextWithAI: query: "the 6-digit confirmation code" into: code pattern: "\\d{6}" - inputText: "${code}"Скрипты
Заголовок раздела «Скрипты»evalScript
Заголовок раздела «evalScript»Выполняет JS в скриптовом контексте флоу (один QuickJS-контекст на прогон). Переменные флоу — глобалы; output.name = … публикует ${output.name}; console.log попадает в отчёт. См. Скрипты.
Ключи: script — строка · обязательный.
commands: - evalScript: "output.total = Number(price) * 2" - assertVisible: "${output.total}"runScript
Заголовок раздела «runScript»Запускает .js-файл (путь относительно флоу) в том же контексте; env добавляет переменные для скрипта.
Ключи: file — строка · обязательный; env — мапа.
commands: - runScript: file: scripts/prepare.js env: SEED: "42"API и данные
Заголовок раздела «API и данные»request
Заголовок раздела «request»Вызывает HTTP-эндпоинт из флоу (http — алиас). - request: <url> — это GET; форма-мапа принимает method, headers, query, json или body, auth ({ bearer } / { basic: { user, pass } }), extract (имя → JSONPath в ${vars}), assert или retryUntil (status кодом или "2xx", равенства json / { contains }, headers, schema файлом или inline), timeout мс (по умолчанию 30000). retryUntil опрашивает раз в секунду. ${} подставляется в запрос, но не в ожидаемые значения. Относительный url дописывается к http.baseUrl флоу, а блок http: шапки задаёт ещё заголовки по умолчанию и cookie-jar. С device: none флоу становится чисто API — см. API-тестирование.
Алиасы: http
Ключи: url — строка · обязательный; method — enum (GET | POST | PUT | PATCH | DELETE | HEAD | OPTIONS); headers — мапа; query — мапа; json — мапа; body — строка; auth — мапа; extract — мапа; assert — мапа; retryUntil — мапа; timeout — мс.
Взаимоисключающие: одно из json, body; одно из assert, retryUntil; внутри auth: одно из bearer, basic.
commands: - request: method: POST url: "${API}/login" json: email: "${EMAIL}" password: "${PASSWORD}" extract: token: $.token assert: status: 200 - request: url: "${API}/me" auth: bearer: "${token}" retryUntil: json: $.status: active timeout: 20000Выполняет один запрос к Postgres, MySQL или SQLite — подготовить фикстуру до UI, проверить, что UI записал, убрать за собой в after. db — строка подключения (postgres://…, mysql://…, sqlite:<путь>), обычно ${DATABASE_URL} из .env; db: в шапке флоу — значение по умолчанию для всех шагов без него. Каждый шаг открывает своё соединение, поэтому sqlite::memory: в следующем шаге снова пустая — указывайте sqlite: на файл. Ровно одно из query (возвращает строки) и exec (возвращает число изменённых строк) обязательно. params — список скаляров (строки, числа, булевы, null), которые связываются по порядку с плейсхолдерами самого запроса ($1, $2 в Postgres, ? в MySQL и SQLite), так что значение никогда не вклеивается в текст SQL. Параметр ${var} несёт извлечённое значение и связывается как текст, поэтому в Postgres приводите плейсхолдер к типу колонки (where id = $1::int). readOnly: true выполняет запрос в транзакции, которая откатывается: проверка, которая не может изменить данные. extract принимает JSONPath по результату — массив строк для query ($[0].id), { "affected": N } для exec; assert принимает rows, minRows, none, first (колонки первой строки), contains (какая-то строка совпала по всем колонкам) и affected. timeout мс (по умолчанию 30000) покрывает и подключение, и запрос. После шага доступны ${sql.rows} или ${sql.affected}. DSN — секрет: в отчётах и логах он выглядит как scheme://user:***@host/db. Запись разрешена — в CI укажите в db: пользователя базы только на чтение для сюит, которые лишь проверяют. См. API-тестирование.
Ключи: db — строка; query — строка; exec — строка; params — список строк; timeout — мс; readOnly — bool; extract — мапа; assert — мапа.
Взаимоисключающие: одно из query, exec.
commands: - sql: exec: "insert into coupons (code, percent) values ($1, $2)" params: ["QA10", 10] assert: affected: 1 - sql: query: "select status, total from orders where coupon = $1" params: ["QA10"] readOnly: true extract: total: $[0].total assert: rows: 1 first: status: paid