Skip to content

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.

screenshots/recipes/order-row.yaml
clip:
  css: 'li, div'
  contains: Acme Corp
  matching: '\$\d'
  maxChildren: 12
  pick: smallest

Sources

Key Matches
cssA CSS selector
role + nameARIA role and accessible name
labelForm control by its label
placeholderInput by placeholder text
testiddata-testid
textElement whose trimmed text equals the value
startsWithElement whose trimmed text begins with the value
headingh1–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…
containscontain this text
containingAllcontain all of these strings
matchinghave text matching this regular expression
maxChildren / minChildrenhave at most / at least this many children
minWidth / maxWidthare within these widths
minHeight / maxHeightare within these heights
narrowerThan / widerThanare narrower / wider than this
visiblehave a non-zero size
withinsit 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
ancestorThe first ancestor matching the filters given
parentThe parent element
child: nThe nth child; -1 is the last
childrenAll 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.

screenshots/recipes/edit-order.yaml
marks:
  dialog:
    heading: Edit order
    ancestor: { narrowerThan: 95vw, pick: outermost }

Selection and shape

Key Effect
pick: first | last | smallest | largestWhich candidate to use
nth: nThe candidate at this position; -1 is the last
pad: nGrow 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
frameThe <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.

screenshots/recipes/checkout.yaml
clip:
  frame: { css: 'iframe[title="Checkout"]' }
  css: '.order-total'
  pad: 12
A frame inside a frameNeeds nothing extra
Cross-origin framesResolve; the browser does it, not the page
within naming a mark outside the frameRefused
transform or zoom on the iframeNot 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.

shotlist.config.yaml
finders:
  listRow:
    css: 'li, div'
    contains: $1
    matching: '\$\d'
    maxChildren: 12
    pick: smallest
screenshots/recipes/order-row.yaml
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.