Recording a test
Capture a real browser session as test steps, and the ten-tier priority ladder Vera walks to pick a selector that survives your next deploy.
Recording is the fastest way to get a real test: Vera opens a browser, you use the app, and every click, keystroke and selection arrives in the builder as a step.
Use it when you know the flow and want it captured exactly. Use AI generation when you want Vera to work out the flow for you, and the builder when you want to assemble steps by hand.
Recording a session
- Open a project and start a recording, giving it a start URL.
- A headed browser window opens — a real one you drive yourself.
- Use the app. Steps stream into the builder live as you go.
- Stop the recording. The captured steps are yours to edit, reorder and assert on.
The start URL is validated server-side before the browser navigates, so a recording cannot be used to make the server fetch an address it should not.
What gets captured
Clicks, text input, and select changes. Recording captures interactions, not outcomes — so a recorded test walks the flow but does not yet check anything.
Adding the assertion is the part that makes it a test. Recording gets you the ninety percent that is tedious; the assertion is the ten percent that carries the value, and it is yours to write. See the assertion section.
How selectors are chosen
The recorder does not emit CSS paths if it can avoid it. For every element it walks a ten-tier priority ladder and takes the first tier that produces a unique match:
| # | Tier | Example |
|---|---|---|
| 1 | data-testid | data-testid=checkout-submit |
| 2 | id (dynamic-looking ids skipped) | #email |
| 3 | name attribute (form elements) | [name=password] |
| 4 | ARIA role + accessible name | role=button[name="Submit"] |
| 5 | A unique class-based selector | .checkout-form .primary |
| 6 | placeholder | [placeholder="Enter your email"] |
| 7 | aria-label | [aria-label="Close"] |
| 8 | Associated <label> | label=Email address |
| 9 | Text content (non-inputs, short text) | text=Sign in |
| 10 | CSS path | div > form > button:nth-child(3) |
Two things make this hold up better than a raw recorder:
- Every candidate is validated for uniqueness before it is accepted. A tier that matches two elements is rejected and the next tier is tried, so you do not get a selector that happens to work today because you clicked the first match.
- Generated class names are filtered out. Framework-hashed classes
(
css-1a2b3c, utility soup) are not stable across builds, so they are not used as identity even when they would be unique right now.
Tier 10 is the honest fallback. If a step's selector is a CSS path, that is the
recorder telling you the element had nothing stable to grab — the durable fix is a
data-testid in your app, and it moves that step to tier 1 on the next recording.
When a selector does break
It does not have to be fixed by hand. On a selector-bearing failure the runner can
snapshot the live DOM, ask for a corrected selector, retry the step, and record
what it changed — the run shows healed, with the original and the replacement.
So a renamed class is usually a green run with a note, not a red one.
Recording behind a login
If the project has an auth role configured, capture its session first and the recording starts already signed in — you record the flow you care about instead of re-recording the login every time.
For a site behind a dev/staging gate, configure Basic Auth on the project.
URL-embedded credentials (https://user:pass@host/…) are not enough: Chromium
applies them to the top-level navigation only, so the app's own fetch/XHR calls
still get a 401.
Limits
- One recording session at a time per browser slot; concurrent browsers are capped process-wide.
- Idle sessions time out, so a forgotten window does not hold a browser open.
See also
- Step actions reference — what the captured steps can be
- The test builder — editing what you recorded
- Reusable flows — factoring a recorded login out of ten tests
- Getting started — AI generation and importing existing specs