UI contracts
DOM and ARIA shapes each command and qualifier actually resolve — diagnose timeouts as wrong control shape, not wrong label
StrikeTest finds controls by labels and fixed DOM/ARIA shapes, never by CSS or XPath in .stk. A timeout or element not found often means the control shape does not match the command — not that the quoted label string is typo’d.
Every command page has a Requirements section. This hub is the master map.
Scope layers
| Layer | Command | What it scopes |
|---|---|---|
| iframe / frame | scope to | Resolution root for later steps |
| Element stack | in (command) | Nested region under current root |
| One-shot container | click on "…" in "…" / should in "…" see | Action or assert inside a container; does not push the in stack |
| One-shot row | … in row "…" | Action or assert inside a table row |
Find hints (by …) apply to the primary target only. Container and row keys always use auto-find.
Find hints vs auto-find
Without by …, each command uses its own auto-find candidate list. With by …, that single strategy replaces the auto chain.
| Hint | Resolves by |
|---|---|
by id | Element #id |
by data-testid | [data-testid='…'] |
by aria-label | [aria-label='…'] |
by name | [name='…'] (any tag) |
by text | Clickables only: button, a, input[type=button], [role=button], [role=link], [role=tab] |
by role "R" | [role='R'] + accessible name (aria-label, else direct text nodes) |
by attribute | Unique visible presence of the attribute named by the label |
Auto data-* fallback (web, no by …): if auto-find misses and the label is a valid data-* attribute name, a unique visible element that has that attribute may still resolve. Ambiguous (2+) fails.
Details: Find hints.
Auto-find cheat sheet
General resolve (ResolveByLabel — hover, many clicks, toggle, most should have): fill candidates → click candidates → checkbox candidates.
| Pool | Order (exact label) |
|---|---|
| fill | id → input/textarea data-testid → input/textarea aria-label → input name → input placeholder → textarea name → textarea placeholder |
| click | id → data-testid → aria-label → role=tab + exact text → visible text on button / a / input[type=button] only → submit value |
| checkbox | checkbox id → data-testid → aria-label → name |
Critical nuance: default page click on "Login" visible text does not match [role=button]. Use by text, by role "button", id/testid/aria-label, or click … in / in row (those do include [role=button]).
| Specialized path | Order / shape |
|---|---|
| Container | role=dialog HasText → data-testid → aria-label → heading text → general resolve |
| Row | tr or role=row containing key text |
| Click in container (action) | button → a → role=button → id → data-testid → aria-label |
| Click in row (action) | button → a → role=button (no id/testid/aria in auto path) |
| Column | role=columnheader + text → th + text → th[aria-label] |
| Native select | select id → data-testid → aria-label → name → label + select |
| Combobox trigger | combobox#id → data-testid → combobox aria-label → button[aria-haspopup] → button text → label + combobox → input[role=combobox] |
| Combobox panel | visible role=listbox or role=menu (prefer aria-controls / aria-owns) |
| File input | file id → data-testid → aria-label → name → label ≫ file (hidden OK) |
| Date / time | aria-label → label + input → id |
Range (set) | aria-label → label + range → id → name |
iframe (scope) | iframe/frame title, name, aria-label |
Command → UI shape
| Command family | Required UI shape |
|---|---|
click on (default) | id / data-testid / aria-label; or tab text; or text on button/a/input[type=button]; submit value |
click + by text | Also [role=button], [role=link], [role=tab] |
click … in / in row | Container/row contracts + action includes [role=button] |
click … column | Column header / th |
fill / clear / press … on | input / textarea only |
select | Native <select> |
open / pick | Combobox trigger + listbox/menu panel + option/li inside panel |
type … and pick | Resolvable field + same panel/option as combobox |
upload | input[type=file] |
set | input[type=range] |
pick date / pick time | Native date / time inputs |
toggle | Checkable / switch-like |
hover / double·right·force click / scroll to / drag | General resolve |
scope to | iframe / frame |
in (command) | Container resolve per stack frame |
should see | Any visible text (iframe scope; element stack ignored on bare see) |
should on/in / in row see | Container / row contracts |
should have | General resolve (+ count / sum / sorted rules) |
accept / dismiss | No DOM — dialog message fragment |
accept cookies | Allowlist button labels via general resolve |
| Page / API ops | No element contract |
Wrong shape → use instead
| UI pattern | Wrong command | Use instead |
|---|---|---|
Native <select> | open / pick | select "…" from "…" |
ARIA combobox / aria-haspopup button | Bare option text click | open / pick |
Radix / menu role=menuitem | open … and pick, bare text click on item | click trigger by id + click item by id |
<div role="button"> with no <button> | Default click on "text" | by text, by role "button", or id / aria-label / data-testid |
Plain <div> with only text | click / open | Real button/link, or add id / aria-label / role=button + correct hint |
| Custom date / time widget | pick date / pick time | Native inputs, or fill/test hooks |
| Custom slider | set | Native range, or other supported control |
| Contenteditable / custom editor | fill | Native input / textarea |
# Radix / Headless menu (not combobox)
When I click on "filter-trigger" by id
And I click on "filter-item-1" by idFailure glossary
| Error pattern | Typical cause |
|---|---|
element not found (tried …) | No candidate matched — wrong label or wrong control shape / scope |
ambiguous … (matched N …) | Duplicate id/testid/text; glob matched multiple |
timed out after … | Action auto-wait exhausted (DOM not ready or shape never appears) |
element is disabled | Resolved a disabled control |
toggle …: not checkable | Target is not checkbox/switch/radio-like |
set …: not a native range input | Used set on a non-range control |
| Combobox panel did not open / multiple open panels | Trigger is not combobox-shaped, or panels lack ownership |
frame "…" not found | Bad iframe label or frame not visible |
be visible fails as not found | Node was removed from the DOM — that is not a successful not be visible |
Related
- Commands — per-command Requirements
- Find hints
- Action qualifiers
- should states
- Syntax