Actions reference — browse guides

Step actions reference

Every action a test step can take — clicks, fills, assertions, extraction, network mocking, native gestures — with its fields and the six selector modes.

Every Vera test is an ordered list of steps, and every step has an action that says what it does. This page is the complete list.

Actions are the contract the whole platform is built on: the visual builder offers them, the recorder emits them, the AI generator is constrained to them, and the runner executes them. If something is not in this list, Vera cannot do it in a test.

The list

ActionWhat it doesKey fields
gotoNavigate to a URL. Relative URLs resolve against the project base URL.url
go-backGo back one page in the browser history.—
go-forwardGo forward one page in the browser history.—
reloadReload the current page.—
switch-tabDrive a different tab from here on.target, index, value
clickClick an element.selector
dragDrag one element onto another.selector, targetSelector
fillType text into an input.selector, value
selectChoose an option in a <select>.selector, value
checkCheck a checkbox.selector
uncheckUncheck a checkbox.selector
hoverHover over an element.selector
pressPress a keyboard key.key
upload-fileAttach a file to an <input type="file">. Playwright engine only.selector, source
waitWait for a duration, an element, or a URL.waitType, value
screenshotCapture a screenshot, and compare it to a baseline if one exists.name, fullPage
handle-dialogAnswer the next alert / confirm / prompt. Place it before the step that opens the dialog.dialogAction, promptText, expectMessage
assertVerify a condition. The step that decides pass or fail.assertType, selector, condition, value
assert-consoleAssert about the console the run captured — typically "no errors".expectMatch, level, value, condition
assert-requestAssert about the network the run captured — typically "no 5xx".expectMatch, url, method, statusMatch
use-flowRun a reusable flow inline.flowId
extractCapture a value from the page into a variable.selector, variable
api-requestCall an HTTP endpoint through the run's browser context.url, method, variable
mock-routeStub or block requests matching a URL pattern.url, value
unmock-routeRemove a mock installed earlier in the run.url
set-clockPin the page clock to a fixed instant.value
wait-for-emailWait for an email and capture a code or magic link from it.variable
tapTap a native element or screen coordinates. Native mobile only.selector
swipeSwipe or scroll between two points. Native mobile only.—
assertToast / assertModal / assertValidationErrorSmart assertion presets — a toast, a modal or a field validation error appeared. See Assertion presets.—
waitForLoadingCompleteWait until spinners, skeletons and progress bars have gone.—
a11yAuditRun an accessibility audit on the page or one element; fail at a chosen severity.—
launchAppLaunch or foreground the app under test. Native mobile only.—
if / else / end-ifConditional branch. See Control flow.condition
loop / end-loopRepeat steps while a condition holds. See Control flow.condition

Forty actions. if, else, end-if, loop and end-loop are individual steps rather than nested blocks — that is deliberate, and Control flow explains why it matters when you reorder steps.

goto is the only one of these that needs an address. The other three move around what the run has already visited:

  • go-back and go-forward walk the browser history one entry at a time.
  • reload re-requests the current page.

A run starts with an empty history. A go-back before the first goto therefore has nowhere to go, and Vera fails the step saying so rather than reporting a move that did not happen — "I went back" is an assertion, and a green step is not allowed to make one about a page that never moved. A history move inside a single-page app counts: Vera decides from the address, not from whether the browser fetched a new document.

Switching tabs

Vera drives one tab at a time. A target="_blank" click really does open a second tab, and every step after it still addresses the opener — the run report lists the tabs that were opened and never driven, so this is visible rather than silent. switch-tab is how you choose to go there.

targetPicksNeeds
index (default)The tab at that position; 0 is the tab the run started on.index
urlThe first tab whose URL contains the text.value
titleThe first tab whose title contains the text.value
originalThe tab the run started on, by identity — closing another tab cannot renumber it away.—

Everything after the step follows the chosen tab: clicks, assertions, screenshots, the accessibility audit, assert-console and assert-request, and the dialog rules above. If no tab matches, the step fails and lists the tabs that are open — it never quietly stays where it was, because every later step would then be running against the wrong page.

Dragging

drag takes two selectors: selector is the element picked up and targetSelector is where it is dropped. Both ends go through the ordinary selector modes, and both are {{variable}}-substituted.

Self-heal heals the end that failed. When a drag fails, Vera checks both ends on the live page: if exactly one of them is missing, that selector — and only that one — is sent to the healer, which is told whether it is looking for the element to pick up or the place to drop it. The run and the report say which end was healed ("Drop target:"), and an accepted repair rewrites only that field. If both ends are present (the drop itself failed) or both are missing, the step is not healed and fails with the engine's own error.

go-back, go-forward, reload, switch-tab and drag run on the Playwright and WebDriver engines. On a native-mobile (Appium) run each is refused by name with a message saying which engine it needs — never skipped, because a skipped drag is a green run about a list nobody reordered.

Uploading a file

upload-file attaches a file to an <input type="file">. Point selector at the input itself, not the button beside it — click and fill on a file input are refused by name, because a click opens a chooser nothing answers and the step would pass having uploaded nothing.

The file travels with the step, as bytes:

{
  "action": "upload-file",
  "selector": "#cv",
  "source": { "kind": "inline", "fileName": "cv.pdf", "encoding": "base64", "content": "JVBERi0xLjQK…" }
}
source fieldMeaning
kindinline — the bytes are in the step. (artifact is declared for forward compatibility but not implemented; a run that reaches it is refused with a message saying so.)
fileNameThe name the page sees. Reduced to a plain file name — separators are flattened, so ../../etc/passwd arrives as etc_passwd.
encodingtext (default, UTF-8) or base64 for anything binary. Invalid base64 is refused rather than silently mangled.
contentThe contents, at most 64 KiB once decoded. Inline bytes are stored in the test and copied into every run of it.

