# `Continuum.Test`
[🔗](https://github.com/Yyeger/Continuum/blob/main/lib/continuum/test.ex#L1)

Public helpers for testing Continuum workflows.

The helpers in this module are deliberately small and stable. They cover the
v0.1 testing loop:

  * run workflows against the in-memory journal
  * load or persist event histories
  * replay a committed golden history
  * inject signals and timers in deterministic tests
  * check out an Ecto SQL Sandbox connection for Postgres-backed tests

The in-memory journal is process-local and not durable. Use unique run IDs
or call `reset_in_memory!/0` between tests that need a clean journal.

# `replay_result`

```elixir
@type replay_result() ::
  {:ok, term()}
  | {:suspended, term()}
  | {:continued, binary()}
  | {:error, term()}
```

# `assert_replays`

```elixir
@spec assert_replays(module(), term(), [map()]) :: term()
```

Assert that a workflow replays from history without drift.

Returns the replayed result.

# `assert_replays`

```elixir
@spec assert_replays(module(), term(), [map()], term()) :: term()
```

Assert that a workflow replays from history to `expected`.

# `checkout_sandbox`

```elixir
@spec checkout_sandbox(
  module() | nil,
  keyword()
) :: :ok
```

Check out an Ecto SQL Sandbox connection.

Pass `shared: true` when workflow engines or workers need to use the test
process' checked-out connection.

# `dump_history!`

```elixir
@spec dump_history!(binary(), Path.t(), keyword()) :: :ok
```

Persist a run history to `path` as an Erlang external term.

The resulting file is intended for golden-history tests committed to the
repository.

# `fire_timer`

```elixir
@spec fire_timer(
  binary(),
  keyword()
) :: :ok | {:error, term()}
```

Inject a fired timer event for the latest pending timer in a run's history.

# `history`

```elixir
@spec history(
  binary(),
  keyword()
) :: [map()]
```

Load a run's event history from a journal.

# `inject_signal`

```elixir
@spec inject_signal(binary(), atom(), term(), keyword()) :: :ok | {:error, term()}
```

Inject a signal into a run and wake its local engine when one exists.

Delivery goes through the same `Continuum.Runtime.SignalRouter` path as
`Continuum.signal/4`: in-memory signals are buffered in the run's mailbox
and consumed by the matching `await signal`, journaling `signal_received`
with the await's command identity — injected signals exercise the same
command-identity drift detection as production deliveries.

# `load_history!`

```elixir
@spec load_history!(Path.t()) :: [map()]
```

Load a history previously written by `dump_history!/3`.

# `replay`

```elixir
@spec replay(module(), term(), [map()], keyword()) :: replay_result()
```

Replay a workflow from an existing history.

Returns `{:ok, result}` when the workflow completes from history, or
`{:suspended, reason}` if the history ends at a pending effect.

# `reset_in_memory!`

```elixir
@spec reset_in_memory!() :: :ok
```

Reset the in-memory journal.

# `start_postgres`

```elixir
@spec start_postgres(module(), term(), keyword()) ::
  {:ok, binary()} | {:error, term()}
```

Start a workflow run against the Postgres journal.

# `start_synchronous`

```elixir
@spec start_synchronous(module(), term(), keyword()) ::
  {:ok, binary()} | {:error, term()}
```

Start a workflow run synchronously against the in-memory journal.

---

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