# `Cucumber.Hooks`
[🔗](https://github.com/huddlz-hq/cucumber/blob/main/lib/cucumber/hooks.ex#L1)

Provides 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 scenario
  * `before_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
    end

## Run-level hooks

`before_all` hooks run lazily, exactly once per run, before the first
scenario that executes. They run in that scenario's test process;
`Cucumber.RunCoordinator` guarantees they run only once, and `@async`
features that reach them concurrently wait for the result. They may
attach via `Cucumber.attach/4` and friends. 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.

# `around`

```elixir
@type around() :: (non_neg_integer(), String.t() | nil, (map() -&gt; term()) -&gt; 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.

# `hook`

```elixir
@type hook() :: {hook_type(), String.t() | nil, String.t() | nil, {module(), atom()}}
```

# `hook_type`

```elixir
@type hook_type() ::
  :before_scenario
  | :after_scenario
  | :before_step
  | :after_step
  | :before_all
  | :after_all
```

# `after_all`
*macro* 

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:`.

# `after_all`
*macro* 

# `after_scenario`
*macro* 

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.

# `after_scenario`
*macro* 

# `after_scenario`
*macro* 

# `after_step`
*macro* 

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.

# `after_step`
*macro* 

# `after_step`
*macro* 

# `before_all`
*macro* 

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:`.

# `before_all`
*macro* 

# `before_scenario`
*macro* 

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 with `Cucumber.PendingStepError`)

# `before_scenario`
*macro* 

# `before_scenario`
*macro* 

# `before_step`
*macro* 

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).

# `before_step`
*macro* 

# `before_step`
*macro* 

---

*Consult [api-reference.md](api-reference.md) for complete listing*
