Cucumber.Hooks (Cucumber v1.0.0)
View SourceProvides hooks for setup and teardown in Cucumber tests.
Four levels of hooks are supported, mirroring reference Cucumber implementations:
before_all/after_all— run once per test run (see below)before_scenario/after_scenario— run around each scenariobefore_step/after_step— run around each step (including background steps)
Scenario and step hooks can be filtered by tag. Hooks of the same kind
run in the order they are defined (module order, then definition order),
with after-hooks running in reverse. Any hook can be given a name:,
which appears in failure output (and in Cucumber Messages, eventually).
Examples
defmodule DatabaseSupport do
use Cucumber.Hooks
# Runs once before the first scenario of the run
before_all context do
{:ok, Map.put(context, :api_started, true)}
end
# Runs once after the whole run, in reverse definition order
after_all _context do
:ok
end
# Global before hook - runs for all scenarios
before_scenario context, name: "prepare database" do
{:ok, Map.put(context, :setup, true)}
end
# Tagged before hook - only runs for @database scenarios
before_scenario "@database", context do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(MyApp.Repo)
if context.async do
Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, {:shared, self()})
end
{:ok, context}
end
# After hooks run in reverse order
after_scenario _context do
# Cleanup code
:ok
end
# Step hooks bracket every step; after_step sees the step's status
after_step context do
log_step(context.step, context.step_status)
:ok
end
endRun-level hooks
before_all hooks run lazily, exactly once per run, before the first
scenario that executes (serialized through Cucumber.RunCoordinator, so
this is safe with @async features). Their accumulated context map is
merged into every scenario's context. If a before_all hook fails, the
remaining before_all hooks still run (to set up as much as possible for
cleanup), but every scenario in the run fails with the original error.
after_all hooks run once after the whole suite via ExUnit.after_suite/1,
in reverse definition order, receiving the before_all context plus the
ExUnit suite summary under :suite_result. A failing after_all hook
fails the run; the remaining after_all hooks still run.
Run-level hooks cannot be tagged (they don't belong to any scenario).
One hook per kind — unless named
A module may define only one global and one per-tag hook of each kind;
giving hooks a name: lifts that restriction, so a module can define any
number of distinctly-named hooks of the same kind.
Summary
Types
Wraps each hook invocation — receives the hook's run-order index, its name (nil if unnamed), and a one-arity function that executes the hook with the given context overrides merged in; must return that function's result. The scenario runner uses this to bracket hooks with Cucumber Messages events and to inject each hook's message reference.
Functions
Defines an after_all hook that runs once after the whole test run, in reverse definition order.
Defines an after_scenario hook that runs after each scenario.
Defines an after_step hook that runs after each step (including failing ones) of matching scenarios.
Defines a before_all hook that runs once per test run, before the first scenario that executes.
Defines a before_scenario hook that runs before each scenario.
Defines a before_step hook that runs before each step (including background steps) of matching scenarios.
Types
@type around() :: (non_neg_integer(), String.t() | nil, (map() -> term()) -> term())
Wraps each hook invocation — receives the hook's run-order index, its name (nil if unnamed), and a one-arity function that executes the hook with the given context overrides merged in; must return that function's result. The scenario runner uses this to bracket hooks with Cucumber Messages events and to inject each hook's message reference.
@type hook_type() ::
:before_scenario
| :after_scenario
| :before_step
| :after_step
| :before_all
| :after_all
Functions
Defines an after_all hook that runs once after the whole test run, in reverse definition order.
The hook receives the before_all context with the ExUnit suite summary
merged under :suite_result. A raise or {:error, reason} fails the
run, but the remaining after_all hooks still run. Cannot be tagged; can
be given a name:.
Defines an after_scenario hook that runs after each scenario.
Can optionally be filtered by tag and/or given a name:. After hooks run
in reverse order of definition and receive the post-background context.
Their return values are ignored.
Defines an after_step hook that runs after each step (including failing ones) of matching scenarios.
Can optionally be filtered by tag and/or given a name:. The hook
receives the step's context with :step_status set to :passed,
:failed, :pending, or :skipped. After-step hooks run in reverse
order of definition; their return values are ignored.
Defines a before_all hook that runs once per test run, before the first scenario that executes.
The hook receives the accumulated before_all context (starting from an
empty map) and may return :ok, a map, a keyword list, {:ok, map}, or
{:error, reason}. The final context map is merged into every scenario's
context. Cannot be tagged; can be given a name:.
Defines a before_scenario hook that runs before each scenario.
Can optionally be filtered by tag and/or given a name:. The hook
receives the test context and must return one of:
{:ok, context}:ok(keeps context unchanged)- map (merged into context)
- keyword list (merged into context)
{:error, reason}(fails the scenario; steps and after hooks don't run):skipped/{:skipped, reason}(skips the whole scenario without failing it; remaining before hooks and all steps are skipped, after hooks still run):pending/{:pending, message}(like:skipped, but the scenario fails withCucumber.PendingStepError)
Defines a before_step hook that runs before each step (including background steps) of matching scenarios.
Can optionally be filtered by tag and/or given a name:. The hook
receives the step's prepared context — including :step (the
Gherkin.Step), :args, and any :datatable/:docstring — and supports
the same return values as before_scenario (a :skipped/:pending
signal skips the rest of the scenario; {:error, reason} fails it
without running the step body).