Selectors
Every call to page.locator(...) or locator.locator(...) takes a
selector string. ferridriver implements the full Playwright selector
engine in Rust: each selector compiles to a pipeline of parts that runs
against the DOM via a small IIFE injected once per page.
You usually do not need engine prefixes — CSS is the default, and the
get_by_* helpers build correct rich selectors for you.
CSS is the default
Any string without a recognized engine prefix is treated as CSS.
Engines
Prefix a part with engine= to switch engines:
Chaining with >>
The >> operator narrows scope: each part's results become the roots
for the next part's query.
Role selectors
role= understands every ARIA role plus these refiners (Playwright-compatible):
Text and label options
Text-based engines accept options from their typed getter equivalents:
In raw selector strings:
Typed getters
The get_by_* helpers build the right selector for you and are the
preferred API when you have something accessible to target.
Rust:
TypeScript (NAPI):
Test ID attribute
testid= and getByTestId resolve against data-testid. Configuring a
custom test-id attribute (e.g. data-qa) is not supported yet — the
attribute name is currently fixed to data-testid.
Performance notes
- The selector-engine JavaScript is injected once per page via
addInitScriptand re-bootstrapped after navigation. Repeated selectors do not reparse the engine. - Each selector parses to a
Selector { parts: Vec<SelectorPart> }in Rust (seecrates/ferridriver/src/selectors.rs) and compiles into a single IIFE — no per-query JS eval. locator(...)is lazy: no DOM query happens until you call an action (click,fill, …) or an assertion (to_be_visible,to_have_text, …).