Cucumber.Runtime (Cucumber v1.0.0)
View SourceRuntime execution of cucumber steps.
This module handles the step execution lifecycle within a running test:
- Each step's text is matched against the step registry to find a definition
- Cucumber Expressions are used to extract typed parameters from step text
- The step function is invoked with context containing extracted
args, optionaldatatable, and optionaldocstring - Step return values are processed to update the shared context:
:okkeeps context unchanged- A map is merged into context
- A keyword list is converted to a map and merged
{:ok, data}unwraps and merges{:error, reason}fails the step:pending/{:pending, message}marks the step pending: remaining steps are skipped, after hooks run, and the scenario fails withCucumber.PendingStepError:skipped/{:skipped, reason}skips the rest of the scenario: remaining steps don't run, after hooks run, and the scenario does not fail (a one-line notice is printed instead)
- On failure, enhanced error messages are generated with step history, file locations, and formatted assertion details
Summary
Functions
Executes a step with the given context and step registry.
Runs a complete scenario inside the test process: before hooks, background steps, scenario steps, and after hooks.
Functions
@spec execute_step(map(), Gherkin.Step.t(), map(), Cucumber.Expression.custom_types()) :: map() | {:halted, :pending | :skipped, String.t() | nil, map()}
Executes a step with the given context and step registry.
parameter_types carries custom parameter type definitions (see
Cucumber.ParameterTypes) used when matching cucumber expressions.
Returns the updated context, or {:halted, status, reason, context} when
the step signaled :pending or :skipped — the caller owns what happens
to the rest of the scenario.
Step hooks do not run through this entry point; they require the scenario
runner's hook list (see run_scenario/3).
Runs a complete scenario inside the test process: before hooks, background steps, scenario steps, and after hooks.
Generated feature tests call this as their entire body. The runtime owning
the whole lifecycle (rather than splitting it across ExUnit setup and
on_exit) keeps after-hooks in the test process and gives the runner
control over cross-step flow — the foundation for skip/pending semantics,
retry, and event emission.
Semantics:
- a
{:error, reason}from a before hook fails the scenario without running any steps (after hooks do not run) - a failing background step fails the scenario; after hooks do not run (they are only armed once the background succeeded)
- after hooks run whether the scenario's steps pass or fail, receiving the post-background context
- a
:pendingor:skippedsignal (from a before hook, a background step, or a scenario step) skips the remaining steps — the unexecuted steps land in the context under:skipped_steps— and after hooks still run. Skipped scenarios pass with a printed notice; pending scenarios fail withCucumber.PendingStepError - a failing scenario is retried when a retry limit is configured
(
config :cucumber, retry: nor a@retry-ntag; a tag beats the config, and a scenario-level tag beats a feature-level one): each attempt re-runs before hooks, background, steps, and after hooks with a fresh context (carrying:retry_attempt, 1-based), and the scenario passes if any attempt passes. Undefined, ambiguous, and pending scenarios are never retried — they cannot succeed by repetition — and neither is a cachedbefore_allfailure
Returns the final context.