BDD
Cucumber / Gherkin framework for ferridriver. Translates .feature files
into parallel test execution via the core TestRunner — same worker
pool, retries, reporters, and fixtures as Rust tests.
146 built-in steps backed by the Page / Locator API (not raw JS
evaluate). All selectors support the Playwright engine syntax
(role=, text=, label=, …).
Rust step bodies
Wire a binary entry point:
JavaScript / TypeScript step bodies
Given / When / Then / defineStep / And / But / Before /
After / BeforeAll / AfterAll / BeforeStep / AfterStep /
defineParameterType / setWorldConstructor / setDefaultTimeout /
setDefinitionFunctionWrapper are globals. this is the World,
carrying page / context / request / browser / parameters /
attach / log / skip.
DataTable exposes raw/rows/hashes/rowsHash/transpose.
Returning 'pending' or 'skipped' (or calling this.skip()) marks the
step as such.
Fixtures in a scenario
bindSteps(test) binds the registrars to a test.extend chain, and a
step destructures what it needs from its first parameter:
The object a step receives is the scenario's World AND its fixture bag:
page / context / request / browser / parameters / attach /
log / skip are on it either way, and a setWorldConstructor
instance becomes its prototype. Fixtures resolve through the same graph
a Playwright spec resolves through — dependency order, auto,
{ scope: 'worker' } shared across the scenarios one worker runs, and
LIFO teardown after the last step. Steps bound to unrelated test
objects fail the scenario up front, pointing at mergeTests(...).
Files are bundled with rolldown (TypeScript, imports, tree-shake),
compiled to QuickJS bytecode once, and Module::loaded per worker. The
bytecode cache is content-hashed, in-memory within a run and persisted
to a cross-process disk cache so an unchanged source tree skips both
rolldown and the QuickJS compile on the next start. No Node, no Bun,
no package.json, no node_modules.
Hybrid (Rust + JS / TS)
The Rust step registry and the JS / TS registry merge — a single
feature can mix steps defined in both, and Before / After hooks from
either side run together.
Gherkin coverage
Full Gherkin 6+: Features, Rules, Backgrounds, Scenarios, Scenario
Outlines (with named Examples blocks), tags (boolean expressions: and,
or, not, parens), data tables, doc strings (with media-type hints
like """json), the asterisk (*) keyword, and i18n keywords via
--language or # language: xx (70+ languages).
How a scenario is named
A Rule and a Scenario Outline are each a suite around what they hold,
so a scenario's title path is
<feature> > [rule >] [outline >] <scenario> — the same nesting
playwright-bdd generates, and what --grep, the rerun list and a
report's own grouping key read.
One Examples ROW is titled by the first of these that applies:
- a
# title-format:comment directly above theExamples:keyword, or above its first tag; - the Examples block's own name, if it names a column in
<>; - the scenario's name, if it names a column in
<>; [test].examplesTitleFormatfrom the config file;Example #<_index_>.
<column> is substituted from the row and <_index_> is the row's
number, counting across every Examples block of that outline. A
placeholder no column supplies is left exactly as written.
Learn more
- Built-in steps — all 146 steps grouped by category
- Hooks — lifecycle points and tag filters
- Running — CLI, reporters, profiles