Перейти к содержимому

Команды флоу

Каждый шаг флоу — одна команда: - 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, но без большинства опциональных возможностей, см. Тестирование десктоп-приложений.

Запускает тестируемое приложение — на 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: allow

Завершает приложение: голая форма - stopApp берёт appId флоу, - stopApp: <appId> останавливает другое. Алиас — killApp.

Алиасы: killApp

Ключи: appId — строка.

commands:
- stopApp
- stopApp: com.example.other

Устанавливает сборку по пути. grant: true сразу выдаёт runtime-разрешения.

Платформы: android, ios

Ключи: path — строка · обязательный; grant — bool.

commands:
- installApp: build/app-debug.apk
- installApp:
path: build/app.ipa
grant: true

Открывает 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}

Сбрасывает сохранённое состояние: localStorage и cookies на web, pm clear на Android, контейнер данных приложения в симуляторе на iOS (только симулятор). Голая форма — для appId флоу; можно передать другой app id.

Ключи: appId — строка.

commands:
- clearState
- clearState: com.example.other

Выдаёт типовые runtime-разрешения (simctl privacy на iOS, pm grant на Android). Голая форма — для appId флоу. На web не поддерживается.

Платформы: android, ios

Ключи: appId — строка.

commands:
- grantPermissions

Задаёт разрешения по одному: мапа имя: 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:
- back

Только для флоу 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: 30000

Нажимает и держит 600 мс — селектор или { point: "x, y" }.

Ключи: selector — селектор; point — точка "x, y".

commands:
- longPressOn: "Message"
- longPressOn:
point: "200, 400"

