# `ExGram.Adapter.Test`
[🔗](https://github.com/rockneurotiko/ex_gram/blob/0.65.0/lib/ex_gram/adapter/test.ex#L1)

HTTP Adapter for testing with per-process isolation using NimbleOwnership.

Supports both private mode (per-process stubs for async tests) and global mode
(shared stubs for synchronous tests).

This module implements the low-level adapter. In tests you typically interact
with it through `ExGram.Test`, which provides a cleaner interface and handles
process isolation automatically via `start_bot/3`.

## Usage

    # In test_helper.exs or application supervision tree
    ExGram.Adapter.Test.start_link()

    # In your test module - use ExGram.Test for the full setup
    defmodule MyBotTest do
      use ExUnit.Case, async: true
      use ExGram.Test   # sets up verify_on_exit! and set_from_context automatically

      setup context do
        {bot_name, _} = ExGram.Test.start_bot(context, MyApp.Bot)
        {:ok, bot_name: bot_name}
      end

      test "my test", %{bot_name: bot_name} do
        ExGram.Test.expect(:send_message, fn body ->
          assert body[:text] == "value"
          {:ok, %{message_id: 1}}
        end)

        ExGram.Test.push_update(bot_name, update)

        # You can inspect calls after the fact
        calls = ExGram.Test.get_calls()
        # calls = [{:post, :send_message, %{chat_id: 123, ...}}]
      end
    end

You can learn more in the [testing guide](https://hexdocs.pm/ex_gram/testing.html)

## API Methods

All stub and expect functions accept action atoms (`:send_message`) that match the names of the
ExGram functions (`ExGram.get_me` -> `:get_me`).

# `allow`

Allow another process to use this process's stubs.

# `backdoor_error`

Backward-compatible wrapper. The name parameter is ignored - isolation is now per-process.

# `backdoor_request`

Backward-compatible wrapper. The name parameter is ignored - isolation is now per-process.

# `child_spec`

```elixir
@spec child_spec(Keyword.t()) :: Supervisor.child_spec()
```

Provide a child specification for supervising the test ownership server.

Parameters

  - opts: Keyword list of options forwarded to start_link/1.

The returned map is a child specification suitable for use in a supervision tree.

# `clean`

Backward-compatible wrapper. Cleans the current owner's state.

# `consume_expect_expectation`

# `expect`

Expect a catch-all response with a callback that receives action atom and body.
Consumed after the first call (n=1).

## Example

    expect(fn action, body ->
      assert action == :send_message
      {:ok, %ExGram.Model.Message{...}}
    end)

# `expect`

Expect a catch-all response with a callback that receives action atom and body.
Consumed after n calls.

## Example

    expect(2, fn action, body ->
      {:ok, %ExGram.Model.Message{...}}
    end)

# `expect`

Expect a response for a path or action atom. Consumed after n calls, then removed.
Expectations are checked before stubs.

The response can be:
- A static value (will be wrapped in `{:ok, value}` if not already a tuple)
- An arity-1 function that receives the request body

## Examples

    # Static response with atom, default n=1
    expect(:send_message, %ExGram.Model.Message{...})

    # Static response with count
    expect(:send_message, 2, %ExGram.Model.Message{...})

    # Dynamic response based on body
    expect(:send_message, fn body ->
      assert body["text"] =~ "Welcome"
      {:ok, %ExGram.Model.Message{...}}
    end)

    # Dynamic response with count
    expect(:send_message, 2, fn body ->
      {:ok, %ExGram.Model.Message{...}}
    end)

# `get_calls`

Get all calls recorded for the current owner.

# `get_calls`

Backward-compatible wrapper. The name parameter is ignored.

# `set_from_context`

```elixir
@spec set_from_context(term()) :: :ok
```

Chooses the ExGram.Test mode based on context.

When `async: true` is used, `set_private/1` is called,
otherwise `set_global/1` is used.

## Examples

    setup {ExGram.Test, :set_from_context}

# `set_global`

Switch to global mode (one owner serves all callers).

## Examples

    setup {ExGram.Test, :set_global}

# `set_private`

Switch to private mode (per-process isolation).

## Examples

    setup {ExGram.Test, :set_private}

# `start_link`

```elixir
@spec start_link(Keyword.t()) :: {:ok, pid()} | {:error, term()}
```

Starts the NimbleOwnership server used to track per-test ownership for ExGram.Adapter.Test.

Accepts the same options as NimbleOwnership.start_link/1. By default sets the `:name` option to the module's ownership server name so the server can be referenced globally; call this once (for example from test_helper.exs or your application supervision tree).

# `stub`

```elixir
@spec stub((atom(), any() -&gt; any())) :: :ok
```

Register a catch-all stub callback for the current owner to handle requests that have no path-specific stub.

The provided `callback` will be invoked with the action (an atom) and the request body when no action-specific stub or expectation matches; its return value is used as the response (for example `{:ok, value}` or `{:error, reason}`).

## Parameters

  - callback: a function of arity 2 receiving `(action :: atom(), body :: any())`.

## Example

    stub(fn action, body ->
      case action do
        :send_message -> {:ok, %ExGram.Model.Message{...}}
        :send_chat_action -> {:ok, true}
      end
    end)

# `stub`

Stub a response for a Telegram API path or action atom. Always returns this response.
Owned by the calling process.

The response can be:
- A static value (will be wrapped in `{:ok, value}` if not already a tuple)
- An arity-1 function that receives the request body
- An arity-2 function that receives path and body (use `stub/1` instead for catch-all)

## Examples

    # Static response with atom
    stub(:send_message, %ExGram.Model.Message{...})

    # Dynamic response based on body
    stub(:send_message, fn body ->
      assert body["text"] =~ "Hello"
      {:ok, %ExGram.Model.Message{...}}
    end)

# `stub_error`

Stub an error for a Telegram API path or action atom. Always returns this error.
Owned by the calling process.

# `verify!`

Verify all expectations were consumed.
Raises if any expectations remain.

# `verify_on_exit!`

Registers cleanup on test exit that verifies expectations were met.
Call this in your test's setup block via `setup {ExGram.Test, :verify_on_exit!}`.

---

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