Queries
A query identifies an element. It is used by clip, by every entry in marks, mask and check.ignore, and by every step that acts on an element.
Keys combine: a source chooses candidates, filters narrow them, traversal moves from them, and selection picks one.
clip:
css: 'li, div'
contains: Acme Corp
matching: '\$\d'
maxChildren: 12
pick: smallest Sources
| Key | Matches |
|---|---|
css | A CSS selector |
role + name | ARIA role and accessible name |
label | Form control by its label |
placeholder | Input by placeholder text |
testid | data-testid |
text | Element whose trimmed text equals the value |
startsWith | Element whose trimmed text begins with the value |
heading | h1–h6 with this exact text |
text and startsWith also narrow a source written alongside them. exact: true makes role + name, label and placeholder match the whole string, case-sensitively.
role, label, placeholder and testid cannot be used inside span or within. Use css, text, startsWith or contains there.
Filters
| Key | Keeps elements that… |
|---|---|
contains | contain this text |
containingAll | contain all of these strings |
matching | have text matching this regular expression |
maxChildren / minChildren | have at most / at least this many children |
minWidth / maxWidth | are within these widths |
minHeight / maxHeight | are within these heights |
narrowerThan / widerThan | are narrower / wider than this |
visible | have a non-zero size |
within | sit inside an already-resolved region |
Sizes take pixels (400) or viewport units (95vw, 50vh). matching runs inside the page and is bounded by site.timeout.
within
Takes a name or a query written out. Two kinds of name resolve:
clip, the region being captured- any mark declared above this one
A name that has not resolved yet is an error. within is available to marks, mask and check.ignore, which run after the clip is known. Steps cannot use it, because setup runs before anything is measured.
Traversal
| Key | Moves to |
|---|---|
ancestor | The first ancestor matching the filters given |
parent | The parent element |
child: n | The nth child; -1 is the last |
children | All children |
ancestor climbs from the element's parent, so an element is never its own ancestor. It takes pick: nearest (the default) or pick: outermost, which keeps climbing while the parent also matches.
marks:
dialog:
heading: Edit order
ancestor: { narrowerThan: 95vw, pick: outermost } Selection and shape
| Key | Effect |
|---|---|
pick: first | last | smallest | largest | Which candidate to use |
nth: n | The candidate at this position; -1 is the last |
pad: n | Grow the resulting box on all sides |
grow: { top, right, bottom, left } | Grow it on specific sides |
span: [query, query] | The bounding box of several queries |
rect: [x, y, width, height] | A literal box, for source: file recipes |
nth and child count from the end when negative, as Array.at does. pad and grow cannot be negative.
Frames
| Key | Effect |
|---|---|
frame | The <iframe> to resolve inside, named by a query of its own |
Everything written beside frame resolves in that iframe's document — sources, filters, traversal and selection alike. The rect comes back in page coordinates.
clip:
frame: { css: 'iframe[title="Checkout"]' }
css: '.order-total'
pad: 12 | A frame inside a frame | Needs nothing extra |
| Cross-origin frames | Resolve; the browser does it, not the page |
within naming a mark outside the frame | Refused |
transform or zoom on the iframe | Not compensated for |
Steps take queries, so click, fill and wait reach inside a frame with the same key and no extra verb.
Finders
A named query defined once in the configuration and called from any recipe. $1 and $2 stand for the arguments it is called with.
finders:
listRow:
css: 'li, div'
contains: $1
matching: '\$\d'
maxChildren: 12
pick: smallest clip: { listRow: Acme Corp } Failure
A query that matches nothing stops the run, naming the recipe and the key. A mask covers every element its query matches; every other use resolves to exactly one.
For advice on which keys to prefer, see Queries that survive a redesign.