There is no path field and there never will be: a step cannot name a file on the machine that runs it. The runner hands the browser the bytes in memory and writes nothing to disk, so the attached file stays valid for the life of the page — a form submitted several steps later still sends it.

There is no mimeType field either. The type the page reads from File.type is derived from fileName's extension, as it would be for a real file: orders.csv is text/csv, cv.pdf is application/pdf. A name with no extension, or one Vera does not recognise, is application/octet-stream.

One file per step. Setting files replaces the input's selection, so two upload-file steps aimed at the same multiple input leave only the second attached. Self-heal applies: a renamed file input is healed like any other selector, and only the locator changes — never the bytes or the name.

upload-file runs on the Playwright engine. On WebDriver and native-mobile (Appium) runs it is refused by name, never skipped — a skipped upload is a green run about a form that received no file.

Assertions

assert is the only action that can fail a test on purpose. Its assertType picks what is being checked:

assertTypePasses when
visibleThe element is present and visible.
hiddenThe element is absent or not visible.
textThe element's text satisfies condition against value.
urlThe page URL satisfies condition against value.
titleThe document title satisfies condition against value.
valueAn input's value satisfies condition against value.
variableA captured variable satisfies condition against value.

A test with no assertion still passes as long as no step errors — it proves the flow is walkable, not that the app is correct. Vera tracks this: an assertion that cannot fail is recorded as insensitive and does not count as coverage.

Assertion presets

The builder's palette also offers presets that expand into an ordinary assert step with its fields pre-filled, so you do not have to remember the selector shapes for common patterns:

  • Assert Toast — a toast or notification appeared, optionally with text.
  • Assert Modal — a modal or dialog opened, optionally with text.
  • Assert Validation Error — a form or field validation error is shown.
  • Wait for Loading — spinners, skeletons and progress bars have gone.
  • Accessibility Audit — runs an axe-core audit and records violations.

These are palette conveniences, not extra action types. A saved test contains the underlying step.

Console and network assertions

assert-console and assert-request read what the run has already captured — Vera streams the console and every request into the run record for the failure report, and these two steps are how a test forms an opinion about it.

Both take expectMatch, which is none (the default) or at-least-one:

  • assert-console with level: error and the default expectMatch: none is "this journey logged no errors and threw no uncaught exceptions".
  • assert-request with statusMatch: 5xx and expectMatch: none is "nothing the page called answered with a server error". statusMatch takes an exact code (404), a class (5xx), an inclusive range (400-499), or a comma-separated list of those; 0 means the request never got a response.
  • assert-request with url: '**/api/pay' and expectMatch: at-least-one is "checkout really did call the payment API".

Two limits worth knowing, because both are deliberate:

  • They look at the whole run so far, not a window around the step. A console error is a defect wherever in the journey it happened, and a window would let one through by being raised a step too early.
  • Capture happens on the primary viewport pass of a Playwright run only. On any other pass or engine the step is skipped, never passed — "no errors were captured" and "nothing was capturing" are different claims, and only the first is evidence.

Dialogs

handle-dialog arms an answer for the next dialog and returns immediately, so it belongs before the step that triggers one — by the time a confirm() is on screen, the click that raised it is already blocked waiting for an answer.

You do not need the step to avoid a hang. Vera always answers a dialog nobody armed, and records what it did on the step that raised it:

DialogUnarmed answerRecorded as
beforeunload ("you have unsaved changes")accept — yes, leave the pageauto-accepted
alert, confirm, promptdismissauto-dismissed

That split is the browser's own, and it matters: dismissing a beforeunload means stay, so a uniform dismiss would leave every navigation off a page with a dirty form silently going nowhere. The auto- prefix is there so a run can never be misread — accepted means a test said so, auto-accepted means nobody did and Vera answered so the run could continue.

Use handle-dialog when the flow needs accept (a delete confirmation), when a prompt() needs text, when you want to assert the wording with expectMessage, or when you want to dismiss a beforeunload to prove the page really does hold an unsaved form. An armed answer always wins over the default. A mismatched expectMessage fails the step that raised the dialog, and an expectation no dialog ever consumed fails the handle-dialog step itself.

Selectors

Any action with a selector field accepts one of six selector modes, so you can target an element the way it is most stable rather than by CSS path:

ModeMatches by
testidA data-testid attribute. The most stable choice.
roleARIA role, optionally with an accessible name.
labelAn associated form label.
placeholderInput placeholder text.
textVisible text content.
cssA raw CSS selector.

Prefer testid and role. text is the most brittle: it can resolve to a child node rather than the element you meant, which is why a text-matched click on a submit button sometimes appears to do nothing.

The recorder chooses for you — see Recording for the nine-rung priority ladder it walks, and how it validates uniqueness before committing to a selector.

Variables in step fields

Any text field can contain {{variable}} tokens, substituted at run time from project variables, environment variables, the active role's credentials, and anything captured earlier by extract or api-request. See Variables for precedence and scope.

Adding an action

Actions are a coordinated contract, not a plugin point. Adding one means editing the ActionType union and step interface in @vera/shared, the route's Zod enum, the executor in the runner, and the builder's palette and step editor together. A step that only exists in some of those places will validate and then do nothing.

See also