Два быстрых тапа по селектору или { 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: up

swipe: 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%"

Скроллит, пока селектор не станет видимым. В форме-мапе: 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: true

Находит оба элемента и тянет от центра к центру. 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"

Зеркало check: тапает, только если элемент включён, затем проверяет, что он выключился.

Ключи: selector — селектор · обязательный.

commands:
- uncheck: { id: newsletter }

Двигает указатель без нажатия — для меню, тултипов и контролов, появляющихся только под курсором: у сенсорного экрана нет наведения.

Платформы: web, vscode

Ключи: selector — селектор · обязательный.

commands:
- hover: "Account"
- assertVisible: "Sign out"

Печатает текст в поле, у которого сейчас фокус. ${VAR} подставляется заранее.

Ключи: text — строка · обязательный.

commands:
- tapOn: "Email"
- inputText: "${EMAIL}"

Печатает сгенерированный e-mail в активное поле.

Ключи: length — целое.

commands:
- inputRandomEmail

Печатает сгенерированные имя и фамилию.

Ключи: length — целое.

commands:
- inputRandomPersonName

Печатает случайное число из length цифр (по умолчанию 8) — голая форма, : N или { length: N }.

Ключи: length — целое.

commands:
- inputRandomNumber: 6

Печатает случайные буквы; length символов (по умолчанию 8) — голая форма, : N или { length: N }.

Ключи: length — целое.

commands:
- inputRandomText:
length: 12

Печатает название города из встроенного списка.

Ключи: length — целое.

commands:
- inputRandomCityName

Печатает название страны из встроенного списка.

Ключи: length — целое.

commands:
- inputRandomCountryName

Печатает название цвета из встроенного списка.

Ключи: length — целое.

commands:
- inputRandomColorName

Очищает поле с фокусом.

commands:
- tapOn: "Search"
- clearText

- eraseText: N удаляет N символов перед курсором; голая форма - eraseText очищает всё поле.

Ключи: count — целое.

commands:
- eraseText: 3

Имена клавиш перечислены ниже, у ключа самого шага, и у каждого — экраны, которые его посылают: телефон посылает все, симулятор 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+p

Убирает программную клавиатуру (blur на web, best-effort на iOS).

Платформы: web, android, ios

commands:
- hideKeyboard

Кладёт текст в регистр копирования флоу — тот же, что заполняет copyText и читает ${copiedText}. Это регистр флоу, а не системный буфер обмена.

Ключи: text — строка · обязательный.

commands:
- setClipboard: "hello"
- pasteText

Печатает содержимое регистра (copyText / setClipboard, иначе переменную copiedText) в активное поле.

commands:
- copyText: "Order #"
- tapOn: "Search"
- pasteText

Выбирает пункт по видимому тексту (option), по значению (optionValue) или по позиции (optionIndex) — ровно одно из трёх. Шлёт input и change, чтобы фреймворк увидел изменение.

Платформы: web, vscode

Ключи: selector — селектор · обязательный; option — строка; optionValue — строка; optionIndex — целое.

Взаимоисключающие: одно из option, optionValue, optionIndex.

commands:
- selectOption:
id: country
option: "Germany"

Диалог выбора файла — это интерфейс браузера, по нему нельзя кликнуть, поэтому файлы передаются в input напрямую. files принимает путь или список путей; относительный ищется рядом с файлом флоу, затем в рабочем каталоге, а путь, за которым нет файла, валит шаг.

Платформы: web, vscode

Ключи: selector — селектор · обязательный; files — список строк · обязательный.

commands:
- uploadFile:
id: avatar
files: fixtures/face.png

Голая форма сравнивает точно; в форме-мапе — одно из 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.

Ждёт до timeout мс (по умолчанию 5000, --wait-timeout), пока селектор не станет видимым, иначе шаг падает.

Ключи: selector — селектор · обязательный; timeout — мс.

commands:
- assertVisible: "Welcome"
- assertVisible:
id: toast
timeout: 10000

Опрашивает, пока селектор не исчезнет на успокоившемся экране (до timeout мс, по умолчанию 5000); падает, если он всё ещё виден, и падает с причиной, если страница так и не успокоилась — отсутствие элемента на ещё рисующейся странице не доказывает, что он исчез.

Ключи: selector — селектор · обязательный; timeout — мс.

commands:
- assertNotVisible: "Loading…"

То же, что assertVisible; читается лучше там, где шаг — ожидание, а не проверка.

Ключи: selector — селектор · обязательный; timeout — мс.

commands:
- waitForVisible:
text: "Dashboard"
timeout: 15000

Форма-алиас: { visible: <селектор> } или { notVisible: <селектор> } плюс timeout мс.

Ключи: visible — селектор; notVisible — селектор; timeout — мс.

commands:
- extendedWaitUntil:
notVisible: "Spinner"
timeout: 20000

Ждёт, пока экран перестанет меняться; timeout мс ограничивает ожидание (по умолчанию --settle-timeout, 2000).

Ключи: timeout — мс.

commands:
- waitForAnimationToEnd
- waitForAnimationToEnd:
timeout: 5000

{ 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"

Читает текст элемента в переменную into (по умолчанию copiedText), доступную как ${name} и как глобал в JS. Алиас copyTextFrom.

Алиасы: copyTextFrom

Ключи: selector — селектор · обязательный; into — строка.

commands:
- copyText:
id: order-number
into: order

Для тестов расширений VS Code: проверяет, что path (относительно открытого workspace) существует и, с contains, содержит текст.

Платформы: vscode

Ключи: path — строка · обязательный; contains — строка.

commands:
- assertFile:
path: out/report.md
contains: "PASS"

Сравнивает экран с <name>.png; первый прогон создаёт эталон. tolerance — допустимый процент отличающихся пикселей (по умолчанию 0.5); при провале фактический кадр сохраняется как <name>.actual.png.

Ключи: name — строка · обязательный; tolerance — число.

commands:
- assertScreenshot: checkout
- assertScreenshot:
name: screens/home
tolerance: 1.5

Пишет <name>.png (по умолчанию screenshot.png) — относительно текущей папки в CLI, рядом с артефактами прогона в десктопе.

Ключи: name — строка.

commands:
- takeScreenshot: after-login

Начинает запись (нативную на Android/iOS, screencast на web); stopRecording пишет <name>.mp4 (по умолчанию recording.mp4). Видео всего прогона проще получить через tapstep test --video.

Ключи: name — строка.

commands:
- startRecording: checkout
- tapOn: "Pay"
- stopRecording

Завершает запись, начатую startRecording, и сохраняет файл.

commands:
- stopRecording

Подменяет локацию устройства { 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: 15

portrait, landscapeLeft (landscape), landscapeRight, upsideDown (регистр не важен).

Платформы: web, android, ios

Ключи: orientation — enum (portrait | landscapeLeft | landscapeRight | upsideDown) · обязательный.

commands:
- setOrientation: landscape

enabled или disabled (true/false тоже работают). Только Android.

Платформы: android

Ключи: mode — enum (enabled | disabled) · обязательный.

commands:
- setAirplaneMode: enabled

Переключает авиарежим. Только Android.

Платформы: android

commands:
- toggleAirplaneMode

Кладёт один путь или список путей в медиатеку устройства.

Платформы: android, ios

Ключи: paths — список строк · обязательный.

commands:
- addMedia:
- fixtures/photo.jpg
- fixtures/clip.mp4

Стирает keychain симулятора. Только iOS.

Платформы: ios

commands:
- clearKeychain

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"

Спрашивает у настроенной модели, верно ли утверждение для текущего экрана. Голая форма — 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: false

Просит модель найти явные визуальные дефекты (обрезанный текст, наложения, сломанная вёрстка). По умолчанию optional; { optional: false } роняет флоу.

Ключи: optional — bool.

commands:
- assertNoDefectsWithAI

Просит модель считать что-то с экрана в переменную into (по умолчанию aiText); с pattern (regex) ответ обязан совпасть — одна повторная попытка, затем шаг падает.

Ключи: query — строка · обязательный; into — строка; pattern — строка.

commands:
- extractTextWithAI:
query: "the 6-digit confirmation code"
into: code
pattern: "\\d{6}"
- inputText: "${code}"

Выполняет JS в скриптовом контексте флоу (один QuickJS-контекст на прогон). Переменные флоу — глобалы; output.name = … публикует ${output.name}; console.log попадает в отчёт. См. Скрипты.

Ключи: script — строка · обязательный.

commands:
- evalScript: "output.total = Number(price) * 2"
- assertVisible: "${output.total}"

Запускает .js-файл (путь относительно флоу) в том же контексте; env добавляет переменные для скрипта.

Ключи: file — строка · обязательный; env — мапа.

commands:
- runScript:
file: scripts/prepare.js
env:
SEED: "42"

Вызывает 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